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