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