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