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