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