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