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