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