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