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