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