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