devices.c revision eb5ba8306522acdbf3a63ca847e5e6b990d842b9
1/* 2 * Copyright (C) 2007 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#include <private/android_filesystem_config.h> 33#include <sys/time.h> 34#include <asm/page.h> 35#include <sys/wait.h> 36 37#include "devices.h" 38#include "util.h" 39#include "log.h" 40#include "list.h" 41 42#define SYSFS_PREFIX "/sys" 43#define FIRMWARE_DIR1 "/etc/firmware" 44#define FIRMWARE_DIR2 "/vendor/firmware" 45 46static int device_fd = -1; 47 48struct uevent { 49 const char *action; 50 const char *path; 51 const char *subsystem; 52 const char *firmware; 53 const char *partition_name; 54 int partition_num; 55 int major; 56 int minor; 57}; 58 59static int open_uevent_socket(void) 60{ 61 struct sockaddr_nl addr; 62 int sz = 64*1024; // XXX larger? udev uses 16MB! 63 int on = 1; 64 int s; 65 66 memset(&addr, 0, sizeof(addr)); 67 addr.nl_family = AF_NETLINK; 68 addr.nl_pid = getpid(); 69 addr.nl_groups = 0xffffffff; 70 71 s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 72 if(s < 0) 73 return -1; 74 75 setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)); 76 setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); 77 78 if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 79 close(s); 80 return -1; 81 } 82 83 return s; 84} 85 86struct perms_ { 87 char *name; 88 char *attr; 89 mode_t perm; 90 unsigned int uid; 91 unsigned int gid; 92 unsigned short prefix; 93}; 94 95struct perm_node { 96 struct perms_ dp; 97 struct listnode plist; 98}; 99 100static list_declare(sys_perms); 101static list_declare(dev_perms); 102 103int add_dev_perms(const char *name, const char *attr, 104 mode_t perm, unsigned int uid, unsigned int gid, 105 unsigned short prefix) { 106 struct perm_node *node = calloc(1, sizeof(*node)); 107 if (!node) 108 return -ENOMEM; 109 110 node->dp.name = strdup(name); 111 if (!node->dp.name) 112 return -ENOMEM; 113 114 if (attr) { 115 node->dp.attr = strdup(attr); 116 if (!node->dp.attr) 117 return -ENOMEM; 118 } 119 120 node->dp.perm = perm; 121 node->dp.uid = uid; 122 node->dp.gid = gid; 123 node->dp.prefix = prefix; 124 125 if (attr) 126 list_add_tail(&sys_perms, &node->plist); 127 else 128 list_add_tail(&dev_perms, &node->plist); 129 130 return 0; 131} 132 133void fixup_sys_perms(const char *upath) 134{ 135 char buf[512]; 136 struct listnode *node; 137 struct perms_ *dp; 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 { 148 if (strcmp(upath, dp->name + 4)) 149 continue; 150 } 151 152 if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf)) 153 return; 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 162static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) 163{ 164 mode_t perm; 165 struct listnode *node; 166 struct perm_node *perm_node; 167 struct perms_ *dp; 168 169 /* search the perms list in reverse so that ueventd.$hardware can 170 * override ueventd.rc 171 */ 172 list_for_each_reverse(node, &dev_perms) { 173 perm_node = node_to_item(node, struct perm_node, plist); 174 dp = &perm_node->dp; 175 176 if (dp->prefix) { 177 if (strncmp(path, dp->name, strlen(dp->name))) 178 continue; 179 } else { 180 if (strcmp(path, dp->name)) 181 continue; 182 } 183 *uid = dp->uid; 184 *gid = dp->gid; 185 return dp->perm; 186 } 187 /* Default if nothing found. */ 188 *uid = 0; 189 *gid = 0; 190 return 0600; 191} 192 193static void make_device(const char *path, 194 const char *upath, 195 int block, int major, int minor) 196{ 197 unsigned uid; 198 unsigned gid; 199 mode_t mode; 200 dev_t dev; 201 202 mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); 203 dev = makedev(major, minor); 204 /* Temporarily change egid to avoid race condition setting the gid of the 205 * device node. Unforunately changing the euid would prevent creation of 206 * some device nodes, so the uid has to be set with chown() and is still 207 * racy. Fixing the gid race at least fixed the issue with system_server 208 * opening dynamic input devices under the AID_INPUT gid. */ 209 setegid(gid); 210 mknod(path, mode, dev); 211 chown(path, uid, -1); 212 setegid(AID_ROOT); 213} 214 215#if LOG_UEVENTS 216 217static inline suseconds_t get_usecs(void) 218{ 219 struct timeval tv; 220 gettimeofday(&tv, 0); 221 return tv.tv_sec * (suseconds_t) 1000000 + tv.tv_usec; 222} 223 224#define log_event_print(x...) INFO(x) 225 226#else 227 228#define log_event_print(fmt, args...) do { } while (0) 229#define get_usecs() 0 230 231#endif 232 233static void parse_event(const char *msg, struct uevent *uevent) 234{ 235 uevent->action = ""; 236 uevent->path = ""; 237 uevent->subsystem = ""; 238 uevent->firmware = ""; 239 uevent->major = -1; 240 uevent->minor = -1; 241 uevent->partition_name = NULL; 242 uevent->partition_num = -1; 243 244 /* currently ignoring SEQNUM */ 245 while(*msg) { 246 if(!strncmp(msg, "ACTION=", 7)) { 247 msg += 7; 248 uevent->action = msg; 249 } else if(!strncmp(msg, "DEVPATH=", 8)) { 250 msg += 8; 251 uevent->path = msg; 252 } else if(!strncmp(msg, "SUBSYSTEM=", 10)) { 253 msg += 10; 254 uevent->subsystem = msg; 255 } else if(!strncmp(msg, "FIRMWARE=", 9)) { 256 msg += 9; 257 uevent->firmware = msg; 258 } else if(!strncmp(msg, "MAJOR=", 6)) { 259 msg += 6; 260 uevent->major = atoi(msg); 261 } else if(!strncmp(msg, "MINOR=", 6)) { 262 msg += 6; 263 uevent->minor = atoi(msg); 264 } else if(!strncmp(msg, "PARTN=", 6)) { 265 msg += 6; 266 uevent->partition_num = atoi(msg); 267 } else if(!strncmp(msg, "PARTNAME=", 9)) { 268 msg += 9; 269 uevent->partition_name = msg; 270 } 271 272 /* advance to after the next \0 */ 273 while(*msg++) 274 ; 275 } 276 277 log_event_print("event { '%s', '%s', '%s', '%s', %d, %d }\n", 278 uevent->action, uevent->path, uevent->subsystem, 279 uevent->firmware, uevent->major, uevent->minor); 280} 281 282static char **get_character_device_symlinks(struct uevent *uevent) 283{ 284 const char *parent; 285 char *slash; 286 char **links; 287 int link_num = 0; 288 int width; 289 290 if (strncmp(uevent->path, "/devices/platform/", 18)) 291 return NULL; 292 293 links = malloc(sizeof(char *) * 2); 294 if (!links) 295 return NULL; 296 memset(links, 0, sizeof(char *) * 2); 297 298 /* skip "/devices/platform/<driver>" */ 299 parent = strchr(uevent->path + 18, '/'); 300 if (!*parent) 301 goto err; 302 303 if (!strncmp(parent, "/usb", 4)) { 304 /* skip root hub name and device. use device interface */ 305 while (*++parent && *parent != '/'); 306 if (*parent) 307 while (*++parent && *parent != '/'); 308 if (!*parent) 309 goto err; 310 slash = strchr(++parent, '/'); 311 if (!slash) 312 goto err; 313 width = slash - parent; 314 if (width <= 0) 315 goto err; 316 317 if (asprintf(&links[link_num], "/dev/usb/%s%.*s", uevent->subsystem, width, parent) > 0) 318 link_num++; 319 else 320 links[link_num] = NULL; 321 mkdir("/dev/usb", 0755); 322 } 323 else { 324 goto err; 325 } 326 327 return links; 328err: 329 free(links); 330 return NULL; 331} 332 333static char **parse_platform_block_device(struct uevent *uevent) 334{ 335 const char *driver; 336 const char *path; 337 char *slash; 338 int width; 339 char buf[256]; 340 char link_path[256]; 341 int fd; 342 int link_num = 0; 343 int ret; 344 char *p; 345 unsigned int size; 346 struct stat info; 347 348 char **links = malloc(sizeof(char *) * 4); 349 if (!links) 350 return NULL; 351 memset(links, 0, sizeof(char *) * 4); 352 353 /* Drop "/devices/platform/" */ 354 path = uevent->path; 355 driver = path + 18; 356 slash = strchr(driver, '/'); 357 if (!slash) 358 goto err; 359 width = slash - driver; 360 if (width <= 0) 361 goto err; 362 363 snprintf(link_path, sizeof(link_path), "/dev/block/platform/%.*s", 364 width, driver); 365 366 if (uevent->partition_name) { 367 p = strdup(uevent->partition_name); 368 sanitize(p); 369 if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0) 370 link_num++; 371 else 372 links[link_num] = NULL; 373 free(p); 374 } 375 376 if (uevent->partition_num >= 0) { 377 if (asprintf(&links[link_num], "%s/by-num/p%d", link_path, uevent->partition_num) > 0) 378 link_num++; 379 else 380 links[link_num] = NULL; 381 } 382 383 slash = strrchr(path, '/'); 384 if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0) 385 link_num++; 386 else 387 links[link_num] = NULL; 388 389 return links; 390 391err: 392 free(links); 393 return NULL; 394} 395 396static void handle_device(const char *action, const char *devpath, 397 const char *path, int block, int major, int minor, char **links) 398{ 399 int i; 400 401 if(!strcmp(action, "add")) { 402 make_device(devpath, path, block, major, minor); 403 if (links) { 404 for (i = 0; links[i]; i++) 405 make_link(devpath, links[i]); 406 } 407 } 408 409 if(!strcmp(action, "remove")) { 410 if (links) { 411 for (i = 0; links[i]; i++) 412 remove_link(devpath, links[i]); 413 } 414 unlink(devpath); 415 } 416 417 if (links) { 418 for (i = 0; links[i]; i++) 419 free(links[i]); 420 free(links); 421 } 422} 423 424static const char *parse_device_name(struct uevent *uevent, unsigned int len) 425{ 426 const char *name; 427 428 /* if it's not a /dev device, nothing else to do */ 429 if((uevent->major < 0) || (uevent->minor < 0)) 430 return NULL; 431 432 /* do we have a name? */ 433 name = strrchr(uevent->path, '/'); 434 if(!name) 435 return NULL; 436 name++; 437 438 /* too-long names would overrun our buffer */ 439 if(strlen(name) > len) 440 return NULL; 441 442 return name; 443} 444 445static void handle_block_device_event(struct uevent *uevent) 446{ 447 const char *base = "/dev/block/"; 448 const char *name; 449 char devpath[96]; 450 char **links = NULL; 451 452 name = parse_device_name(uevent, 64); 453 if (!name) 454 return; 455 456 snprintf(devpath, sizeof(devpath), "%s%s", base, name); 457 mkdir(base, 0755); 458 459 if (!strncmp(uevent->path, "/devices/platform/", 18)) 460 links = parse_platform_block_device(uevent); 461 462 handle_device(uevent->action, devpath, uevent->path, 1, 463 uevent->major, uevent->minor, links); 464 465} 466 467static void handle_generic_device_event(struct uevent *uevent) 468{ 469 char *base; 470 const char *name; 471 char devpath[96] = {0}; 472 char **links = NULL; 473 474 name = parse_device_name(uevent, 64); 475 if (!name) 476 return; 477 478 if (!strncmp(uevent->subsystem, "usb", 3)) { 479 if (!strcmp(uevent->subsystem, "usb")) { 480 /* This imitates the file system that would be created 481 * if we were using devfs instead. 482 * Minors are broken up into groups of 128, starting at "001" 483 */ 484 int bus_id = uevent->minor / 128 + 1; 485 int device_id = uevent->minor % 128 + 1; 486 /* build directories */ 487 mkdir("/dev/bus", 0755); 488 mkdir("/dev/bus/usb", 0755); 489 snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d", bus_id); 490 mkdir(devpath, 0755); 491 snprintf(devpath, sizeof(devpath), "/dev/bus/usb/%03d/%03d", bus_id, device_id); 492 } else { 493 /* ignore other USB events */ 494 return; 495 } 496 } else if (!strncmp(uevent->subsystem, "graphics", 8)) { 497 base = "/dev/graphics/"; 498 mkdir(base, 0755); 499 } else if (!strncmp(uevent->subsystem, "oncrpc", 6)) { 500 base = "/dev/oncrpc/"; 501 mkdir(base, 0755); 502 } else if (!strncmp(uevent->subsystem, "adsp", 4)) { 503 base = "/dev/adsp/"; 504 mkdir(base, 0755); 505 } else if (!strncmp(uevent->subsystem, "msm_camera", 10)) { 506 base = "/dev/msm_camera/"; 507 mkdir(base, 0755); 508 } else if(!strncmp(uevent->subsystem, "input", 5)) { 509 base = "/dev/input/"; 510 mkdir(base, 0755); 511 } else if(!strncmp(uevent->subsystem, "mtd", 3)) { 512 base = "/dev/mtd/"; 513 mkdir(base, 0755); 514 } else if(!strncmp(uevent->subsystem, "sound", 5)) { 515 base = "/dev/snd/"; 516 mkdir(base, 0755); 517 } else if(!strncmp(uevent->subsystem, "misc", 4) && 518 !strncmp(name, "log_", 4)) { 519 base = "/dev/log/"; 520 mkdir(base, 0755); 521 name += 4; 522 } else 523 base = "/dev/"; 524 links = get_character_device_symlinks(uevent); 525 526 if (!devpath[0]) 527 snprintf(devpath, sizeof(devpath), "%s%s", base, name); 528 529 handle_device(uevent->action, devpath, uevent->path, 0, 530 uevent->major, uevent->minor, links); 531} 532 533static void handle_device_event(struct uevent *uevent) 534{ 535 if (!strcmp(uevent->action,"add")) 536 fixup_sys_perms(uevent->path); 537 538 if (!strncmp(uevent->subsystem, "block", 5)) { 539 handle_block_device_event(uevent); 540 } else { 541 handle_generic_device_event(uevent); 542 } 543} 544 545static int load_firmware(int fw_fd, int loading_fd, int data_fd) 546{ 547 struct stat st; 548 long len_to_copy; 549 int ret = 0; 550 551 if(fstat(fw_fd, &st) < 0) 552 return -1; 553 len_to_copy = st.st_size; 554 555 write(loading_fd, "1", 1); /* start transfer */ 556 557 while (len_to_copy > 0) { 558 char buf[PAGE_SIZE]; 559 ssize_t nr; 560 561 nr = read(fw_fd, buf, sizeof(buf)); 562 if(!nr) 563 break; 564 if(nr < 0) { 565 ret = -1; 566 break; 567 } 568 569 len_to_copy -= nr; 570 while (nr > 0) { 571 ssize_t nw = 0; 572 573 nw = write(data_fd, buf + nw, nr); 574 if(nw <= 0) { 575 ret = -1; 576 goto out; 577 } 578 nr -= nw; 579 } 580 } 581 582out: 583 if(!ret) 584 write(loading_fd, "0", 1); /* successful end of transfer */ 585 else 586 write(loading_fd, "-1", 2); /* abort transfer */ 587 588 return ret; 589} 590 591static int is_booting(void) 592{ 593 return access("/dev/.booting", F_OK) == 0; 594} 595 596static void process_firmware_event(struct uevent *uevent) 597{ 598 char *root, *loading, *data, *file1 = NULL, *file2 = NULL; 599 int l, loading_fd, data_fd, fw_fd; 600 int booting = is_booting(); 601 602 INFO("firmware: loading '%s' for '%s'\n", 603 uevent->firmware, uevent->path); 604 605 l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path); 606 if (l == -1) 607 return; 608 609 l = asprintf(&loading, "%sloading", root); 610 if (l == -1) 611 goto root_free_out; 612 613 l = asprintf(&data, "%sdata", root); 614 if (l == -1) 615 goto loading_free_out; 616 617 l = asprintf(&file1, FIRMWARE_DIR1"/%s", uevent->firmware); 618 if (l == -1) 619 goto data_free_out; 620 621 l = asprintf(&file2, FIRMWARE_DIR2"/%s", uevent->firmware); 622 if (l == -1) 623 goto data_free_out; 624 625 loading_fd = open(loading, O_WRONLY); 626 if(loading_fd < 0) 627 goto file_free_out; 628 629 data_fd = open(data, O_WRONLY); 630 if(data_fd < 0) 631 goto loading_close_out; 632 633try_loading_again: 634 fw_fd = open(file1, O_RDONLY); 635 if(fw_fd < 0) { 636 fw_fd = open(file2, O_RDONLY); 637 if (fw_fd < 0) { 638 if (booting) { 639 /* If we're not fully booted, we may be missing 640 * filesystems needed for firmware, wait and retry. 641 */ 642 usleep(100000); 643 booting = is_booting(); 644 goto try_loading_again; 645 } 646 INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno); 647 write(loading_fd, "-1", 2); 648 goto data_close_out; 649 } 650 } 651 652 if(!load_firmware(fw_fd, loading_fd, data_fd)) 653 INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware); 654 else 655 INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware); 656 657 close(fw_fd); 658data_close_out: 659 close(data_fd); 660loading_close_out: 661 close(loading_fd); 662file_free_out: 663 free(file1); 664 free(file2); 665data_free_out: 666 free(data); 667loading_free_out: 668 free(loading); 669root_free_out: 670 free(root); 671} 672 673static void handle_firmware_event(struct uevent *uevent) 674{ 675 pid_t pid; 676 int ret; 677 678 if(strcmp(uevent->subsystem, "firmware")) 679 return; 680 681 if(strcmp(uevent->action, "add")) 682 return; 683 684 /* we fork, to avoid making large memory allocations in init proper */ 685 pid = fork(); 686 if (!pid) { 687 process_firmware_event(uevent); 688 exit(EXIT_SUCCESS); 689 } 690} 691 692#define UEVENT_MSG_LEN 1024 693void handle_device_fd() 694{ 695 for(;;) { 696 char msg[UEVENT_MSG_LEN+2]; 697 char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; 698 struct iovec iov = {msg, sizeof(msg)}; 699 struct sockaddr_nl snl; 700 struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0}; 701 702 ssize_t n = recvmsg(device_fd, &hdr, 0); 703 if (n <= 0) { 704 break; 705 } 706 707 if ((snl.nl_groups != 1) || (snl.nl_pid != 0)) { 708 /* ignoring non-kernel netlink multicast message */ 709 continue; 710 } 711 712 struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr); 713 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { 714 /* no sender credentials received, ignore message */ 715 continue; 716 } 717 718 struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg); 719 if (cred->uid != 0) { 720 /* message from non-root user, ignore */ 721 continue; 722 } 723 724 if(n >= UEVENT_MSG_LEN) /* overflow -- discard */ 725 continue; 726 727 msg[n] = '\0'; 728 msg[n+1] = '\0'; 729 730 struct uevent uevent; 731 parse_event(msg, &uevent); 732 733 handle_device_event(&uevent); 734 handle_firmware_event(&uevent); 735 } 736} 737 738/* Coldboot walks parts of the /sys tree and pokes the uevent files 739** to cause the kernel to regenerate device add events that happened 740** before init's device manager was started 741** 742** We drain any pending events from the netlink socket every time 743** we poke another uevent file to make sure we don't overrun the 744** socket's buffer. 745*/ 746 747static void do_coldboot(DIR *d) 748{ 749 struct dirent *de; 750 int dfd, fd; 751 752 dfd = dirfd(d); 753 754 fd = openat(dfd, "uevent", O_WRONLY); 755 if(fd >= 0) { 756 write(fd, "add\n", 4); 757 close(fd); 758 handle_device_fd(); 759 } 760 761 while((de = readdir(d))) { 762 DIR *d2; 763 764 if(de->d_type != DT_DIR || de->d_name[0] == '.') 765 continue; 766 767 fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); 768 if(fd < 0) 769 continue; 770 771 d2 = fdopendir(fd); 772 if(d2 == 0) 773 close(fd); 774 else { 775 do_coldboot(d2); 776 closedir(d2); 777 } 778 } 779} 780 781static void coldboot(const char *path) 782{ 783 DIR *d = opendir(path); 784 if(d) { 785 do_coldboot(d); 786 closedir(d); 787 } 788} 789 790void device_init(void) 791{ 792 suseconds_t t0, t1; 793 struct stat info; 794 int fd; 795 796 device_fd = open_uevent_socket(); 797 if(device_fd < 0) 798 return; 799 800 fcntl(device_fd, F_SETFD, FD_CLOEXEC); 801 fcntl(device_fd, F_SETFL, O_NONBLOCK); 802 803 if (stat(coldboot_done, &info) < 0) { 804 t0 = get_usecs(); 805 coldboot("/sys/class"); 806 coldboot("/sys/block"); 807 coldboot("/sys/devices"); 808 t1 = get_usecs(); 809 fd = open(coldboot_done, O_WRONLY|O_CREAT, 0000); 810 close(fd); 811 log_event_print("coldboot %ld uS\n", ((long) (t1 - t0))); 812 } else { 813 log_event_print("skipping coldboot, already done\n"); 814 } 815} 816 817int get_device_fd() 818{ 819 return device_fd; 820} 821