devices.cpp revision 632e99a0d48823b6f73f89db105493bdd682e3b0
1/*
2 * Copyright (C) 2007-2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <dirent.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <fnmatch.h>
21#include <libgen.h>
22#include <stddef.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <sys/sendfile.h>
27#include <sys/socket.h>
28#include <sys/stat.h>
29#include <sys/time.h>
30#include <sys/types.h>
31#include <sys/un.h>
32#include <sys/wait.h>
33#include <unistd.h>
34
35#include <linux/netlink.h>
36
37#include <memory>
38
39#include <selinux/selinux.h>
40#include <selinux/label.h>
41#include <selinux/android.h>
42#include <selinux/avc.h>
43
44#include <private/android_filesystem_config.h>
45
46#include <android-base/file.h>
47#include <android-base/stringprintf.h>
48#include <android-base/unique_fd.h>
49#include <cutils/list.h>
50#include <cutils/uevent.h>
51
52#include "devices.h"
53#include "ueventd_parser.h"
54#include "util.h"
55#include "log.h"
56
57#define SYSFS_PREFIX    "/sys"
58static const char *firmware_dirs[] = { "/etc/firmware",
59                                       "/vendor/firmware",
60                                       "/firmware/image" };
61
62extern struct selabel_handle *sehandle;
63
64static int device_fd = -1;
65
66struct uevent {
67    const char *action;
68    const char *path;
69    const char *subsystem;
70    const char *firmware;
71    const char *partition_name;
72    const char *device_name;
73    int partition_num;
74    int major;
75    int minor;
76};
77
78struct perms_ {
79    char *name;
80    char *attr;
81    mode_t perm;
82    unsigned int uid;
83    unsigned int gid;
84    unsigned short prefix;
85    unsigned short wildcard;
86};
87
88struct perm_node {
89    struct perms_ dp;
90    struct listnode plist;
91};
92
93struct platform_node {
94    char *name;
95    char *path;
96    int path_len;
97    struct listnode list;
98};
99
100static list_declare(sys_perms);
101static list_declare(dev_perms);
102static list_declare(platform_names);
103
104int add_dev_perms(const char *name, const char *attr,
105                  mode_t perm, unsigned int uid, unsigned int gid,
106                  unsigned short prefix,
107                  unsigned short wildcard) {
108    struct perm_node *node = (perm_node*) calloc(1, sizeof(*node));
109    if (!node)
110        return -ENOMEM;
111
112    node->dp.name = strdup(name);
113    if (!node->dp.name)
114        return -ENOMEM;
115
116    if (attr) {
117        node->dp.attr = strdup(attr);
118        if (!node->dp.attr)
119            return -ENOMEM;
120    }
121
122    node->dp.perm = perm;
123    node->dp.uid = uid;
124    node->dp.gid = gid;
125    node->dp.prefix = prefix;
126    node->dp.wildcard = wildcard;
127
128    if (attr)
129        list_add_tail(&sys_perms, &node->plist);
130    else
131        list_add_tail(&dev_perms, &node->plist);
132
133    return 0;
134}
135
136static bool perm_path_matches(const char *path, struct perms_ *dp)
137{
138    if (dp->prefix) {
139        if (strncmp(path, dp->name, strlen(dp->name)) == 0)
140            return true;
141    } else if (dp->wildcard) {
142        if (fnmatch(dp->name, path, FNM_PATHNAME) == 0)
143            return true;
144    } else {
145        if (strcmp(path, dp->name) == 0)
146            return true;
147    }
148
149    return false;
150}
151
152static bool match_subsystem(perms_* dp, const char* pattern,
153                            const char* path, const char* subsystem) {
154    if (!pattern || !subsystem || strstr(dp->name, subsystem) == NULL) {
155        return false;
156    }
157
158    std::string subsys_path = android::base::StringPrintf(pattern, subsystem, basename(path));
159    return perm_path_matches(subsys_path.c_str(), dp);
160}
161
162static void fixup_sys_perms(const char* upath, const char* subsystem) {
163    // upaths omit the "/sys" that paths in this list
164    // contain, so we prepend it...
165    std::string path = std::string(SYSFS_PREFIX) + upath;
166
167    listnode* node;
168    list_for_each(node, &sys_perms) {
169        perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
170        if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem)) {
171            ; // matched
172        } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(), subsystem)) {
173            ; // matched
174        } else if (!perm_path_matches(path.c_str(), dp)) {
175            continue;
176        }
177
178        std::string attr_file = path + "/" + dp->attr;
179        LOG(INFO) << "fixup " << attr_file
180                  << " " << dp->uid << " " << dp->gid << " " << std::oct << dp->perm;
181        chown(attr_file.c_str(), dp->uid, dp->gid);
182        chmod(attr_file.c_str(), dp->perm);
183    }
184
185    if (access(path.c_str(), F_OK) == 0) {
186        LOG(VERBOSE) << "restorecon_recursive: " << path;
187        restorecon_recursive(path.c_str());
188    }
189}
190
191static mode_t get_device_perm(const char *path, const char **links,
192                unsigned *uid, unsigned *gid)
193{
194    struct listnode *node;
195    struct perm_node *perm_node;
196    struct perms_ *dp;
197
198    /* search the perms list in reverse so that ueventd.$hardware can
199     * override ueventd.rc
200     */
201    list_for_each_reverse(node, &dev_perms) {
202        bool match = false;
203
204        perm_node = node_to_item(node, struct perm_node, plist);
205        dp = &perm_node->dp;
206
207        if (perm_path_matches(path, dp)) {
208            match = true;
209        } else {
210            if (links) {
211                int i;
212                for (i = 0; links[i]; i++) {
213                    if (perm_path_matches(links[i], dp)) {
214                        match = true;
215                        break;
216                    }
217                }
218            }
219        }
220
221        if (match) {
222            *uid = dp->uid;
223            *gid = dp->gid;
224            return dp->perm;
225        }
226    }
227    /* Default if nothing found. */
228    *uid = 0;
229    *gid = 0;
230    return 0600;
231}
232
233static void make_device(const char *path,
234                        const char */*upath*/,
235                        int block, int major, int minor,
236                        const char **links)
237{
238    unsigned uid;
239    unsigned gid;
240    mode_t mode;
241    dev_t dev;
242    char *secontext = NULL;
243
244    mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
245
246    if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
247        PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
248        return;
249    }
250    setfscreatecon(secontext);
251
252    dev = makedev(major, minor);
253    /* Temporarily change egid to avoid race condition setting the gid of the
254     * device node. Unforunately changing the euid would prevent creation of
255     * some device nodes, so the uid has to be set with chown() and is still
256     * racy. Fixing the gid race at least fixed the issue with system_server
257     * opening dynamic input devices under the AID_INPUT gid. */
258    setegid(gid);
259    /* If the node already exists update its SELinux label to handle cases when
260     * it was created with the wrong context during coldboot procedure. */
261    if (mknod(path, mode, dev) && (errno == EEXIST)) {
262
263        char* fcon = nullptr;
264        int rc = lgetfilecon(path, &fcon);
265        if (rc < 0) {
266            PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
267            goto out;
268        }
269
270        bool different = strcmp(fcon, secontext) != 0;
271        freecon(fcon);
272
273        if (different && lsetfilecon(path, secontext)) {
274            PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
275        }
276    }
277
278out:
279    chown(path, uid, -1);
280    setegid(AID_ROOT);
281
282    freecon(secontext);
283    setfscreatecon(NULL);
284}
285
286static void add_platform_device(const char *path)
287{
288    int path_len = strlen(path);
289    struct platform_node *bus;
290    const char *name = path;
291
292    if (!strncmp(path, "/devices/", 9)) {
293        name += 9;
294        if (!strncmp(name, "platform/", 9))
295            name += 9;
296    }
297
298    LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
299
300    bus = (platform_node*) calloc(1, sizeof(struct platform_node));
301    bus->path = strdup(path);
302    bus->path_len = path_len;
303    bus->name = bus->path + (name - path);
304    list_add_tail(&platform_names, &bus->list);
305}
306
307/*
308 * given a path that may start with a platform device, find the length of the
309 * platform device prefix.  If it doesn't start with a platform device, return
310 * 0.
311 */
312static struct platform_node *find_platform_device(const char *path)
313{
314    int path_len = strlen(path);
315    struct listnode *node;
316    struct platform_node *bus;
317
318    list_for_each_reverse(node, &platform_names) {
319        bus = node_to_item(node, struct platform_node, list);
320        if ((bus->path_len < path_len) &&
321                (path[bus->path_len] == '/') &&
322                !strncmp(path, bus->path, bus->path_len))
323            return bus;
324    }
325
326    return NULL;
327}
328
329static void remove_platform_device(const char *path)
330{
331    struct listnode *node;
332    struct platform_node *bus;
333
334    list_for_each_reverse(node, &platform_names) {
335        bus = node_to_item(node, struct platform_node, list);
336        if (!strcmp(path, bus->path)) {
337            LOG(INFO) << "removing platform device " << bus->name;
338            free(bus->path);
339            list_remove(node);
340            free(bus);
341            return;
342        }
343    }
344}
345
346/* Given a path that may start with a PCI device, populate the supplied buffer
347 * with the PCI domain/bus number and the peripheral ID and return 0.
348 * If it doesn't start with a PCI device, or there is some error, return -1 */
349static int find_pci_device_prefix(const char *path, char *buf, ssize_t buf_sz)
350{
351    const char *start, *end;
352
353    if (strncmp(path, "/devices/pci", 12))
354        return -1;
355
356    /* Beginning of the prefix is the initial "pci" after "/devices/" */
357    start = path + 9;
358
359    /* End of the prefix is two path '/' later, capturing the domain/bus number
360     * and the peripheral ID. Example: pci0000:00/0000:00:1f.2 */
361    end = strchr(start, '/');
362    if (!end)
363        return -1;
364    end = strchr(end + 1, '/');
365    if (!end)
366        return -1;
367
368    /* Make sure we have enough room for the string plus null terminator */
369    if (end - start + 1 > buf_sz)
370        return -1;
371
372    strncpy(buf, start, end - start);
373    buf[end - start] = '\0';
374    return 0;
375}
376
377static void parse_event(const char *msg, struct uevent *uevent)
378{
379    uevent->action = "";
380    uevent->path = "";
381    uevent->subsystem = "";
382    uevent->firmware = "";
383    uevent->major = -1;
384    uevent->minor = -1;
385    uevent->partition_name = NULL;
386    uevent->partition_num = -1;
387    uevent->device_name = NULL;
388
389        /* currently ignoring SEQNUM */
390    while(*msg) {
391        if(!strncmp(msg, "ACTION=", 7)) {
392            msg += 7;
393            uevent->action = msg;
394        } else if(!strncmp(msg, "DEVPATH=", 8)) {
395            msg += 8;
396            uevent->path = msg;
397        } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
398            msg += 10;
399            uevent->subsystem = msg;
400        } else if(!strncmp(msg, "FIRMWARE=", 9)) {
401            msg += 9;
402            uevent->firmware = msg;
403        } else if(!strncmp(msg, "MAJOR=", 6)) {
404            msg += 6;
405            uevent->major = atoi(msg);
406        } else if(!strncmp(msg, "MINOR=", 6)) {
407            msg += 6;
408            uevent->minor = atoi(msg);
409        } else if(!strncmp(msg, "PARTN=", 6)) {
410            msg += 6;
411            uevent->partition_num = atoi(msg);
412        } else if(!strncmp(msg, "PARTNAME=", 9)) {
413            msg += 9;
414            uevent->partition_name = msg;
415        } else if(!strncmp(msg, "DEVNAME=", 8)) {
416            msg += 8;
417            uevent->device_name = msg;
418        }
419
420        /* advance to after the next \0 */
421        while(*msg++)
422            ;
423    }
424
425    if (LOG_UEVENTS) {
426        LOG(INFO) << android::base::StringPrintf("event { '%s', '%s', '%s', '%s', %d, %d }",
427                                                 uevent->action, uevent->path, uevent->subsystem,
428                                                 uevent->firmware, uevent->major, uevent->minor);
429    }
430}
431
432static char **get_character_device_symlinks(struct uevent *uevent)
433{
434    const char *parent;
435    const char *slash;
436    char **links;
437    int link_num = 0;
438    int width;
439    struct platform_node *pdev;
440
441    pdev = find_platform_device(uevent->path);
442    if (!pdev)
443        return NULL;
444
445    links = (char**) malloc(sizeof(char *) * 2);
446    if (!links)
447        return NULL;
448    memset(links, 0, sizeof(char *) * 2);
449
450    /* skip "/devices/platform/<driver>" */
451    parent = strchr(uevent->path + pdev->path_len, '/');
452    if (!parent)
453        goto err;
454
455    if (!strncmp(parent, "/usb", 4)) {
456        /* skip root hub name and device. use device interface */
457        while (*++parent && *parent != '/');
458        if (*parent)
459            while (*++parent && *parent != '/');
460        if (!*parent)
461            goto err;
462        slash = strchr(++parent, '/');
463        if (!slash)
464            goto err;
465        width = slash - parent;
466        if (width <= 0)
467            goto err;
468
469        if (asprintf(&links[link_num], "/dev/usb/%s%.*s", uevent->subsystem, width, parent) > 0)
470            link_num++;
471        else
472            links[link_num] = NULL;
473        mkdir("/dev/usb", 0755);
474    }
475    else {
476        goto err;
477    }
478
479    return links;
480err:
481    free(links);
482    return NULL;
483}
484
485static char **get_block_device_symlinks(struct uevent *uevent)
486{
487    const char *device;
488    struct platform_node *pdev;
489    const char *slash;
490    const char *type;
491    char buf[256];
492    char link_path[256];
493    int link_num = 0;
494    char *p;
495
496    pdev = find_platform_device(uevent->path);
497    if (pdev) {
498        device = pdev->name;
499        type = "platform";
500    } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
501        device = buf;
502        type = "pci";
503    } else {
504        return NULL;
505    }
506
507    char **links = (char**) malloc(sizeof(char *) * 4);
508    if (!links)
509        return NULL;
510    memset(links, 0, sizeof(char *) * 4);
511
512    LOG(INFO) << "found " << type << " device " << device;
513
514    snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
515
516    if (uevent->partition_name) {
517        p = strdup(uevent->partition_name);
518        sanitize(p);
519        if (strcmp(uevent->partition_name, p)) {
520            LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '" << p << "'";
521        }
522        if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
523            link_num++;
524        else
525            links[link_num] = NULL;
526        free(p);
527    }
528
529    if (uevent->partition_num >= 0) {
530        if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0)
531            link_num++;
532        else
533            links[link_num] = NULL;
534    }
535
536    slash = strrchr(uevent->path, '/');
537    if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
538        link_num++;
539    else
540        links[link_num] = NULL;
541
542    return links;
543}
544
545static void make_link_init(const char* oldpath, const char* newpath) {
546  const char* slash = strrchr(newpath, '/');
547  if (!slash) return;
548
549  if (mkdir_recursive(dirname(newpath), 0755)) {
550    PLOG(ERROR) << "Failed to create directory " << dirname(newpath);
551  }
552
553  if (symlink(oldpath, newpath) && errno != EEXIST) {
554    PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
555  }
556}
557
558static void remove_link(const char* oldpath, const char* newpath) {
559  std::string path;
560  if (android::base::Readlink(newpath, &path) && path == oldpath) unlink(newpath);
561}
562
563static void handle_device(const char *action, const char *devpath,
564        const char *path, int block, int major, int minor, char **links)
565{
566    if(!strcmp(action, "add")) {
567        make_device(devpath, path, block, major, minor, (const char **)links);
568        if (links) {
569            for (int i = 0; links[i]; i++) {
570                make_link_init(devpath, links[i]);
571            }
572        }
573    }
574
575    if(!strcmp(action, "remove")) {
576        if (links) {
577            for (int i = 0; links[i]; i++) {
578                remove_link(devpath, links[i]);
579            }
580        }
581        unlink(devpath);
582    }
583
584    if (links) {
585        for (int i = 0; links[i]; i++) {
586            free(links[i]);
587        }
588        free(links);
589    }
590}
591
592static void handle_platform_device_event(struct uevent *uevent)
593{
594    const char *path = uevent->path;
595
596    if (!strcmp(uevent->action, "add"))
597        add_platform_device(path);
598    else if (!strcmp(uevent->action, "remove"))
599        remove_platform_device(path);
600}
601
602static const char *parse_device_name(struct uevent *uevent, unsigned int len)
603{
604    const char *name;
605
606    /* if it's not a /dev device, nothing else to do */
607    if((uevent->major < 0) || (uevent->minor < 0))
608        return NULL;
609
610    /* do we have a name? */
611    name = strrchr(uevent->path, '/');
612    if(!name)
613        return NULL;
614    name++;
615
616    /* too-long names would overrun our buffer */
617    if(strlen(name) > len) {
618        LOG(ERROR) << "DEVPATH=" << name << " exceeds " << len << "-character limit on filename; ignoring event";
619        return NULL;
620    }
621
622    return name;
623}
624
625#define DEVPATH_LEN 96
626#define MAX_DEV_NAME 64
627
628static void handle_block_device_event(struct uevent *uevent)
629{
630    const char *base = "/dev/block/";
631    const char *name;
632    char devpath[DEVPATH_LEN];
633    char **links = NULL;
634
635    name = parse_device_name(uevent, MAX_DEV_NAME);
636    if (!name)
637        return;
638
639    snprintf(devpath, sizeof(devpath), "%s%s", base, name);
640    make_dir(base, 0755);
641
642    if (!strncmp(uevent->path, "/devices/", 9))
643        links = get_block_device_symlinks(uevent);
644
645    handle_device(uevent->action, devpath, uevent->path, 1,
646            uevent->major, uevent->minor, links);
647}
648
649static bool assemble_devpath(char *devpath, const char *dirname,
650        const char *devname)
651{
652    int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
653    if (s < 0) {
654        PLOG(ERROR) << "failed to assemble device path; ignoring event";
655        return false;
656    } else if (s >= DEVPATH_LEN) {
657        LOG(ERROR) << dirname << "/" << devname
658                   << " exceeds " << DEVPATH_LEN << "-character limit on path; ignoring event";
659        return false;
660    }
661    return true;
662}
663
664static void mkdir_recursive_for_devpath(const char *devpath)
665{
666    char dir[DEVPATH_LEN];
667    char *slash;
668
669    strcpy(dir, devpath);
670    slash = strrchr(dir, '/');
671    *slash = '\0';
672    mkdir_recursive(dir, 0755);
673}
674
675static void handle_generic_device_event(struct uevent *uevent)
676{
677    const char *base;
678    const char *name;
679    char devpath[DEVPATH_LEN] = {0};
680    char **links = NULL;
681
682    name = parse_device_name(uevent, MAX_DEV_NAME);
683    if (!name)
684        return;
685
686    struct ueventd_subsystem *subsystem =
687            ueventd_subsystem_find_by_name(uevent->subsystem);
688
689    if (subsystem) {
690        const char *devname;
691
692        switch (subsystem->devname_src) {
693        case DEVNAME_UEVENT_DEVNAME:
694            devname = uevent->device_name;
695            break;
696
697        case DEVNAME_UEVENT_DEVPATH:
698            devname = name;
699            break;
700
701        default:
702            LOG(ERROR) << uevent->subsystem << " subsystem's devpath option is not set; ignoring event";
703            return;
704        }
705
706        if (!assemble_devpath(devpath, subsystem->dirname, devname))
707            return;
708        mkdir_recursive_for_devpath(devpath);
709    } else if (!strncmp(uevent->subsystem, "usb", 3)) {
710         if (!strcmp(uevent->subsystem, "usb")) {
711            if (uevent->device_name) {
712                if (!assemble_devpath(devpath, "/dev", uevent->device_name))
713                    return;
714                mkdir_recursive_for_devpath(devpath);
715             }
716             else {
717                 /* This imitates the file system that would be created
718                  * if we were using devfs instead.
719                  * Minors are broken up into groups of 128, starting at "001"
720                  */
721                 int bus_id = uevent->minor / 128 + 1;
722                 int device_id = uevent->minor % 128 + 1;
723                 /* build directories */
724                 make_dir("/dev/bus", 0755);
725                 make_dir("/dev/bus/usb", 0755);
726                 snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
727                 make_dir(devpath, 0755);
728                 snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
729             }
730         } else {
731             /* ignore other USB events */
732             return;
733         }
734     } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
735         base = "/dev/graphics/";
736         make_dir(base, 0755);
737     } else if (!strncmp(uevent->subsystem, "drm", 3)) {
738         base = "/dev/dri/";
739         make_dir(base, 0755);
740     } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
741         base = "/dev/oncrpc/";
742         make_dir(base, 0755);
743     } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
744         base = "/dev/adsp/";
745         make_dir(base, 0755);
746     } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
747         base = "/dev/msm_camera/";
748         make_dir(base, 0755);
749     } else if(!strncmp(uevent->subsystem, "input", 5)) {
750         base = "/dev/input/";
751         make_dir(base, 0755);
752     } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
753         base = "/dev/mtd/";
754         make_dir(base, 0755);
755     } else if(!strncmp(uevent->subsystem, "sound", 5)) {
756         base = "/dev/snd/";
757         make_dir(base, 0755);
758     } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) {
759         LOG(INFO) << "kernel logger is deprecated";
760         base = "/dev/log/";
761         make_dir(base, 0755);
762         name += 4;
763     } else
764         base = "/dev/";
765     links = get_character_device_symlinks(uevent);
766
767     if (!devpath[0])
768         snprintf(devpath, sizeof(devpath), "%s%s", base, name);
769
770     handle_device(uevent->action, devpath, uevent->path, 0,
771             uevent->major, uevent->minor, links);
772}
773
774static void handle_device_event(struct uevent *uevent)
775{
776    if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
777        fixup_sys_perms(uevent->path, uevent->subsystem);
778
779    if (!strncmp(uevent->subsystem, "block", 5)) {
780        handle_block_device_event(uevent);
781    } else if (!strncmp(uevent->subsystem, "platform", 8)) {
782        handle_platform_device_event(uevent);
783    } else {
784        handle_generic_device_event(uevent);
785    }
786}
787
788static void load_firmware(uevent* uevent, const std::string& root,
789                          int fw_fd, size_t fw_size,
790                          int loading_fd, int data_fd) {
791    // Start transfer.
792    android::base::WriteFully(loading_fd, "1", 1);
793
794    // Copy the firmware.
795    int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
796    if (rc == -1) {
797        PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
798    }
799
800    // Tell the firmware whether to abort or commit.
801    const char* response = (rc != -1) ? "0" : "-1";
802    android::base::WriteFully(loading_fd, response, strlen(response));
803}
804
805static int is_booting() {
806    return access("/dev/.booting", F_OK) == 0;
807}
808
809static void process_firmware_event(uevent* uevent) {
810    int booting = is_booting();
811
812    LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
813
814    std::string root = android::base::StringPrintf("/sys%s", uevent->path);
815    std::string loading = root + "/loading";
816    std::string data = root + "/data";
817
818    android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
819    if (loading_fd == -1) {
820        PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
821        return;
822    }
823
824    android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
825    if (data_fd == -1) {
826        PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
827        return;
828    }
829
830try_loading_again:
831    for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
832        std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
833        android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
834        struct stat sb;
835        if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
836            load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
837            return;
838        }
839    }
840
841    if (booting) {
842        // If we're not fully booted, we may be missing
843        // filesystems needed for firmware, wait and retry.
844        usleep(100000);
845        booting = is_booting();
846        goto try_loading_again;
847    }
848
849    LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;
850
851    // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
852    write(loading_fd, "-1", 2);
853}
854
855static void handle_firmware_event(uevent* uevent) {
856    if (strcmp(uevent->subsystem, "firmware")) return;
857    if (strcmp(uevent->action, "add")) return;
858
859    // Loading the firmware in a child means we can do that in parallel...
860    // (We ignore SIGCHLD rather than wait for our children.)
861    pid_t pid = fork();
862    if (pid == 0) {
863        Timer t;
864        process_firmware_event(uevent);
865        LOG(INFO) << "loading " << uevent->path << " took " << t.duration() << "s";
866        _exit(EXIT_SUCCESS);
867    } else if (pid == -1) {
868        PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
869    }
870}
871
872#define UEVENT_MSG_LEN  2048
873
874static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
875{
876    char msg[UEVENT_MSG_LEN+2];
877    int n;
878    while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
879        if(n >= UEVENT_MSG_LEN)   /* overflow -- discard */
880            continue;
881
882        msg[n] = '\0';
883        msg[n+1] = '\0';
884
885        struct uevent uevent;
886        parse_event(msg, &uevent);
887        handle_uevent(&uevent);
888    }
889}
890
891void handle_device_fd()
892{
893    handle_device_fd_with(
894        [](struct uevent *uevent) {
895            if (selinux_status_updated() > 0) {
896                struct selabel_handle *sehandle2;
897                sehandle2 = selinux_android_file_context_handle();
898                if (sehandle2) {
899                    selabel_close(sehandle);
900                    sehandle = sehandle2;
901                }
902            }
903
904            handle_device_event(uevent);
905            handle_firmware_event(uevent);
906        });
907}
908
909/* Coldboot walks parts of the /sys tree and pokes the uevent files
910** to cause the kernel to regenerate device add events that happened
911** before init's device manager was started
912**
913** We drain any pending events from the netlink socket every time
914** we poke another uevent file to make sure we don't overrun the
915** socket's buffer.
916*/
917
918static void do_coldboot(DIR *d)
919{
920    struct dirent *de;
921    int dfd, fd;
922
923    dfd = dirfd(d);
924
925    fd = openat(dfd, "uevent", O_WRONLY);
926    if(fd >= 0) {
927        write(fd, "add\n", 4);
928        close(fd);
929        handle_device_fd();
930    }
931
932    while((de = readdir(d))) {
933        DIR *d2;
934
935        if(de->d_type != DT_DIR || de->d_name[0] == '.')
936            continue;
937
938        fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
939        if(fd < 0)
940            continue;
941
942        d2 = fdopendir(fd);
943        if(d2 == 0)
944            close(fd);
945        else {
946            do_coldboot(d2);
947            closedir(d2);
948        }
949    }
950}
951
952static void coldboot(const char *path)
953{
954    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
955    if(d) {
956        do_coldboot(d.get());
957    }
958}
959
960static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
961{
962    const char *name;
963    char devpath[DEVPATH_LEN];
964
965    if (is_block && strncmp(uevent->subsystem, "block", 5))
966        return;
967
968    name = parse_device_name(uevent, MAX_DEV_NAME);
969    if (!name) {
970        LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
971                   << " " << uevent->partition_name << " " << uevent->partition_num
972                   << " " << uevent->major << ":" << uevent->minor;
973        return;
974    }
975
976    snprintf(devpath, sizeof(devpath), "%s%s", base, name);
977    make_dir(base, 0755);
978
979    dev_t dev = makedev(uevent->major, uevent->minor);
980    mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
981    mknod(devpath, mode, dev);
982}
983
984void early_create_dev(const std::string& syspath, early_device_type dev_type)
985{
986    android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
987    if (dfd < 0) {
988        LOG(ERROR) << "Failed to open " << syspath;
989        return;
990    }
991
992    android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
993    if (fd < 0) {
994        LOG(ERROR) << "Failed to open " << syspath << "/uevent";
995        return;
996    }
997
998    fcntl(device_fd, F_SETFL, O_NONBLOCK);
999
1000    write(fd, "add\n", 4);
1001    handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
1002        [](struct uevent *uevent) {
1003            early_uevent_handler(uevent, "/dev/block/", true);
1004        } :
1005        [](struct uevent *uevent) {
1006            early_uevent_handler(uevent, "/dev/", false);
1007        });
1008}
1009
1010int early_device_socket_open() {
1011    device_fd = uevent_open_socket(256*1024, true);
1012    return device_fd < 0;
1013}
1014
1015void early_device_socket_close() {
1016    close(device_fd);
1017}
1018
1019void device_init() {
1020    sehandle = selinux_android_file_context_handle();
1021    selinux_status_open(true);
1022
1023    /* is 256K enough? udev uses 16MB! */
1024    device_fd = uevent_open_socket(256*1024, true);
1025    if (device_fd == -1) {
1026        return;
1027    }
1028    fcntl(device_fd, F_SETFL, O_NONBLOCK);
1029
1030    if (access(COLDBOOT_DONE, F_OK) == 0) {
1031        LOG(VERBOSE) << "Skipping coldboot, already done!";
1032        return;
1033    }
1034
1035    Timer t;
1036    coldboot("/sys/class");
1037    coldboot("/sys/block");
1038    coldboot("/sys/devices");
1039    close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
1040    LOG(INFO) << "Coldboot took " << t.duration() << "s.";
1041}
1042
1043int get_device_fd() {
1044    return device_fd;
1045}
1046