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