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