Home | History | Annotate | Download | only in init
      1 /*
      2  * Copyright (C) 2007 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 <errno.h>
     18 #include <stddef.h>
     19 #include <stdio.h>
     20 #include <stdlib.h>
     21 #include <sys/stat.h>
     22 #include <sys/types.h>
     23 
     24 #include <fcntl.h>
     25 #include <dirent.h>
     26 #include <unistd.h>
     27 #include <string.h>
     28 
     29 #include <sys/socket.h>
     30 #include <sys/un.h>
     31 #include <linux/netlink.h>
     32 
     33 #ifdef HAVE_SELINUX
     34 #include <selinux/selinux.h>
     35 #include <selinux/label.h>
     36 #endif
     37 
     38 #include <private/android_filesystem_config.h>
     39 #include <sys/time.h>
     40 #include <asm/page.h>
     41 #include <sys/wait.h>
     42 
     43 #include <cutils/list.h>
     44 #include <cutils/uevent.h>
     45 
     46 #include "devices.h"
     47 #include "util.h"
     48 #include "log.h"
     49 
     50 #define SYSFS_PREFIX    "/sys"
     51 #define FIRMWARE_DIR1   "/etc/firmware"
     52 #define FIRMWARE_DIR2   "/vendor/firmware"
     53 
     54 #ifdef HAVE_SELINUX
     55 static struct selabel_handle *sehandle;
     56 #endif
     57 
     58 static int device_fd = -1;
     59 
     60 struct uevent {
     61     const char *action;
     62     const char *path;
     63     const char *subsystem;
     64     const char *firmware;
     65     const char *partition_name;
     66     const char *device_name;
     67     int partition_num;
     68     int major;
     69     int minor;
     70 };
     71 
     72 struct perms_ {
     73     char *name;
     74     char *attr;
     75     mode_t perm;
     76     unsigned int uid;
     77     unsigned int gid;
     78     unsigned short prefix;
     79 };
     80 
     81 struct perm_node {
     82     struct perms_ dp;
     83     struct listnode plist;
     84 };
     85 
     86 struct platform_node {
     87     char *name;
     88     int name_len;
     89     struct listnode list;
     90 };
     91 
     92 static list_declare(sys_perms);
     93 static list_declare(dev_perms);
     94 static list_declare(platform_names);
     95 
     96 int add_dev_perms(const char *name, const char *attr,
     97                   mode_t perm, unsigned int uid, unsigned int gid,
     98                   unsigned short prefix) {
     99     struct perm_node *node = calloc(1, sizeof(*node));
    100     if (!node)
    101         return -ENOMEM;
    102 
    103     node->dp.name = strdup(name);
    104     if (!node->dp.name)
    105         return -ENOMEM;
    106 
    107     if (attr) {
    108         node->dp.attr = strdup(attr);
    109         if (!node->dp.attr)
    110             return -ENOMEM;
    111     }
    112 
    113     node->dp.perm = perm;
    114     node->dp.uid = uid;
    115     node->dp.gid = gid;
    116     node->dp.prefix = prefix;
    117 
    118     if (attr)
    119         list_add_tail(&sys_perms, &node->plist);
    120     else
    121         list_add_tail(&dev_perms, &node->plist);
    122 
    123     return 0;
    124 }
    125 
    126 void fixup_sys_perms(const char *upath)
    127 {
    128     char buf[512];
    129     struct listnode *node;
    130     struct perms_ *dp;
    131 
    132         /* upaths omit the "/sys" that paths in this list
    133          * contain, so we add 4 when comparing...
    134          */
    135     list_for_each(node, &sys_perms) {
    136         dp = &(node_to_item(node, struct perm_node, plist))->dp;
    137         if (dp->prefix) {
    138             if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
    139                 continue;
    140         } else {
    141             if (strcmp(upath, dp->name + 4))
    142                 continue;
    143         }
    144 
    145         if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
    146             return;
    147 
    148         sprintf(buf,"/sys%s/%s", upath, dp->attr);
    149         INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
    150         chown(buf, dp->uid, dp->gid);
    151         chmod(buf, dp->perm);
    152     }
    153 }
    154 
    155 static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid)
    156 {
    157     mode_t perm;
    158     struct listnode *node;
    159     struct perm_node *perm_node;
    160     struct perms_ *dp;
    161 
    162     /* search the perms list in reverse so that ueventd.$hardware can
    163      * override ueventd.rc
    164      */
    165     list_for_each_reverse(node, &dev_perms) {
    166         perm_node = node_to_item(node, struct perm_node, plist);
    167         dp = &perm_node->dp;
    168 
    169         if (dp->prefix) {
    170             if (strncmp(path, dp->name, strlen(dp->name)))
    171                 continue;
    172         } else {
    173             if (strcmp(path, dp->name))
    174                 continue;
    175         }
    176         *uid = dp->uid;
    177         *gid = dp->gid;
    178         return dp->perm;
    179     }
    180     /* Default if nothing found. */
    181     *uid = 0;
    182     *gid = 0;
    183     return 0600;
    184 }
    185 
    186 static void make_device(const char *path,
    187                         const char *upath,
    188                         int block, int major, int minor)
    189 {
    190     unsigned uid;
    191     unsigned gid;
    192     mode_t mode;
    193     dev_t dev;
    194 #ifdef HAVE_SELINUX
    195     char *secontext = NULL;
    196 #endif
    197 
    198     mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
    199 #ifdef HAVE_SELINUX
    200     if (sehandle) {
    201         selabel_lookup(sehandle, &secontext, path, mode);
    202         setfscreatecon(secontext);
    203     }
    204 #endif
    205     dev = makedev(major, minor);
    206     /* Temporarily change egid to avoid race condition setting the gid of the
    207      * device node. Unforunately changing the euid would prevent creation of
    208      * some device nodes, so the uid has to be set with chown() and is still
    209      * racy. Fixing the gid race at least fixed the issue with system_server
    210      * opening dynamic input devices under the AID_INPUT gid. */
    211     setegid(gid);
    212     mknod(path, mode, dev);
    213     chown(path, uid, -1);
    214     setegid(AID_ROOT);
    215 #ifdef HAVE_SELINUX
    216     if (secontext) {
    217         freecon(secontext);
    218         setfscreatecon(NULL);
    219     }
    220 #endif
    221 }
    222 
    223 
    224 static int make_dir(const char *path, mode_t mode)
    225 {
    226     int rc;
    227 
    228 #ifdef HAVE_SELINUX
    229     char *secontext = NULL;
    230 
    231     if (sehandle) {
    232         selabel_lookup(sehandle, &secontext, path, mode);
    233         setfscreatecon(secontext);
    234     }
    235 #endif
    236 
    237     rc = mkdir(path, mode);
    238 
    239 #ifdef HAVE_SELINUX
    240     if (secontext) {
    241         freecon(secontext);
    242         setfscreatecon(NULL);
    243     }
    244 #endif
    245     return rc;
    246 }
    247 
    248 
    249 static void add_platform_device(const char *name)
    250 {
    251     int name_len = strlen(name);
    252     struct listnode *node;
    253     struct platform_node *bus;
    254 
    255     list_for_each_reverse(node, &platform_names) {
    256         bus = node_to_item(node, struct platform_node, list);
    257         if ((bus->name_len < name_len) &&
    258                 (name[bus->name_len] == '/') &&
    259                 !strncmp(name, bus->name, bus->name_len))
    260             /* subdevice of an existing platform, ignore it */
    261             return;
    262     }
    263 
    264     INFO("adding platform device %s\n", name);
    265 
    266     bus = calloc(1, sizeof(struct platform_node));
    267     bus->name = strdup(name);
    268     bus->name_len = name_len;
    269     list_add_tail(&platform_names, &bus->list);
    270 }
    271 
    272 /*
    273  * given a name that may start with a platform device, find the length of the
    274  * platform device prefix.  If it doesn't start with a platform device, return
    275  * 0.
    276  */
    277 static const char *find_platform_device(const char *name)
    278 {
    279     int name_len = strlen(name);
    280     struct listnode *node;
    281     struct platform_node *bus;
    282 
    283     list_for_each_reverse(node, &platform_names) {
    284         bus = node_to_item(node, struct platform_node, list);
    285         if ((bus->name_len < name_len) &&
    286                 (name[bus->name_len] == '/') &&
    287                 !strncmp(name, bus->name, bus->name_len))
    288             return bus->name;
    289     }
    290 
    291     return NULL;
    292 }
    293 
    294 static void remove_platform_device(const char *name)
    295 {
    296     struct listnode *node;
    297     struct platform_node *bus;
    298 
    299     list_for_each_reverse(node, &platform_names) {
    300         bus = node_to_item(node, struct platform_node, list);
    301         if (!strcmp(name, bus->name)) {
    302             INFO("removing platform device %s\n", name);
    303             free(bus->name);
    304             list_remove(node);
    305             free(bus);
    306             return;
    307         }
    308     }
    309 }
    310 
    311 #if LOG_UEVENTS
    312 
    313 static inline suseconds_t get_usecs(void)
    314 {
    315     struct timeval tv;
    316     gettimeofday(&tv, 0);
    317     return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec;
    318 }
    319 
    320 #define log_event_print(x...) INFO(x)
    321 
    322 #else
    323 
    324 #define log_event_print(fmt, args...)   do { } while (0)
    325 #define get_usecs()                     0
    326 
    327 #endif
    328 
    329 static void parse_event(const char *msg, struct uevent *uevent)
    330 {
    331     uevent->action = "";
    332     uevent->path = "";
    333     uevent->subsystem = "";
    334     uevent->firmware = "";
    335     uevent->major = -1;
    336     uevent->minor = -1;
    337     uevent->partition_name = NULL;
    338     uevent->partition_num = -1;
    339     uevent->device_name = NULL;
    340 
    341         /* currently ignoring SEQNUM */
    342     while(*msg) {
    343         if(!strncmp(msg, "ACTION=", 7)) {
    344             msg += 7;
    345             uevent->action = msg;
    346         } else if(!strncmp(msg, "DEVPATH=", 8)) {
    347             msg += 8;
    348             uevent->path = msg;
    349         } else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
    350             msg += 10;
    351             uevent->subsystem = msg;
    352         } else if(!strncmp(msg, "FIRMWARE=", 9)) {
    353             msg += 9;
    354             uevent->firmware = msg;
    355         } else if(!strncmp(msg, "MAJOR=", 6)) {
    356             msg += 6;
    357             uevent->major = atoi(msg);
    358         } else if(!strncmp(msg, "MINOR=", 6)) {
    359             msg += 6;
    360             uevent->minor = atoi(msg);
    361         } else if(!strncmp(msg, "PARTN=", 6)) {
    362             msg += 6;
    363             uevent->partition_num = atoi(msg);
    364         } else if(!strncmp(msg, "PARTNAME=", 9)) {
    365             msg += 9;
    366             uevent->partition_name = msg;
    367         } else if(!strncmp(msg, "DEVNAME=", 8)) {
    368             msg += 8;
    369             uevent->device_name = msg;
    370         }
    371 
    372         /* advance to after the next \0 */
    373         while(*msg++)
    374             ;
    375     }
    376 
    377     log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n",
    378                     uevent->action, uevent->path, uevent->subsystem,
    379                     uevent->firmware, uevent->major, uevent->minor);
    380 }
    381 
    382 static char **get_character_device_symlinks(struct uevent *uevent)
    383 {
    384     const char *parent;
    385     char *slash;
    386     char **links;
    387     int link_num = 0;
    388     int width;
    389 
    390     if (strncmp(uevent->path, "/devices/platform/", 18))
    391         return NULL;
    392 
    393     links = malloc(sizeof(char *) * 2);
    394     if (!links)
    395         return NULL;
    396     memset(links, 0, sizeof(char *) * 2);
    397 
    398     /* skip "/devices/platform/<driver>" */
    399     parent = strchr(uevent->path + 18, '/');
    400     if (!*parent)
    401         goto err;
    402 
    403     if (!strncmp(parent, "/usb", 4)) {
    404         /* skip root hub name and device. use device interface */
    405         while (*++parent && *parent != '/');
    406         if (*parent)
    407             while (*++parent && *parent != '/');
    408         if (!*parent)
    409             goto err;
    410         slash = strchr(++parent, '/');
    411         if (!slash)
    412             goto err;
    413         width = slash - parent;
    414         if (width <= 0)
    415             goto err;
    416 
    417         if (asprintf(&links[link_num], "/dev/usb/%s%.*s", uevent->subsystem, width, parent) > 0)
    418             link_num++;
    419         else
    420             links[link_num] = NULL;
    421         mkdir("/dev/usb", 0755);
    422     }
    423     else {
    424         goto err;
    425     }
    426 
    427     return links;
    428 err:
    429     free(links);
    430     return NULL;
    431 }
    432 
    433 static char **parse_platform_block_device(struct uevent *uevent)
    434 {
    435     const char *device;
    436     const char *path;
    437     char *slash;
    438     int width;
    439     char buf[256];
    440     char link_path[256];
    441     int fd;
    442     int link_num = 0;
    443     int ret;
    444     char *p;
    445     unsigned int size;
    446     struct stat info;
    447 
    448     char **links = malloc(sizeof(char *) * 4);
    449     if (!links)
    450         return NULL;
    451     memset(links, 0, sizeof(char *) * 4);
    452 
    453     /* Drop "/devices/platform/" */
    454     path = uevent->path;
    455     device = path + 18;
    456     device = find_platform_device(device);
    457     if (!device)
    458         goto err;
    459 
    460     INFO("found platform device %s\n", device);
    461 
    462     snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device);
    463 
    464     if (uevent->partition_name) {
    465         p = strdup(uevent->partition_name);
    466         sanitize(p);
    467         if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
    468             link_num++;
    469         else
    470             links[link_num] = NULL;
    471         free(p);
    472     }
    473 
    474     if (uevent->partition_num >= 0) {
    475         if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0)
    476             link_num++;
    477         else
    478             links[link_num] = NULL;
    479     }
    480 
    481     slash = strrchr(path, '/');
    482     if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0)
    483         link_num++;
    484     else
    485         links[link_num] = NULL;
    486 
    487     return links;
    488 
    489 err:
    490     free(links);
    491     return NULL;
    492 }
    493 
    494 static void handle_device(const char *action, const char *devpath,
    495         const char *path, int block, int major, int minor, char **links)
    496 {
    497     int i;
    498 
    499     if(!strcmp(action, "add")) {
    500         make_device(devpath, path, block, major, minor);
    501         if (links) {
    502             for (i = 0; links[i]; i++)
    503                 make_link(devpath, links[i]);
    504         }
    505     }
    506 
    507     if(!strcmp(action, "remove")) {
    508         if (links) {
    509             for (i = 0; links[i]; i++)
    510                 remove_link(devpath, links[i]);
    511         }
    512         unlink(devpath);
    513     }
    514 
    515     if (links) {
    516         for (i = 0; links[i]; i++)
    517             free(links[i]);
    518         free(links);
    519     }
    520 }
    521 
    522 static void handle_platform_device_event(struct uevent *uevent)
    523 {
    524     const char *name = uevent->path + 18; /* length of /devices/platform/ */
    525 
    526     if (!strcmp(uevent->action, "add"))
    527         add_platform_device(name);
    528     else if (!strcmp(uevent->action, "remove"))
    529         remove_platform_device(name);
    530 }
    531 
    532 static const char *parse_device_name(struct uevent *uevent, unsigned int len)
    533 {
    534     const char *name;
    535 
    536     /* if it's not a /dev device, nothing else to do */
    537     if((uevent->major < 0) || (uevent->minor < 0))
    538         return NULL;
    539 
    540     /* do we have a name? */
    541     name = strrchr(uevent->path, '/');
    542     if(!name)
    543         return NULL;
    544     name++;
    545 
    546     /* too-long names would overrun our buffer */
    547     if(strlen(name) > len)
    548         return NULL;
    549 
    550     return name;
    551 }
    552 
    553 static void handle_block_device_event(struct uevent *uevent)
    554 {
    555     const char *base = "/dev/block/";
    556     const char *name;
    557     char devpath[96];
    558     char **links = NULL;
    559 
    560     name = parse_device_name(uevent, 64);
    561     if (!name)
    562         return;
    563 
    564     snprintf(devpath, sizeof(devpath), "%s%s", base, name);
    565     make_dir(base, 0755);
    566 
    567     if (!strncmp(uevent->path, "/devices/platform/", 18))
    568         links = parse_platform_block_device(uevent);
    569 
    570     handle_device(uevent->action, devpath, uevent->path, 1,
    571             uevent->major, uevent->minor, links);
    572 }
    573 
    574 static void handle_generic_device_event(struct uevent *uevent)
    575 {
    576     char *base;
    577     const char *name;
    578     char devpath[96] = {0};
    579     char **links = NULL;
    580 
    581     name = parse_device_name(uevent, 64);
    582     if (!name)
    583         return;
    584 
    585     if (!strncmp(uevent->subsystem, "usb", 3)) {
    586          if (!strcmp(uevent->subsystem, "usb")) {
    587             if (uevent->device_name) {
    588                 /*
    589                  * create device node provided by kernel if present
    590                  * see drivers/base/core.c
    591                  */
    592                 char *p = devpath;
    593                 snprintf(devpath, sizeof(devpath), "/dev/%s", uevent->device_name);
    594                 /* skip leading /dev/ */
    595                 p += 5;
    596                 /* build directories */
    597                 while (*p) {
    598                     if (*p == '/') {
    599                         *p = 0;
    600                         make_dir(devpath, 0755);
    601                         *p = '/';
    602                     }
    603                     p++;
    604                 }
    605              }
    606              else {
    607                  /* This imitates the file system that would be created
    608                   * if we were using devfs instead.
    609                   * Minors are broken up into groups of 128, starting at "001"
    610                   */
    611                  int bus_id = uevent->minor / 128 + 1;
    612                  int device_id = uevent->minor % 128 + 1;
    613                  /* build directories */
    614                  make_dir("/dev/bus", 0755);
    615                  make_dir("/dev/bus/usb", 0755);
    616                  snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id);
    617                  make_dir(devpath, 0755);
    618                  snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id);
    619              }
    620          } else {
    621              /* ignore other USB events */
    622              return;
    623          }
    624      } else if (!strncmp(uevent->subsystem, "graphics", 8)) {
    625          base = "/dev/graphics/";
    626          make_dir(base, 0755);
    627      } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) {
    628          base = "/dev/oncrpc/";
    629          make_dir(base, 0755);
    630      } else if (!strncmp(uevent->subsystem, "adsp", 4)) {
    631          base = "/dev/adsp/";
    632          make_dir(base, 0755);
    633      } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) {
    634          base = "/dev/msm_camera/";
    635          make_dir(base, 0755);
    636      } else if(!strncmp(uevent->subsystem, "input", 5)) {
    637          base = "/dev/input/";
    638          make_dir(base, 0755);
    639      } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
    640          base = "/dev/mtd/";
    641          make_dir(base, 0755);
    642      } else if(!strncmp(uevent->subsystem, "sound", 5)) {
    643          base = "/dev/snd/";
    644          make_dir(base, 0755);
    645      } else if(!strncmp(uevent->subsystem, "misc", 4) &&
    646                  !strncmp(name, "log_", 4)) {
    647          base = "/dev/log/";
    648          make_dir(base, 0755);
    649          name += 4;
    650      } else
    651          base = "/dev/";
    652      links = get_character_device_symlinks(uevent);
    653 
    654      if (!devpath[0])
    655          snprintf(devpath, sizeof(devpath), "%s%s", base, name);
    656 
    657      handle_device(uevent->action, devpath, uevent->path, 0,
    658              uevent->major, uevent->minor, links);
    659 }
    660 
    661 static void handle_device_event(struct uevent *uevent)
    662 {
    663     if (!strcmp(uevent->action,"add"))
    664         fixup_sys_perms(uevent->path);
    665 
    666     if (!strncmp(uevent->subsystem, "block", 5)) {
    667         handle_block_device_event(uevent);
    668     } else if (!strncmp(uevent->subsystem, "platform", 8)) {
    669         handle_platform_device_event(uevent);
    670     } else {
    671         handle_generic_device_event(uevent);
    672     }
    673 }
    674 
    675 static int load_firmware(int fw_fd, int loading_fd, int data_fd)
    676 {
    677     struct stat st;
    678     long len_to_copy;
    679     int ret = 0;
    680 
    681     if(fstat(fw_fd, &st) < 0)
    682         return -1;
    683     len_to_copy = st.st_size;
    684 
    685     write(loading_fd, "1", 1);  /* start transfer */
    686 
    687     while (len_to_copy > 0) {
    688         char buf[PAGE_SIZE];
    689         ssize_t nr;
    690 
    691         nr = read(fw_fd, buf, sizeof(buf));
    692         if(!nr)
    693             break;
    694         if(nr < 0) {
    695             ret = -1;
    696             break;
    697         }
    698 
    699         len_to_copy -= nr;
    700         while (nr > 0) {
    701             ssize_t nw = 0;
    702 
    703             nw = write(data_fd, buf + nw, nr);
    704             if(nw <= 0) {
    705                 ret = -1;
    706                 goto out;
    707             }
    708             nr -= nw;
    709         }
    710     }
    711 
    712 out:
    713     if(!ret)
    714         write(loading_fd, "0", 1);  /* successful end of transfer */
    715     else
    716         write(loading_fd, "-1", 2); /* abort transfer */
    717 
    718     return ret;
    719 }
    720 
    721 static int is_booting(void)
    722 {
    723     return access("/dev/.booting", F_OK) == 0;
    724 }
    725 
    726 static void process_firmware_event(struct uevent *uevent)
    727 {
    728     char *root, *loading, *data, *file1 = NULL, *file2 = NULL;
    729     int l, loading_fd, data_fd, fw_fd;
    730     int booting = is_booting();
    731 
    732     INFO("firmware: loading '%s' for '%s'\n",
    733          uevent->firmware, uevent->path);
    734 
    735     l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
    736     if (l == -1)
    737         return;
    738 
    739     l = asprintf(&loading, "%sloading", root);
    740     if (l == -1)
    741         goto root_free_out;
    742 
    743     l = asprintf(&data, "%sdata", root);
    744     if (l == -1)
    745         goto loading_free_out;
    746 
    747     l = asprintf(&file1, FIRMWARE_DIR1"/%s", uevent->firmware);
    748     if (l == -1)
    749         goto data_free_out;
    750 
    751     l = asprintf(&file2, FIRMWARE_DIR2"/%s", uevent->firmware);
    752     if (l == -1)
    753         goto data_free_out;
    754 
    755     loading_fd = open(loading, O_WRONLY);
    756     if(loading_fd < 0)
    757         goto file_free_out;
    758 
    759     data_fd = open(data, O_WRONLY);
    760     if(data_fd < 0)
    761         goto loading_close_out;
    762 
    763 try_loading_again:
    764     fw_fd = open(file1, O_RDONLY);
    765     if(fw_fd < 0) {
    766         fw_fd = open(file2, O_RDONLY);
    767         if (fw_fd < 0) {
    768             if (booting) {
    769                     /* If we're not fully booted, we may be missing
    770                      * filesystems needed for firmware, wait and retry.
    771                      */
    772                 usleep(100000);
    773                 booting = is_booting();
    774                 goto try_loading_again;
    775             }
    776             INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno);
    777             write(loading_fd, "-1", 2);
    778             goto data_close_out;
    779         }
    780     }
    781 
    782     if(!load_firmware(fw_fd, loading_fd, data_fd))
    783         INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
    784     else
    785         INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
    786 
    787     close(fw_fd);
    788 data_close_out:
    789     close(data_fd);
    790 loading_close_out:
    791     close(loading_fd);
    792 file_free_out:
    793     free(file1);
    794     free(file2);
    795 data_free_out:
    796     free(data);
    797 loading_free_out:
    798     free(loading);
    799 root_free_out:
    800     free(root);
    801 }
    802 
    803 static void handle_firmware_event(struct uevent *uevent)
    804 {
    805     pid_t pid;
    806     int ret;
    807 
    808     if(strcmp(uevent->subsystem, "firmware"))
    809         return;
    810 
    811     if(strcmp(uevent->action, "add"))
    812         return;
    813 
    814     /* we fork, to avoid making large memory allocations in init proper */
    815     pid = fork();
    816     if (!pid) {
    817         process_firmware_event(uevent);
    818         exit(EXIT_SUCCESS);
    819     }
    820 }
    821 
    822 #define UEVENT_MSG_LEN  1024
    823 void handle_device_fd()
    824 {
    825     char msg[UEVENT_MSG_LEN+2];
    826     int n;
    827     while ((n = uevent_kernel_multicast_recv(device_fd, msg, UEVENT_MSG_LEN)) > 0) {
    828         if(n >= UEVENT_MSG_LEN)   /* overflow -- discard */
    829             continue;
    830 
    831         msg[n] = '\0';
    832         msg[n+1] = '\0';
    833 
    834         struct uevent uevent;
    835         parse_event(msg, &uevent);
    836 
    837         handle_device_event(&uevent);
    838         handle_firmware_event(&uevent);
    839     }
    840 }
    841 
    842 /* Coldboot walks parts of the /sys tree and pokes the uevent files
    843 ** to cause the kernel to regenerate device add events that happened
    844 ** before init's device manager was started
    845 **
    846 ** We drain any pending events from the netlink socket every time
    847 ** we poke another uevent file to make sure we don't overrun the
    848 ** socket's buffer.
    849 */
    850 
    851 static void do_coldboot(DIR *d)
    852 {
    853     struct dirent *de;
    854     int dfd, fd;
    855 
    856     dfd = dirfd(d);
    857 
    858     fd = openat(dfd, "uevent", O_WRONLY);
    859     if(fd >= 0) {
    860         write(fd, "add\n", 4);
    861         close(fd);
    862         handle_device_fd();
    863     }
    864 
    865     while((de = readdir(d))) {
    866         DIR *d2;
    867 
    868         if(de->d_type != DT_DIR || de->d_name[0] == '.')
    869             continue;
    870 
    871         fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
    872         if(fd < 0)
    873             continue;
    874 
    875         d2 = fdopendir(fd);
    876         if(d2 == 0)
    877             close(fd);
    878         else {
    879             do_coldboot(d2);
    880             closedir(d2);
    881         }
    882     }
    883 }
    884 
    885 static void coldboot(const char *path)
    886 {
    887     DIR *d = opendir(path);
    888     if(d) {
    889         do_coldboot(d);
    890         closedir(d);
    891     }
    892 }
    893 
    894 void device_init(void)
    895 {
    896     suseconds_t t0, t1;
    897     struct stat info;
    898     int fd;
    899 #ifdef HAVE_SELINUX
    900     struct selinux_opt seopts[] = {
    901         { SELABEL_OPT_PATH, "/file_contexts" }
    902     };
    903 
    904     if (is_selinux_enabled() > 0)
    905         sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);
    906 #endif
    907     /* is 64K enough? udev uses 16MB! */
    908     device_fd = uevent_open_socket(64*1024, true);
    909     if(device_fd < 0)
    910         return;
    911 
    912     fcntl(device_fd, F_SETFD, FD_CLOEXEC);
    913     fcntl(device_fd, F_SETFL, O_NONBLOCK);
    914 
    915     if (stat(coldboot_done, &info) < 0) {
    916         t0 = get_usecs();
    917         coldboot("/sys/class");
    918         coldboot("/sys/block");
    919         coldboot("/sys/devices");
    920         t1 = get_usecs();
    921         fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000);
    922         close(fd);
    923         log_event_print("coldboot %ld uS\n", ((long) (t1 - t0)));
    924     } else {
    925         log_event_print("skipping coldboot, already done\n");
    926     }
    927 }
    928 
    929 int get_device_fd()
    930 {
    931     return device_fd;
    932 }
    933