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