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