1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Devfsadm replaces drvconfig, audlinks, disks, tapes, ports, devlinks 31 * as a general purpose device administrative utility. It creates 32 * devices special files in /devices and logical links in /dev, and 33 * coordinates updates to /etc/path_to_instance with the kernel. It 34 * operates in both command line mode to handle user or script invoked 35 * reconfiguration updates, and operates in daemon mode to handle dynamic 36 * reconfiguration for hotplugging support. 37 */ 38 39 #include <string.h> 40 #include <deflt.h> 41 #include <tsol/label.h> 42 #include <bsm/devices.h> 43 #include <bsm/devalloc.h> 44 #include <utime.h> 45 #include <sys/param.h> 46 #include <bsm/libbsm.h> 47 #include "devfsadm_impl.h" 48 49 /* externs from devalloc.c */ 50 extern void _reset_devalloc(int); 51 extern void _update_devalloc_db(devlist_t *, int, int, char *, char *); 52 extern int _da_check_for_usb(char *, char *); 53 54 /* create or remove nodes or links. unset with -n */ 55 static int file_mods = TRUE; 56 57 /* cleanup mode. Set with -C */ 58 static int cleanup = FALSE; 59 60 /* devlinks -d compatibility */ 61 static int devlinks_debug = FALSE; 62 63 /* flag to check if system is labeled */ 64 int system_labeled = FALSE; 65 66 /* flag to enable/disable device allocation with -e/-d */ 67 static int devalloc_flag = 0; 68 69 /* flag that indicates if device allocation is on or not */ 70 static int devalloc_is_on = 0; 71 72 /* flag to update device allocation database for this device type */ 73 static int update_devdb = 0; 74 75 /* 76 * devices to be deallocated with -d : 77 * audio, floppy, cd, floppy, tape, rmdisk. 78 */ 79 static char *devalloc_list[10] = {DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_CD_CHAN, 80 DDI_NT_FD, DDI_NT_TAPE, DDI_NT_BLOCK_CHAN, 81 DDI_NT_UGEN, DDI_NT_USB_ATTACHMENT_POINT, 82 DDI_NT_SCSI_NEXUS, NULL}; 83 84 /* list of allocatable devices */ 85 static devlist_t devlist; 86 87 /* load a single driver only. set with -i */ 88 static int single_drv = FALSE; 89 static char *driver = NULL; 90 91 /* attempt to load drivers or defer attach nodes */ 92 static int load_attach_drv = TRUE; 93 94 /* set if invoked via /usr/lib/devfsadm/devfsadmd */ 95 static int daemon_mode = FALSE; 96 97 /* output directed to syslog during daemon mode if set */ 98 static int logflag = FALSE; 99 100 /* build links in /dev. -x to turn off */ 101 static int build_dev = TRUE; 102 103 /* build nodes in /devices. -y to turn off */ 104 static int build_devices = TRUE; 105 106 /* -z to turn off */ 107 static int flush_path_to_inst_enable = TRUE; 108 109 /* variables used for path_to_inst flushing */ 110 static int inst_count = 0; 111 static mutex_t count_lock; 112 static cond_t cv; 113 114 /* variables for minor_fini thread */ 115 static mutex_t minor_fini_mutex; 116 static int minor_fini_canceled = TRUE; 117 static int minor_fini_delayed = FALSE; 118 static cond_t minor_fini_cv; 119 static int minor_fini_timeout = MINOR_FINI_TIMEOUT_DEFAULT; 120 121 /* single-threads /dev modification */ 122 static sema_t dev_sema; 123 124 /* the program we were invoked as; ie argv[0] */ 125 static char *prog; 126 127 /* pointers to create/remove link lists */ 128 static create_list_t *create_head = NULL; 129 static remove_list_t *remove_head = NULL; 130 131 /* supports the class -c option */ 132 static char **classes = NULL; 133 static int num_classes = 0; 134 135 /* used with verbose option -v or -V */ 136 static int num_verbose = 0; 137 static char **verbose = NULL; 138 139 static struct mperm *minor_perms = NULL; 140 static driver_alias_t *driver_aliases = NULL; 141 142 /* set if -r alternate root given */ 143 static char *root_dir = ""; 144 145 /* /devices or <rootdir>/devices */ 146 static char *devices_dir = DEVICES; 147 148 /* /dev or <rootdir>/dev */ 149 static char *dev_dir = DEV; 150 151 /* /etc/dev or <rootdir>/etc/dev */ 152 static char *etc_dev_dir = ETCDEV; 153 154 /* 155 * writable root (for lock files and doors during install). 156 * This is also root dir for /dev attr dir during install. 157 */ 158 static char *attr_root = NULL; 159 160 /* /etc/path_to_inst unless -p used */ 161 static char *inst_file = INSTANCE_FILE; 162 163 /* /usr/lib/devfsadm/linkmods unless -l used */ 164 static char *module_dirs = MODULE_DIRS; 165 166 /* default uid/gid used if /etc/minor_perm entry not found */ 167 static uid_t root_uid; 168 static gid_t sys_gid; 169 170 /* /etc/devlink.tab unless devlinks -t used */ 171 static char *devlinktab_file = NULL; 172 173 /* File and data structure to reserve enumerate IDs */ 174 static char *enumerate_file = ENUMERATE_RESERVED; 175 static enumerate_file_t *enumerate_reserved = NULL; 176 177 /* set if /dev link is new. speeds up rm_stale_links */ 178 static int linknew = TRUE; 179 180 /* variables for devlink.tab compat processing */ 181 static devlinktab_list_t *devlinktab_list = NULL; 182 static unsigned int devlinktab_line = 0; 183 184 /* cache head for devfsadm_enumerate*() functions */ 185 static numeral_set_t *head_numeral_set = NULL; 186 187 /* list list of devfsadm modules */ 188 static module_t *module_head = NULL; 189 190 /* name_to_major list used in utility function */ 191 static n2m_t *n2m_list = NULL; 192 193 /* cache of some links used for performance */ 194 static linkhead_t *headlinkhead = NULL; 195 196 /* locking variables to prevent multiples writes to /dev */ 197 static int hold_dev_lock = FALSE; 198 static int hold_daemon_lock = FALSE; 199 static int dev_lock_fd; 200 static int daemon_lock_fd; 201 static char dev_lockfile[PATH_MAX + 1]; 202 static char daemon_lockfile[PATH_MAX + 1]; 203 204 /* last devinfo node/minor processed. used for performance */ 205 static di_node_t lnode; 206 static di_minor_t lminor; 207 static char lphy_path[PATH_MAX + 1] = {""}; 208 209 /* Globals used by the link database */ 210 static di_devlink_handle_t devlink_cache; 211 static int update_database = FALSE; 212 213 /* Globals used to set logindev perms */ 214 static struct login_dev *login_dev_cache = NULL; 215 static int login_dev_enable = FALSE; 216 217 /* Global to use devinfo snapshot cache */ 218 static int use_snapshot_cache = FALSE; 219 220 /* Global for no-further-processing hash */ 221 static item_t **nfp_hash; 222 static mutex_t nfp_mutex = DEFAULTMUTEX; 223 224 /* 225 * Packaged directories - not removed even when empty. 226 * The dirs must be listed in canonical form 227 * i.e. without leading "/dev/" 228 */ 229 static char *packaged_dirs[] = 230 {"dsk", "rdsk", "term", NULL}; 231 232 /* RCM related globals */ 233 static void *librcm_hdl; 234 static rcm_handle_t *rcm_hdl = NULL; 235 static thread_t process_rcm_events_tid; 236 static struct rcm_eventq *volatile rcm_eventq_head = NULL; 237 static struct rcm_eventq *rcm_eventq_tail = NULL; 238 static mutex_t rcm_eventq_lock; 239 static cond_t rcm_eventq_cv; 240 static volatile int need_to_exit_rcm_event_thread = 0; 241 242 /* Devname globals */ 243 static int devname_debug_msg = 1; 244 static nvlist_t *devname_maps = NULL; 245 static int devname_first_call = 1; 246 static int load_devname_nsmaps = FALSE; 247 static int lookup_door_fd = -1; 248 static char *lookup_door_path; 249 250 static void load_dev_acl(void); 251 static void update_drvconf(major_t); 252 static void check_reconfig_state(void); 253 static void devname_setup_nsmaps(void); 254 static int s_stat(const char *, struct stat *); 255 256 static int is_blank(char *); 257 258 /* sysevent queue related globals */ 259 static mutex_t syseventq_mutex = DEFAULTMUTEX; 260 static syseventq_t *syseventq_front; 261 static syseventq_t *syseventq_back; 262 static void process_syseventq(); 263 264 int 265 main(int argc, char *argv[]) 266 { 267 struct passwd *pw; 268 struct group *gp; 269 pid_t pid; 270 int cond = 0; 271 272 (void) setlocale(LC_ALL, ""); 273 (void) textdomain(TEXT_DOMAIN); 274 275 if ((prog = strrchr(argv[0], '/')) == NULL) { 276 prog = argv[0]; 277 } else { 278 prog++; 279 } 280 281 if (getuid() != 0) { 282 err_print(MUST_BE_ROOT); 283 devfsadm_exit(1); 284 } 285 286 /* 287 * Close all files except stdin/stdout/stderr 288 */ 289 closefrom(3); 290 291 if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) { 292 root_uid = pw->pw_uid; 293 } else { 294 err_print(CANT_FIND_USER, DEFAULT_DEV_USER); 295 root_uid = (uid_t)0; /* assume 0 is root */ 296 } 297 298 /* the default group is sys */ 299 300 if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) { 301 sys_gid = gp->gr_gid; 302 } else { 303 err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP); 304 sys_gid = (gid_t)3; /* assume 3 is sys */ 305 } 306 307 (void) umask(0); 308 309 system_labeled = is_system_labeled(); 310 if (system_labeled == FALSE) { 311 /* 312 * is_system_labeled() will return false in case we are 313 * starting before the first reboot after Trusted Extensions 314 * is enabled. Check the setting in /etc/system to see if 315 * TX is enabled (even if not yet booted). 316 */ 317 if (defopen("/etc/system") == 0) { 318 if (defread("set sys_labeling=1") != NULL) 319 system_labeled = TRUE; 320 321 /* close defaults file */ 322 (void) defopen(NULL); 323 } 324 } 325 /* 326 * Check if device allocation is enabled. 327 */ 328 if (system_labeled) { 329 /* 330 * In TX, the first line in /etc/security/device_allocate has 331 * DEVICE_ALLOCATION=ON if the feature is enabled. 332 */ 333 devalloc_is_on = da_is_on(); 334 } else if (auditon(A_GETCOND, (caddr_t)&cond, sizeof (cond)) == 0) { 335 /* 336 * Device allocation (and auditing) is enabled if BSM is 337 * enabled. auditon returns -1 and sets errno to EINVAL if BSM 338 * is not enabled. 339 */ 340 devalloc_is_on = 1; 341 } 342 343 #ifdef DEBUG 344 if (system_labeled == FALSE) { 345 struct stat tx_stat; 346 347 /* test hook: see also mkdevalloc.c and allocate.c */ 348 system_labeled = is_system_labeled_debug(&tx_stat); 349 } 350 #endif 351 352 parse_args(argc, argv); 353 354 (void) sema_init(&dev_sema, 1, USYNC_THREAD, NULL); 355 356 /* Initialize device allocation list */ 357 devlist.audio = devlist.cd = devlist.floppy = devlist.tape = 358 devlist.rmdisk = NULL; 359 360 if (daemon_mode == TRUE) { 361 /* 362 * Build /dev and /devices before daemonizing if 363 * reconfig booting and daemon invoked with alternate 364 * root. This is to support install. 365 */ 366 if (getenv(RECONFIG_BOOT) != NULL && root_dir[0] != '\0') { 367 vprint(INFO_MID, CONFIGURING); 368 load_dev_acl(); 369 update_drvconf((major_t)-1); 370 process_devinfo_tree(); 371 (void) modctl(MODSETMINIROOT); 372 } 373 374 /* 375 * fork before detaching from tty in order to print error 376 * message if unable to acquire file lock. locks not preserved 377 * across forks. Even under debug we want to fork so that 378 * when executed at boot we don't hang. 379 */ 380 if (fork() != 0) { 381 devfsadm_exit(0); 382 } 383 384 /* set directory to / so it coredumps there */ 385 if (chdir("/") == -1) { 386 err_print(CHROOT_FAILED, strerror(errno)); 387 } 388 389 /* only one daemon can run at a time */ 390 if ((pid = enter_daemon_lock()) == getpid()) { 391 detachfromtty(); 392 (void) cond_init(&cv, USYNC_THREAD, 0); 393 (void) mutex_init(&count_lock, USYNC_THREAD, 0); 394 if (thr_create(NULL, NULL, 395 (void *(*)(void *))instance_flush_thread, 396 NULL, THR_DETACHED, NULL) != 0) { 397 err_print(CANT_CREATE_THREAD, "daemon", 398 strerror(errno)); 399 devfsadm_exit(1); 400 } 401 402 /* start the minor_fini_thread */ 403 (void) mutex_init(&minor_fini_mutex, USYNC_THREAD, 0); 404 (void) cond_init(&minor_fini_cv, USYNC_THREAD, 0); 405 if (thr_create(NULL, NULL, 406 (void *(*)(void *))minor_fini_thread, 407 NULL, THR_DETACHED, NULL)) { 408 err_print(CANT_CREATE_THREAD, "minor_fini", 409 strerror(errno)); 410 devfsadm_exit(1); 411 } 412 413 414 /* 415 * No need for rcm notifications when running 416 * with an alternate root. So initialize rcm only 417 * when devfsadm is running with root dir "/". 418 * Similarly, logindevperms need only be set 419 * in daemon mode and when root dir is "/". 420 */ 421 if (root_dir[0] == '\0') { 422 (void) rcm_init(); 423 login_dev_enable = TRUE; 424 } 425 daemon_update(); 426 } else { 427 err_print(DAEMON_RUNNING, pid); 428 devfsadm_exit(1); 429 } 430 exit_daemon_lock(); 431 432 } else { 433 /* not a daemon, so just build /dev and /devices */ 434 process_devinfo_tree(); 435 if (devalloc_flag != 0) 436 /* Enable/disable device allocation */ 437 _reset_devalloc(devalloc_flag); 438 } 439 return (0); 440 } 441 442 static void 443 update_drvconf(major_t major) 444 { 445 if (modctl(MODLOADDRVCONF, major) != 0) 446 err_print(gettext("update_drvconf failed for major %d\n"), 447 major); 448 } 449 450 451 static void 452 load_dev_acl() 453 { 454 if (load_devpolicy() != 0) 455 err_print(gettext("device policy load failed\n")); 456 load_minor_perm_file(); 457 } 458 459 /* 460 * As devfsadm is run early in boot to provide the kernel with 461 * minor_perm info, we might as well check for reconfig at the 462 * same time to avoid running devfsadm twice. This gets invoked 463 * earlier than the env variable RECONFIG_BOOT is set up. 464 */ 465 static void 466 check_reconfig_state() 467 { 468 struct stat sb; 469 470 if (s_stat("/reconfigure", &sb) == 0) { 471 (void) modctl(MODDEVNAME, MODDEVNAME_RECONFIG, 0); 472 } 473 } 474 475 static void 476 modctl_sysavail() 477 { 478 /* 479 * Inform /dev that system is available, that 480 * implicit reconfig can now be performed. 481 */ 482 (void) modctl(MODDEVNAME, MODDEVNAME_SYSAVAIL, 0); 483 } 484 485 static void 486 set_lock_root(void) 487 { 488 struct stat sb; 489 char *lock_root; 490 size_t len; 491 492 lock_root = attr_root ? attr_root : root_dir; 493 494 len = strlen(lock_root) + strlen(ETCDEV) + 1; 495 etc_dev_dir = s_malloc(len); 496 (void) snprintf(etc_dev_dir, len, "%s%s", lock_root, ETCDEV); 497 498 if (s_stat(etc_dev_dir, &sb) != 0) { 499 s_mkdirp(etc_dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); 500 } else if (!S_ISDIR(sb.st_mode)) { 501 err_print(NOT_DIR, etc_dev_dir); 502 devfsadm_exit(1); 503 } 504 } 505 506 507 /* 508 * Parse arguments for all 6 programs handled from devfsadm. 509 */ 510 static void 511 parse_args(int argc, char *argv[]) 512 { 513 char opt; 514 char get_linkcompat_opts = FALSE; 515 char *compat_class; 516 int num_aliases = 0; 517 int len; 518 int retval; 519 int add_bind = FALSE; 520 struct aliases *ap = NULL; 521 struct aliases *a_head = NULL; 522 struct aliases *a_tail = NULL; 523 struct modconfig mc; 524 525 if (strcmp(prog, DISKS) == 0) { 526 compat_class = "disk"; 527 get_linkcompat_opts = TRUE; 528 529 } else if (strcmp(prog, TAPES) == 0) { 530 compat_class = "tape"; 531 get_linkcompat_opts = TRUE; 532 533 } else if (strcmp(prog, PORTS) == 0) { 534 compat_class = "port"; 535 get_linkcompat_opts = TRUE; 536 537 } else if (strcmp(prog, AUDLINKS) == 0) { 538 compat_class = "audio"; 539 get_linkcompat_opts = TRUE; 540 541 } else if (strcmp(prog, DEVLINKS) == 0) { 542 devlinktab_file = DEVLINKTAB_FILE; 543 544 build_devices = FALSE; 545 load_attach_drv = FALSE; 546 547 while ((opt = getopt(argc, argv, "dnr:st:vV:")) != EOF) { 548 switch (opt) { 549 case 'd': 550 file_mods = FALSE; 551 flush_path_to_inst_enable = FALSE; 552 devlinks_debug = TRUE; 553 break; 554 case 'n': 555 /* prevent driver loading and deferred attach */ 556 load_attach_drv = FALSE; 557 break; 558 case 'r': 559 set_root_devices_dev_dir(optarg); 560 if (zone_pathcheck(root_dir) != 561 DEVFSADM_SUCCESS) 562 devfsadm_exit(1); 563 break; 564 case 's': 565 /* 566 * suppress. don't create/remove links/nodes 567 * useful with -v or -V 568 */ 569 file_mods = FALSE; 570 flush_path_to_inst_enable = FALSE; 571 break; 572 case 't': 573 /* supply a non-default table file */ 574 devlinktab_file = optarg; 575 break; 576 case 'v': 577 /* documented verbose flag */ 578 add_verbose_id(VERBOSE_MID); 579 break; 580 case 'V': 581 /* undocumented for extra verbose levels */ 582 add_verbose_id(optarg); 583 break; 584 default: 585 usage(); 586 break; 587 } 588 } 589 590 if (optind < argc) { 591 usage(); 592 } 593 594 } else if (strcmp(prog, DRVCONFIG) == 0) { 595 build_dev = FALSE; 596 597 while ((opt = 598 getopt(argc, argv, "a:bdc:i:m:np:R:r:svV:")) != EOF) { 599 switch (opt) { 600 case 'a': 601 ap = calloc(sizeof (struct aliases), 1); 602 ap->a_name = dequote(optarg); 603 len = strlen(ap->a_name) + 1; 604 if (len > MAXMODCONFNAME) { 605 err_print(ALIAS_TOO_LONG, 606 MAXMODCONFNAME, ap->a_name); 607 devfsadm_exit(1); 608 } 609 ap->a_len = len; 610 if (a_tail == NULL) { 611 a_head = ap; 612 } else { 613 a_tail->a_next = ap; 614 } 615 a_tail = ap; 616 num_aliases++; 617 add_bind = TRUE; 618 break; 619 case 'b': 620 add_bind = TRUE; 621 break; 622 case 'c': 623 (void) strcpy(mc.drvclass, optarg); 624 break; 625 case 'd': 626 /* 627 * need to keep for compatibility, but 628 * do nothing. 629 */ 630 break; 631 case 'i': 632 single_drv = TRUE; 633 (void) strcpy(mc.drvname, optarg); 634 driver = s_strdup(optarg); 635 break; 636 case 'm': 637 mc.major = atoi(optarg); 638 break; 639 case 'n': 640 /* prevent driver loading and deferred attach */ 641 load_attach_drv = FALSE; 642 break; 643 case 'p': 644 /* specify alternate path_to_inst file */ 645 inst_file = s_strdup(optarg); 646 break; 647 case 'R': 648 /* 649 * Private flag for suninstall to populate 650 * device information on the installed root. 651 */ 652 root_dir = s_strdup(optarg); 653 if (zone_pathcheck(root_dir) != 654 DEVFSADM_SUCCESS) 655 devfsadm_exit(devfsadm_copy()); 656 break; 657 case 'r': 658 devices_dir = s_strdup(optarg); 659 if (zone_pathcheck(devices_dir) != 660 DEVFSADM_SUCCESS) 661 devfsadm_exit(1); 662 break; 663 case 's': 664 /* 665 * suppress. don't create nodes 666 * useful with -v or -V 667 */ 668 file_mods = FALSE; 669 flush_path_to_inst_enable = FALSE; 670 break; 671 case 'v': 672 /* documented verbose flag */ 673 add_verbose_id(VERBOSE_MID); 674 break; 675 case 'V': 676 /* undocumented for extra verbose levels */ 677 add_verbose_id(optarg); 678 break; 679 default: 680 usage(); 681 } 682 } 683 684 if (optind < argc) { 685 usage(); 686 } 687 688 if ((add_bind == TRUE) && (mc.major == -1 || 689 mc.drvname[0] == NULL)) { 690 err_print(MAJOR_AND_B_FLAG); 691 devfsadm_exit(1); 692 } 693 if (add_bind == TRUE) { 694 mc.num_aliases = num_aliases; 695 mc.ap = a_head; 696 retval = modctl(MODADDMAJBIND, NULL, (caddr_t)&mc); 697 if (retval < 0) { 698 err_print(MODCTL_ADDMAJBIND); 699 } 700 devfsadm_exit(retval); 701 } 702 703 } else if ((strcmp(prog, DEVFSADM) == 0) || 704 (strcmp(prog, DEVFSADMD) == 0)) { 705 char *zonename = NULL; 706 int init_drvconf = 0; 707 int init_perm = 0; 708 int public_mode = 0; 709 int init_sysavail = 0; 710 711 if (strcmp(prog, DEVFSADMD) == 0) { 712 daemon_mode = TRUE; 713 } 714 715 devlinktab_file = DEVLINKTAB_FILE; 716 717 while ((opt = getopt(argc, argv, 718 "a:Cc:deIi:l:mnp:PR:r:sSt:vV:x:")) != EOF) { 719 if (opt == 'I' || opt == 'P' || opt == 'S') { 720 if (public_mode) 721 usage(); 722 } else { 723 if (init_perm || init_drvconf || init_sysavail) 724 usage(); 725 public_mode = 1; 726 } 727 switch (opt) { 728 case 'a': 729 attr_root = s_strdup(optarg); 730 break; 731 case 'C': 732 cleanup = TRUE; 733 break; 734 case 'c': 735 num_classes++; 736 classes = s_realloc(classes, num_classes * 737 sizeof (char *)); 738 classes[num_classes - 1] = optarg; 739 break; 740 case 'd': 741 if (daemon_mode == FALSE) { 742 /* 743 * Device allocation to be disabled. 744 */ 745 devalloc_flag = DA_OFF; 746 build_dev = FALSE; 747 } 748 break; 749 case 'e': 750 if (daemon_mode == FALSE) { 751 /* 752 * Device allocation to be enabled. 753 */ 754 devalloc_flag = DA_ON; 755 build_dev = FALSE; 756 } 757 break; 758 case 'I': /* update kernel driver.conf cache */ 759 if (daemon_mode == TRUE) 760 usage(); 761 init_drvconf = 1; 762 break; 763 case 'i': 764 single_drv = TRUE; 765 driver = s_strdup(optarg); 766 break; 767 case 'l': 768 /* specify an alternate module load path */ 769 module_dirs = s_strdup(optarg); 770 break; 771 case 'm': 772 load_devname_nsmaps = TRUE; 773 break; 774 case 'n': 775 /* prevent driver loading and deferred attach */ 776 load_attach_drv = FALSE; 777 break; 778 case 'p': 779 /* specify alternate path_to_inst file */ 780 inst_file = s_strdup(optarg); 781 break; 782 case 'P': 783 if (daemon_mode == TRUE) 784 usage(); 785 /* load minor_perm and device_policy */ 786 init_perm = 1; 787 break; 788 case 'R': 789 /* 790 * Private flag for suninstall to populate 791 * device information on the installed root. 792 */ 793 root_dir = s_strdup(optarg); 794 devfsadm_exit(devfsadm_copy()); 795 break; 796 case 'r': 797 set_root_devices_dev_dir(optarg); 798 break; 799 case 's': 800 /* 801 * suppress. don't create/remove links/nodes 802 * useful with -v or -V 803 */ 804 file_mods = FALSE; 805 flush_path_to_inst_enable = FALSE; 806 break; 807 case 'S': 808 if (daemon_mode == TRUE) 809 usage(); 810 init_sysavail = 1; 811 break; 812 case 't': 813 devlinktab_file = optarg; 814 break; 815 case 'v': 816 /* documented verbose flag */ 817 add_verbose_id(VERBOSE_MID); 818 break; 819 case 'V': 820 /* undocumented: specify verbose lvl */ 821 add_verbose_id(optarg); 822 break; 823 case 'x': 824 /* 825 * x is the "private switch" option. The 826 * goal is to not suck up all the other 827 * option letters. 828 */ 829 if (strcmp(optarg, "update_devlinksdb") == 0) { 830 update_database = TRUE; 831 } else if (strcmp(optarg, "no_dev") == 0) { 832 /* don't build /dev */ 833 build_dev = FALSE; 834 } else if (strcmp(optarg, "no_devices") == 0) { 835 /* don't build /devices */ 836 build_devices = FALSE; 837 } else if (strcmp(optarg, "no_p2i") == 0) { 838 /* don't flush path_to_inst */ 839 flush_path_to_inst_enable = FALSE; 840 } else if (strcmp(optarg, "use_dicache") == 0) { 841 use_snapshot_cache = TRUE; 842 } else { 843 usage(); 844 } 845 break; 846 default: 847 usage(); 848 break; 849 } 850 } 851 if (optind < argc) { 852 usage(); 853 } 854 855 /* 856 * We're not in zone mode; Check to see if the rootpath 857 * collides with any zonepaths. 858 */ 859 if (zonename == NULL) { 860 if (zone_pathcheck(root_dir) != DEVFSADM_SUCCESS) 861 devfsadm_exit(1); 862 } 863 864 if (init_drvconf || init_perm || init_sysavail) { 865 /* 866 * Load minor perm before force-loading drivers 867 * so the correct permissions are picked up. 868 */ 869 if (init_perm) { 870 check_reconfig_state(); 871 load_dev_acl(); 872 } 873 if (init_drvconf) 874 update_drvconf((major_t)-1); 875 if (init_sysavail) 876 modctl_sysavail(); 877 devfsadm_exit(0); 878 /* NOTREACHED */ 879 } 880 881 if (load_devname_nsmaps == TRUE) { 882 devname_setup_nsmaps(); 883 devfsadm_exit(0); 884 } 885 } 886 887 888 if (get_linkcompat_opts == TRUE) { 889 890 build_devices = FALSE; 891 load_attach_drv = FALSE; 892 num_classes++; 893 classes = s_realloc(classes, num_classes * 894 sizeof (char *)); 895 classes[num_classes - 1] = compat_class; 896 897 while ((opt = getopt(argc, argv, "Cnr:svV:")) != EOF) { 898 switch (opt) { 899 case 'C': 900 cleanup = TRUE; 901 break; 902 case 'n': 903 /* prevent driver loading or deferred attach */ 904 load_attach_drv = FALSE; 905 break; 906 case 'r': 907 set_root_devices_dev_dir(optarg); 908 if (zone_pathcheck(root_dir) != 909 DEVFSADM_SUCCESS) 910 devfsadm_exit(1); 911 break; 912 case 's': 913 /* suppress. don't create/remove links/nodes */ 914 /* useful with -v or -V */ 915 file_mods = FALSE; 916 flush_path_to_inst_enable = FALSE; 917 break; 918 case 'v': 919 /* documented verbose flag */ 920 add_verbose_id(VERBOSE_MID); 921 break; 922 case 'V': 923 /* undocumented for extra verbose levels */ 924 add_verbose_id(optarg); 925 break; 926 default: 927 usage(); 928 } 929 } 930 if (optind < argc) { 931 usage(); 932 } 933 } 934 set_lock_root(); 935 } 936 937 void 938 usage(void) 939 { 940 if (strcmp(prog, DEVLINKS) == 0) { 941 err_print(DEVLINKS_USAGE); 942 } else if (strcmp(prog, DRVCONFIG) == 0) { 943 err_print(DRVCONFIG_USAGE); 944 } else if ((strcmp(prog, DEVFSADM) == 0) || 945 (strcmp(prog, DEVFSADMD) == 0)) { 946 err_print(DEVFSADM_USAGE); 947 } else { 948 err_print(COMPAT_LINK_USAGE); 949 } 950 951 devfsadm_exit(1); 952 } 953 954 static void 955 devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass) 956 { 957 char *msg, *name; 958 struct mlist mlist = {0}; 959 di_node_t node; 960 961 vprint(CHATTY_MID, "devi_tree_walk: root=%s, minor=%s, driver=%s," 962 " error=%d, flags=%u\n", dcip->dci_root, 963 dcip->dci_minor ? dcip->dci_minor : "<NULL>", 964 dcip->dci_driver ? dcip->dci_driver : "<NULL>", dcip->dci_error, 965 dcip->dci_flags); 966 967 assert(dcip->dci_root); 968 969 if (dcip->dci_flags & DCA_LOAD_DRV) { 970 node = di_init_driver(dcip->dci_driver, flags); 971 msg = DRIVER_FAILURE; 972 name = dcip->dci_driver; 973 } else { 974 node = di_init(dcip->dci_root, flags); 975 msg = DI_INIT_FAILED; 976 name = dcip->dci_root; 977 } 978 979 if (node == DI_NODE_NIL) { 980 dcip->dci_error = errno; 981 /* 982 * Rapid hotplugging (commonly seen during USB testing), 983 * may remove a device before the create event for it 984 * has been processed. To prevent alarming users with 985 * a superfluous message, we suppress error messages 986 * for ENXIO and hotplug. 987 */ 988 if (!(errno == ENXIO && (dcip->dci_flags & DCA_HOT_PLUG))) 989 err_print(msg, name, strerror(dcip->dci_error)); 990 return; 991 } 992 993 if (dcip->dci_flags & DCA_FLUSH_PATHINST) 994 flush_path_to_inst(); 995 996 dcip->dci_arg = &mlist; 997 998 vprint(CHATTY_MID, "walking device tree\n"); 999 1000 (void) di_walk_minor(node, NULL, DI_CHECK_ALIAS, dcip, 1001 check_minor_type); 1002 1003 process_deferred_links(dcip, DCA_CREATE_LINK); 1004 1005 dcip->dci_arg = NULL; 1006 1007 /* 1008 * Finished creating devfs files and dev links. 1009 * Log sysevent and notify RCM. 1010 */ 1011 if (ev_subclass) 1012 build_and_enq_event(EC_DEV_ADD, ev_subclass, dcip->dci_root, 1013 node, dcip->dci_minor); 1014 1015 if ((dcip->dci_flags & DCA_NOTIFY_RCM) && rcm_hdl) 1016 (void) notify_rcm(node, dcip->dci_minor); 1017 1018 /* Add new device to device allocation database */ 1019 if (system_labeled && update_devdb) { 1020 _update_devalloc_db(&devlist, 0, DA_ADD, NULL, root_dir); 1021 update_devdb = 0; 1022 } 1023 1024 di_fini(node); 1025 } 1026 1027 static void 1028 process_deferred_links(struct dca_impl *dcip, int flags) 1029 { 1030 struct mlist *dep; 1031 struct minor *mp, *smp; 1032 1033 vprint(CHATTY_MID, "processing deferred links\n"); 1034 1035 dep = dcip->dci_arg; 1036 1037 /* 1038 * The list head is not used during the deferred create phase 1039 */ 1040 dcip->dci_arg = NULL; 1041 1042 assert(dep); 1043 assert((dep->head == NULL) ^ (dep->tail != NULL)); 1044 assert(flags == DCA_FREE_LIST || flags == DCA_CREATE_LINK); 1045 1046 for (smp = NULL, mp = dep->head; mp; mp = mp->next) { 1047 if (flags == DCA_CREATE_LINK) 1048 (void) check_minor_type(mp->node, mp->minor, dcip); 1049 free(smp); 1050 smp = mp; 1051 } 1052 1053 free(smp); 1054 } 1055 1056 /* 1057 * Called in non-daemon mode to take a snap shot of the devinfo tree. 1058 * Then it calls the appropriate functions to build /devices and /dev. 1059 * It also flushes path_to_inst. 1060 * Except in the devfsadm -i (single driver case), the flags used by devfsadm 1061 * needs to match DI_CACHE_SNAPSHOT_FLAGS. That will make DINFOCACHE snapshot 1062 * updated. 1063 */ 1064 void 1065 process_devinfo_tree() 1066 { 1067 uint_t flags; 1068 struct dca_impl dci; 1069 char name[MAXNAMELEN]; 1070 char *fcn = "process_devinfo_tree: "; 1071 1072 vprint(CHATTY_MID, "%senter\n", fcn); 1073 1074 dca_impl_init("/", NULL, &dci); 1075 1076 lock_dev(); 1077 1078 /* 1079 * Update kernel driver.conf cache when devfsadm/drvconfig 1080 * is invoked to build /devices and /dev. 1081 */ 1082 if (load_attach_drv == TRUE) 1083 update_drvconf((major_t)-1); 1084 1085 if (single_drv == TRUE) { 1086 /* 1087 * load a single driver, but walk the entire devinfo tree 1088 */ 1089 if (load_attach_drv == FALSE) 1090 err_print(DRV_LOAD_REQD); 1091 1092 vprint(CHATTY_MID, "%sattaching driver (%s)\n", fcn, driver); 1093 1094 dci.dci_flags |= DCA_LOAD_DRV; 1095 (void) snprintf(name, sizeof (name), "%s", driver); 1096 dci.dci_driver = name; 1097 flags = DINFOCPYALL | DINFOPATH; 1098 1099 } else if (load_attach_drv == TRUE) { 1100 /* 1101 * Load and attach all drivers, then walk the entire tree. 1102 * If the cache flag is set, use DINFOCACHE to get cached 1103 * data. 1104 */ 1105 if (use_snapshot_cache == TRUE) { 1106 flags = DINFOCACHE; 1107 vprint(CHATTY_MID, "%susing snapshot cache\n", fcn); 1108 } else { 1109 vprint(CHATTY_MID, "%sattaching all drivers\n", fcn); 1110 flags = DI_CACHE_SNAPSHOT_FLAGS; 1111 if (cleanup) { 1112 /* 1113 * remove dangling entries from /etc/devices 1114 * files. 1115 */ 1116 flags |= DINFOCLEANUP; 1117 } 1118 } 1119 } else { 1120 /* 1121 * For devlinks, disks, ports, tapes and devfsadm -n, 1122 * just need to take a snapshot with active devices. 1123 */ 1124 vprint(CHATTY_MID, "%staking snapshot of active devices\n", 1125 fcn); 1126 flags = DINFOCPYALL; 1127 } 1128 1129 if (((load_attach_drv == TRUE) || (single_drv == TRUE)) && 1130 (build_devices == TRUE)) { 1131 dci.dci_flags |= DCA_FLUSH_PATHINST; 1132 } 1133 1134 /* handle pre-cleanup operations desired by the modules. */ 1135 pre_and_post_cleanup(RM_PRE); 1136 1137 devi_tree_walk(&dci, flags, NULL); 1138 1139 if (dci.dci_error) { 1140 devfsadm_exit(1); 1141 } 1142 1143 /* handle post-cleanup operations desired by the modules. */ 1144 pre_and_post_cleanup(RM_POST); 1145 1146 unlock_dev(SYNC_STATE); 1147 } 1148 1149 /*ARGSUSED*/ 1150 static void 1151 print_cache_signal(int signo) 1152 { 1153 if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) { 1154 err_print("signal SIGUSR1 failed: %s\n", strerror(errno)); 1155 devfsadm_exit(1); 1156 } 1157 } 1158 1159 static void 1160 revoke_lookup_door(void) 1161 { 1162 if (lookup_door_fd != -1) { 1163 if (door_revoke(lookup_door_fd) == -1) { 1164 err_print("door_revoke of %s failed - %s\n", 1165 lookup_door_path, strerror(errno)); 1166 } 1167 } 1168 } 1169 1170 /*ARGSUSED*/ 1171 static void 1172 catch_exit(int signo) 1173 { 1174 revoke_lookup_door(); 1175 } 1176 1177 /* 1178 * Register with eventd for messages. Create doors for synchronous 1179 * link creation. 1180 */ 1181 static void 1182 daemon_update(void) 1183 { 1184 int fd; 1185 char *fcn = "daemon_update: "; 1186 char door_file[MAXPATHLEN]; 1187 const char *subclass_list; 1188 sysevent_handle_t *sysevent_hp; 1189 vprint(CHATTY_MID, "%senter\n", fcn); 1190 1191 if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) { 1192 err_print("signal SIGUSR1 failed: %s\n", strerror(errno)); 1193 devfsadm_exit(1); 1194 } 1195 if (signal(SIGTERM, catch_exit) == SIG_ERR) { 1196 err_print("signal SIGTERM failed: %s\n", strerror(errno)); 1197 devfsadm_exit(1); 1198 } 1199 1200 if (snprintf(door_file, sizeof (door_file), 1201 "%s%s", attr_root ? attr_root : root_dir, DEVFSADM_SERVICE_DOOR) 1202 >= sizeof (door_file)) { 1203 err_print("update_daemon failed to open sysevent service " 1204 "door\n"); 1205 devfsadm_exit(1); 1206 } 1207 if ((sysevent_hp = sysevent_open_channel_alt( 1208 door_file)) == NULL) { 1209 err_print(CANT_CREATE_DOOR, 1210 door_file, strerror(errno)); 1211 devfsadm_exit(1); 1212 } 1213 if (sysevent_bind_subscriber(sysevent_hp, event_handler) != 0) { 1214 err_print(CANT_CREATE_DOOR, 1215 door_file, strerror(errno)); 1216 (void) sysevent_close_channel(sysevent_hp); 1217 devfsadm_exit(1); 1218 } 1219 subclass_list = EC_SUB_ALL; 1220 if (sysevent_register_event(sysevent_hp, EC_ALL, &subclass_list, 1) 1221 != 0) { 1222 err_print(CANT_CREATE_DOOR, 1223 door_file, strerror(errno)); 1224 (void) sysevent_unbind_subscriber(sysevent_hp); 1225 (void) sysevent_close_channel(sysevent_hp); 1226 devfsadm_exit(1); 1227 } 1228 if (snprintf(door_file, sizeof (door_file), "%s/%s", 1229 etc_dev_dir, DEVFSADM_SYNCH_DOOR) >= sizeof (door_file)) { 1230 err_print(CANT_CREATE_DOOR, DEVFSADM_SYNCH_DOOR, 1231 strerror(ENAMETOOLONG)); 1232 devfsadm_exit(1); 1233 } 1234 1235 (void) s_unlink(door_file); 1236 if ((fd = open(door_file, O_RDWR | O_CREAT, SYNCH_DOOR_PERMS)) == -1) { 1237 err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1238 devfsadm_exit(1); 1239 } 1240 (void) close(fd); 1241 1242 if ((fd = door_create(sync_handler, NULL, 1243 DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 1244 err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1245 (void) s_unlink(door_file); 1246 devfsadm_exit(1); 1247 } 1248 1249 if (fattach(fd, door_file) == -1) { 1250 err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1251 (void) s_unlink(door_file); 1252 devfsadm_exit(1); 1253 } 1254 1255 /* 1256 * devname_lookup_door 1257 */ 1258 if (snprintf(door_file, sizeof (door_file), "%s/%s", 1259 etc_dev_dir, DEVNAME_LOOKUP_DOOR) >= sizeof (door_file)) { 1260 err_print(CANT_CREATE_DOOR, DEVNAME_LOOKUP_DOOR, 1261 strerror(ENAMETOOLONG)); 1262 devfsadm_exit(1); 1263 } 1264 1265 (void) s_unlink(door_file); 1266 if ((fd = open(door_file, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR)) == -1) { 1267 err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1268 devfsadm_exit(1); 1269 } 1270 (void) close(fd); 1271 1272 if ((fd = door_create(devname_lookup_handler, NULL, 1273 DOOR_REFUSE_DESC)) == -1) { 1274 err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1275 (void) s_unlink(door_file); 1276 devfsadm_exit(1); 1277 } 1278 1279 (void) fdetach(door_file); 1280 lookup_door_path = s_strdup(door_file); 1281 retry: 1282 if (fattach(fd, door_file) == -1) { 1283 if (errno == EBUSY) 1284 goto retry; 1285 err_print(CANT_CREATE_DOOR, door_file, strerror(errno)); 1286 (void) s_unlink(door_file); 1287 devfsadm_exit(1); 1288 } 1289 lookup_door_fd = fd; 1290 1291 /* pass down the door name to kernel for door_ki_open */ 1292 if (devname_kcall(MODDEVNAME_LOOKUPDOOR, (void *)door_file) != 0) 1293 err_print(DEVNAME_CONTACT_FAILED, strerror(errno)); 1294 else 1295 devname_setup_nsmaps(); 1296 1297 vprint(CHATTY_MID, "%spausing\n", fcn); 1298 for (;;) { 1299 (void) pause(); 1300 } 1301 } 1302 1303 /*ARGSUSED*/ 1304 static void 1305 sync_handler(void *cookie, char *ap, size_t asize, 1306 door_desc_t *dp, uint_t ndesc) 1307 { 1308 door_cred_t dcred; 1309 struct dca_off *dcp, rdca; 1310 struct dca_impl dci; 1311 1312 /* 1313 * Must be root to make this call 1314 * If caller is not root, don't touch its data. 1315 */ 1316 if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) { 1317 dcp = ⤷ 1318 dcp->dca_error = EPERM; 1319 goto out; 1320 } 1321 1322 assert(ap); 1323 assert(asize == sizeof (*dcp)); 1324 1325 dcp = (void *)ap; 1326 1327 /* 1328 * Root is always present and is the first component of "name" member 1329 */ 1330 assert(dcp->dca_root == 0); 1331 1332 /* 1333 * The structure passed in by the door_client uses offsets 1334 * instead of pointers to work across address space boundaries. 1335 * Now copy the data into a structure (dca_impl) which uses 1336 * pointers. 1337 */ 1338 dci.dci_root = &dcp->dca_name[dcp->dca_root]; 1339 dci.dci_minor = dcp->dca_minor ? &dcp->dca_name[dcp->dca_minor] : NULL; 1340 dci.dci_driver = 1341 dcp->dca_driver ? &dcp->dca_name[dcp->dca_driver] : NULL; 1342 dci.dci_error = 0; 1343 dci.dci_flags = dcp->dca_flags | (dci.dci_driver ? DCA_LOAD_DRV : 0); 1344 dci.dci_arg = NULL; 1345 1346 lock_dev(); 1347 devi_tree_walk(&dci, DINFOCPYALL, NULL); 1348 dcp->dca_error = dci.dci_error; 1349 1350 if (dcp->dca_flags & DCA_DEVLINK_SYNC) 1351 unlock_dev(SYNC_STATE); 1352 else 1353 unlock_dev(CACHE_STATE); 1354 1355 out: (void) door_return((char *)dcp, sizeof (*dcp), NULL, 0); 1356 } 1357 1358 static void 1359 lock_dev(void) 1360 { 1361 vprint(CHATTY_MID, "lock_dev(): entered\n"); 1362 1363 if (build_dev == FALSE) 1364 return; 1365 1366 /* lockout other threads from /dev */ 1367 while (sema_wait(&dev_sema) != 0); 1368 1369 /* 1370 * Lock out other devfsadm processes from /dev. 1371 * If this wasn't the last process to run, 1372 * clear caches 1373 */ 1374 if (enter_dev_lock() != getpid()) { 1375 invalidate_enumerate_cache(); 1376 rm_all_links_from_cache(); 1377 (void) di_devlink_close(&devlink_cache, DI_LINK_ERROR); 1378 1379 /* send any sysevents that were queued up. */ 1380 process_syseventq(); 1381 } 1382 1383 /* 1384 * (re)load the reverse links database if not 1385 * already cached. 1386 */ 1387 if (devlink_cache == NULL) 1388 devlink_cache = di_devlink_open(root_dir, 0); 1389 1390 /* 1391 * If modules were unloaded, reload them. Also use module status 1392 * as an indication that we should check to see if other binding 1393 * files need to be reloaded. 1394 */ 1395 if (module_head == NULL) { 1396 load_modules(); 1397 read_minor_perm_file(); 1398 read_driver_aliases_file(); 1399 read_devlinktab_file(); 1400 read_logindevperm_file(); 1401 read_enumerate_file(); 1402 } 1403 1404 if (module_head != NULL) 1405 return; 1406 1407 if (strcmp(prog, DEVLINKS) == 0) { 1408 if (devlinktab_list == NULL) { 1409 err_print(NO_LINKTAB, devlinktab_file); 1410 err_print(NO_MODULES, module_dirs); 1411 err_print(ABORTING); 1412 devfsadm_exit(1); 1413 } 1414 } else { 1415 err_print(NO_MODULES, module_dirs); 1416 if (strcmp(prog, DEVFSADM) == 0) { 1417 err_print(MODIFY_PATH); 1418 } 1419 } 1420 } 1421 1422 /* 1423 * Unlock the device. If we are processing a CACHE_STATE call, we signal a 1424 * minor_fini_thread delayed SYNC_STATE at the end of the call. If we are 1425 * processing a SYNC_STATE call, we cancel any minor_fini_thread SYNC_STATE 1426 * at both the start and end of the call since we will be doing the SYNC_STATE. 1427 */ 1428 static void 1429 unlock_dev(int flag) 1430 { 1431 assert(flag == SYNC_STATE || flag == CACHE_STATE); 1432 1433 vprint(CHATTY_MID, "unlock_dev(): entered\n"); 1434 1435 /* If we are starting a SYNC_STATE, cancel minor_fini_thread SYNC */ 1436 if (flag == SYNC_STATE) { 1437 (void) mutex_lock(&minor_fini_mutex); 1438 minor_fini_canceled = TRUE; 1439 minor_fini_delayed = FALSE; 1440 (void) mutex_unlock(&minor_fini_mutex); 1441 } 1442 1443 if (build_dev == FALSE) 1444 return; 1445 1446 if (devlink_cache == NULL) { 1447 err_print(NO_DEVLINK_CACHE); 1448 } 1449 assert(devlink_cache); 1450 1451 if (flag == SYNC_STATE) { 1452 unload_modules(); 1453 if (update_database) 1454 (void) di_devlink_update(devlink_cache); 1455 (void) di_devlink_close(&devlink_cache, 0); 1456 1457 /* 1458 * now that the devlinks db cache has been flushed, it is safe 1459 * to send any sysevents that were queued up. 1460 */ 1461 process_syseventq(); 1462 } 1463 1464 exit_dev_lock(); 1465 1466 (void) mutex_lock(&minor_fini_mutex); 1467 if (flag == SYNC_STATE) { 1468 /* We did a SYNC_STATE, cancel minor_fini_thread SYNC */ 1469 minor_fini_canceled = TRUE; 1470 minor_fini_delayed = FALSE; 1471 } else { 1472 /* We did a CACHE_STATE, start delayed minor_fini_thread SYNC */ 1473 minor_fini_canceled = FALSE; 1474 minor_fini_delayed = TRUE; 1475 (void) cond_signal(&minor_fini_cv); 1476 } 1477 (void) mutex_unlock(&minor_fini_mutex); 1478 1479 (void) sema_post(&dev_sema); 1480 } 1481 1482 /* 1483 * Check that if -r is set, it is not any part of a zone--- that is, that 1484 * the zonepath is not a substring of the root path. 1485 */ 1486 static int 1487 zone_pathcheck(char *checkpath) 1488 { 1489 void *dlhdl = NULL; 1490 char *name; 1491 char root[MAXPATHLEN]; /* resolved devfsadm root path */ 1492 char zroot[MAXPATHLEN]; /* zone root path */ 1493 char rzroot[MAXPATHLEN]; /* resolved zone root path */ 1494 char tmp[MAXPATHLEN]; 1495 FILE *cookie; 1496 int err = DEVFSADM_SUCCESS; 1497 1498 if (checkpath[0] == '\0') 1499 return (DEVFSADM_SUCCESS); 1500 1501 /* 1502 * Check if zones is available on this system. 1503 */ 1504 if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) { 1505 return (DEVFSADM_SUCCESS); 1506 } 1507 1508 bzero(root, sizeof (root)); 1509 if (resolvepath(checkpath, root, sizeof (root) - 1) == -1) { 1510 /* 1511 * In this case the user has done "devfsadm -r" on some path 1512 * which does not yet exist, or we got some other misc. error. 1513 * We punt and don't resolve the path in this case. 1514 */ 1515 (void) strlcpy(root, checkpath, sizeof (root)); 1516 } 1517 1518 if (strlen(root) > 0 && (root[strlen(root) - 1] != '/')) { 1519 (void) snprintf(tmp, sizeof (tmp), "%s/", root); 1520 (void) strlcpy(root, tmp, sizeof (root)); 1521 } 1522 1523 cookie = setzoneent(); 1524 while ((name = getzoneent(cookie)) != NULL) { 1525 /* Skip the global zone */ 1526 if (strcmp(name, GLOBAL_ZONENAME) == 0) { 1527 free(name); 1528 continue; 1529 } 1530 1531 if (zone_get_zonepath(name, zroot, sizeof (zroot)) != Z_OK) { 1532 free(name); 1533 continue; 1534 } 1535 1536 bzero(rzroot, sizeof (rzroot)); 1537 if (resolvepath(zroot, rzroot, sizeof (rzroot) - 1) == -1) { 1538 /* 1539 * Zone path doesn't exist, or other misc error, 1540 * so we try using the non-resolved pathname. 1541 */ 1542 (void) strlcpy(rzroot, zroot, sizeof (rzroot)); 1543 } 1544 if (strlen(rzroot) > 0 && (rzroot[strlen(rzroot) - 1] != '/')) { 1545 (void) snprintf(tmp, sizeof (tmp), "%s/", rzroot); 1546 (void) strlcpy(rzroot, tmp, sizeof (rzroot)); 1547 } 1548 1549 /* 1550 * Finally, the comparison. If the zone root path is a 1551 * leading substring of the root path, fail. 1552 */ 1553 if (strncmp(rzroot, root, strlen(rzroot)) == 0) { 1554 err_print(ZONE_PATHCHECK, root, name); 1555 err = DEVFSADM_FAILURE; 1556 free(name); 1557 break; 1558 } 1559 free(name); 1560 } 1561 endzoneent(cookie); 1562 (void) dlclose(dlhdl); 1563 return (err); 1564 } 1565 1566 /* 1567 * Called by the daemon when it receives an event from the devfsadm SLM 1568 * to syseventd. 1569 * 1570 * The devfsadm SLM uses a private event channel for communication to 1571 * devfsadmd set-up via private libsysevent interfaces. This handler is 1572 * used to bind to the devfsadmd channel for event delivery. 1573 * The devfsadmd SLM insures single calls to this routine as well as 1574 * synchronized event delivery. 1575 * 1576 */ 1577 static void 1578 event_handler(sysevent_t *ev) 1579 { 1580 char *path; 1581 char *minor; 1582 char *subclass; 1583 char *dev_ev_subclass; 1584 char *driver_name; 1585 nvlist_t *attr_list = NULL; 1586 int err = 0; 1587 int instance; 1588 int branch_event = 0; 1589 1590 subclass = sysevent_get_subclass_name(ev); 1591 vprint(EVENT_MID, "event_handler: %s id:0X%llx\n", 1592 subclass, sysevent_get_seq(ev)); 1593 1594 if (strcmp(subclass, ESC_DEVFS_START) == 0) { 1595 return; 1596 } 1597 1598 /* Check if event is an instance modification */ 1599 if (strcmp(subclass, ESC_DEVFS_INSTANCE_MOD) == 0) { 1600 devfs_instance_mod(); 1601 return; 1602 } 1603 if (sysevent_get_attr_list(ev, &attr_list) != 0) { 1604 vprint(EVENT_MID, "event_handler: can not get attr list\n"); 1605 return; 1606 } 1607 1608 if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0 || 1609 strcmp(subclass, ESC_DEVFS_DEVI_REMOVE) == 0 || 1610 strcmp(subclass, ESC_DEVFS_MINOR_CREATE) == 0 || 1611 strcmp(subclass, ESC_DEVFS_MINOR_REMOVE) == 0) { 1612 if ((err = nvlist_lookup_string(attr_list, DEVFS_PATHNAME, 1613 &path)) != 0) 1614 goto out; 1615 1616 if (nvlist_lookup_string(attr_list, DEVFS_DEVI_CLASS, 1617 &dev_ev_subclass) != 0) 1618 dev_ev_subclass = NULL; 1619 1620 if (nvlist_lookup_string(attr_list, DEVFS_DRIVER_NAME, 1621 &driver_name) != 0) 1622 driver_name = NULL; 1623 1624 if (nvlist_lookup_int32(attr_list, DEVFS_INSTANCE, 1625 &instance) != 0) 1626 instance = -1; 1627 1628 if (nvlist_lookup_int32(attr_list, DEVFS_BRANCH_EVENT, 1629 &branch_event) != 0) 1630 branch_event = 0; 1631 1632 if (nvlist_lookup_string(attr_list, DEVFS_MINOR_NAME, 1633 &minor) != 0) 1634 minor = NULL; 1635 1636 lock_dev(); 1637 1638 if (strcmp(ESC_DEVFS_DEVI_ADD, subclass) == 0) { 1639 add_minor_pathname(path, NULL, dev_ev_subclass); 1640 if (branch_event) { 1641 build_and_enq_event(EC_DEV_BRANCH, 1642 ESC_DEV_BRANCH_ADD, path, DI_NODE_NIL, 1643 NULL); 1644 } 1645 1646 } else if (strcmp(ESC_DEVFS_MINOR_CREATE, subclass) == 0) { 1647 add_minor_pathname(path, minor, dev_ev_subclass); 1648 1649 } else if (strcmp(ESC_DEVFS_MINOR_REMOVE, subclass) == 0) { 1650 hot_cleanup(path, minor, dev_ev_subclass, driver_name, 1651 instance); 1652 1653 } else { /* ESC_DEVFS_DEVI_REMOVE */ 1654 hot_cleanup(path, NULL, dev_ev_subclass, 1655 driver_name, instance); 1656 if (branch_event) { 1657 build_and_enq_event(EC_DEV_BRANCH, 1658 ESC_DEV_BRANCH_REMOVE, path, DI_NODE_NIL, 1659 NULL); 1660 } 1661 } 1662 1663 unlock_dev(CACHE_STATE); 1664 1665 } else if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0 || 1666 strcmp(subclass, ESC_DEVFS_BRANCH_REMOVE) == 0) { 1667 if ((err = nvlist_lookup_string(attr_list, 1668 DEVFS_PATHNAME, &path)) != 0) 1669 goto out; 1670 1671 /* just log ESC_DEV_BRANCH... event */ 1672 if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0) 1673 dev_ev_subclass = ESC_DEV_BRANCH_ADD; 1674 else 1675 dev_ev_subclass = ESC_DEV_BRANCH_REMOVE; 1676 1677 lock_dev(); 1678 build_and_enq_event(EC_DEV_BRANCH, dev_ev_subclass, path, 1679 DI_NODE_NIL, NULL); 1680 unlock_dev(CACHE_STATE); 1681 } else 1682 err_print(UNKNOWN_EVENT, subclass); 1683 1684 out: 1685 if (err) 1686 err_print(EVENT_ATTR_LOOKUP_FAILED, strerror(err)); 1687 nvlist_free(attr_list); 1688 } 1689 1690 static void 1691 dca_impl_init(char *root, char *minor, struct dca_impl *dcip) 1692 { 1693 assert(root); 1694 1695 dcip->dci_root = root; 1696 dcip->dci_minor = minor; 1697 dcip->dci_driver = NULL; 1698 dcip->dci_error = 0; 1699 dcip->dci_flags = 0; 1700 dcip->dci_arg = NULL; 1701 } 1702 1703 /* 1704 * Kernel logs a message when a devinfo node is attached. Try to create 1705 * /dev and /devices for each minor node. minorname can be NULL. 1706 */ 1707 void 1708 add_minor_pathname(char *node, char *minor, char *ev_subclass) 1709 { 1710 struct dca_impl dci; 1711 1712 vprint(CHATTY_MID, "add_minor_pathname: node_path=%s minor=%s\n", 1713 node, minor ? minor : "NULL"); 1714 1715 dca_impl_init(node, minor, &dci); 1716 1717 /* 1718 * Restrict hotplug link creation if daemon 1719 * started with -i option. 1720 */ 1721 if (single_drv == TRUE) { 1722 dci.dci_driver = driver; 1723 } 1724 1725 /* 1726 * We are being invoked in response to a hotplug 1727 * event. Also, notify RCM if nodetype indicates 1728 * a network device has been hotplugged. 1729 */ 1730 dci.dci_flags = DCA_HOT_PLUG | DCA_CHECK_TYPE; 1731 1732 devi_tree_walk(&dci, DINFOPROP|DINFOMINOR, ev_subclass); 1733 } 1734 1735 static di_node_t 1736 find_clone_node() 1737 { 1738 static di_node_t clone_node = DI_NODE_NIL; 1739 1740 if (clone_node == DI_NODE_NIL) 1741 clone_node = di_init("/pseudo/clone@0", DINFOPROP); 1742 return (clone_node); 1743 } 1744 1745 static int 1746 is_descendent_of(di_node_t node, char *driver) 1747 { 1748 while (node != DI_NODE_NIL) { 1749 char *drv = di_driver_name(node); 1750 if (strcmp(drv, driver) == 0) 1751 return (1); 1752 node = di_parent_node(node); 1753 } 1754 return (0); 1755 } 1756 1757 /* 1758 * Checks the minor type. If it is an alias node, then lookup 1759 * the real node/minor first, then call minor_process() to 1760 * do the real work. 1761 */ 1762 static int 1763 check_minor_type(di_node_t node, di_minor_t minor, void *arg) 1764 { 1765 ddi_minor_type minor_type; 1766 di_node_t clone_node; 1767 char *mn; 1768 char *nt; 1769 struct mlist *dep; 1770 struct dca_impl *dcip = arg; 1771 1772 assert(dcip); 1773 1774 dep = dcip->dci_arg; 1775 1776 mn = di_minor_name(minor); 1777 1778 /* 1779 * We match driver here instead of in minor_process 1780 * as we want the actual driver name. This check is 1781 * unnecessary during deferred processing. 1782 */ 1783 if (dep && 1784 ((dcip->dci_driver && !is_descendent_of(node, dcip->dci_driver)) || 1785 (dcip->dci_minor && strcmp(mn, dcip->dci_minor)))) { 1786 return (DI_WALK_CONTINUE); 1787 } 1788 1789 if ((dcip->dci_flags & DCA_CHECK_TYPE) && 1790 (nt = di_minor_nodetype(minor)) && 1791 (strcmp(nt, DDI_NT_NET) == 0)) { 1792 dcip->dci_flags |= DCA_NOTIFY_RCM; 1793 dcip->dci_flags &= ~DCA_CHECK_TYPE; 1794 } 1795 1796 minor_type = di_minor_type(minor); 1797 1798 if (minor_type == DDM_MINOR) { 1799 minor_process(node, minor, dep); 1800 1801 } else if (minor_type == DDM_ALIAS) { 1802 struct mlist *cdep, clone_del = {0}; 1803 1804 clone_node = find_clone_node(); 1805 if (clone_node == DI_NODE_NIL) { 1806 err_print(DI_INIT_FAILED, "clone", strerror(errno)); 1807 return (DI_WALK_CONTINUE); 1808 } 1809 1810 cdep = dep ? &clone_del : NULL; 1811 1812 minor_process(clone_node, minor, cdep); 1813 1814 /* 1815 * cache "alias" minor node and free "clone" minor 1816 */ 1817 if (cdep != NULL && cdep->head != NULL) { 1818 assert(cdep->tail != NULL); 1819 cache_deferred_minor(dep, node, minor); 1820 dcip->dci_arg = cdep; 1821 process_deferred_links(dcip, DCA_FREE_LIST); 1822 dcip->dci_arg = dep; 1823 } 1824 } 1825 1826 return (DI_WALK_CONTINUE); 1827 } 1828 1829 1830 /* 1831 * This is the entry point for each minor node, whether walking 1832 * the entire tree via di_walk_minor() or processing a hotplug event 1833 * for a single devinfo node (via hotplug ndi_devi_online()). 1834 */ 1835 /*ARGSUSED*/ 1836 static void 1837 minor_process(di_node_t node, di_minor_t minor, struct mlist *dep) 1838 { 1839 create_list_t *create; 1840 int defer; 1841 1842 vprint(CHATTY_MID, "minor_process: node=%s, minor=%s\n", 1843 di_node_name(node), di_minor_name(minor)); 1844 1845 if (dep != NULL) { 1846 1847 /* 1848 * Reset /devices node to minor_perm perm/ownership 1849 * if we are here to deactivate device allocation 1850 */ 1851 if (build_devices == TRUE) { 1852 reset_node_permissions(node, minor); 1853 } 1854 1855 if (build_dev == FALSE) { 1856 return; 1857 } 1858 1859 /* 1860 * This function will create any nodes for /etc/devlink.tab. 1861 * If devlink.tab handles link creation, we don't call any 1862 * devfsadm modules since that could cause duplicate caching 1863 * in the enumerate functions if different re strings are 1864 * passed that are logically identical. I'm still not 1865 * convinced this would cause any harm, but better to be safe. 1866 * 1867 * Deferred processing is available only for devlinks 1868 * created through devfsadm modules. 1869 */ 1870 if (process_devlink_compat(minor, node) == TRUE) { 1871 return; 1872 } 1873 } else { 1874 vprint(CHATTY_MID, "minor_process: deferred processing\n"); 1875 } 1876 1877 /* 1878 * look for relevant link create rules in the modules, and 1879 * invoke the link create callback function to build a link 1880 * if there is a match. 1881 */ 1882 defer = 0; 1883 for (create = create_head; create != NULL; create = create->next) { 1884 if ((minor_matches_rule(node, minor, create) == TRUE) && 1885 class_ok(create->create->device_class) == 1886 DEVFSADM_SUCCESS) { 1887 if (call_minor_init(create->modptr) == 1888 DEVFSADM_FAILURE) { 1889 continue; 1890 } 1891 1892 /* 1893 * If NOT doing the deferred creates (i.e. 1st pass) and 1894 * rule requests deferred processing cache the minor 1895 * data. 1896 * 1897 * If deferred processing (2nd pass), create links 1898 * ONLY if rule requests deferred processing. 1899 */ 1900 if (dep && ((create->create->flags & CREATE_MASK) == 1901 CREATE_DEFER)) { 1902 defer = 1; 1903 continue; 1904 } else if (dep == NULL && 1905 ((create->create->flags & CREATE_MASK) != 1906 CREATE_DEFER)) { 1907 continue; 1908 } 1909 1910 if ((*(create->create->callback_fcn)) 1911 (minor, node) == DEVFSADM_TERMINATE) { 1912 break; 1913 } 1914 } 1915 } 1916 1917 if (defer) 1918 cache_deferred_minor(dep, node, minor); 1919 } 1920 1921 1922 /* 1923 * Cache node and minor in defer list. 1924 */ 1925 static void 1926 cache_deferred_minor( 1927 struct mlist *dep, 1928 di_node_t node, 1929 di_minor_t minor) 1930 { 1931 struct minor *mp; 1932 const char *fcn = "cache_deferred_minor"; 1933 1934 vprint(CHATTY_MID, "%s node=%s, minor=%s\n", fcn, 1935 di_node_name(node), di_minor_name(minor)); 1936 1937 if (dep == NULL) { 1938 vprint(CHATTY_MID, "%s: cannot cache during " 1939 "deferred processing. Ignoring minor\n", fcn); 1940 return; 1941 } 1942 1943 mp = (struct minor *)s_zalloc(sizeof (struct minor)); 1944 mp->node = node; 1945 mp->minor = minor; 1946 mp->next = NULL; 1947 1948 assert(dep->head == NULL || dep->tail != NULL); 1949 if (dep->head == NULL) { 1950 dep->head = mp; 1951 } else { 1952 dep->tail->next = mp; 1953 } 1954 dep->tail = mp; 1955 } 1956 1957 /* 1958 * Check to see if "create" link creation rule matches this node/minor. 1959 * If it does, return TRUE. 1960 */ 1961 static int 1962 minor_matches_rule(di_node_t node, di_minor_t minor, create_list_t *create) 1963 { 1964 char *m_nodetype, *m_drvname; 1965 1966 if (create->create->node_type != NULL) { 1967 1968 m_nodetype = di_minor_nodetype(minor); 1969 assert(m_nodetype != NULL); 1970 1971 switch (create->create->flags & TYPE_MASK) { 1972 case TYPE_EXACT: 1973 if (strcmp(create->create->node_type, m_nodetype) != 1974 0) { 1975 return (FALSE); 1976 } 1977 break; 1978 case TYPE_PARTIAL: 1979 if (strncmp(create->create->node_type, m_nodetype, 1980 strlen(create->create->node_type)) != 0) { 1981 return (FALSE); 1982 } 1983 break; 1984 case TYPE_RE: 1985 if (regexec(&(create->node_type_comp), m_nodetype, 1986 0, NULL, 0) != 0) { 1987 return (FALSE); 1988 } 1989 break; 1990 } 1991 } 1992 1993 if (create->create->drv_name != NULL) { 1994 m_drvname = di_driver_name(node); 1995 switch (create->create->flags & DRV_MASK) { 1996 case DRV_EXACT: 1997 if (strcmp(create->create->drv_name, m_drvname) != 0) { 1998 return (FALSE); 1999 } 2000 break; 2001 case DRV_RE: 2002 if (regexec(&(create->drv_name_comp), m_drvname, 2003 0, NULL, 0) != 0) { 2004 return (FALSE); 2005 } 2006 break; 2007 } 2008 } 2009 2010 return (TRUE); 2011 } 2012 2013 /* 2014 * If no classes were given on the command line, then return DEVFSADM_SUCCESS. 2015 * Otherwise, return DEVFSADM_SUCCESS if the device "class" from the module 2016 * matches one of the device classes given on the command line, 2017 * otherwise, return DEVFSADM_FAILURE. 2018 */ 2019 static int 2020 class_ok(char *class) 2021 { 2022 int i; 2023 2024 if (num_classes == 0) { 2025 return (DEVFSADM_SUCCESS); 2026 } 2027 2028 for (i = 0; i < num_classes; i++) { 2029 if (strcmp(class, classes[i]) == 0) { 2030 return (DEVFSADM_SUCCESS); 2031 } 2032 } 2033 return (DEVFSADM_FAILURE); 2034 } 2035 2036 /* 2037 * call minor_fini on active modules, then unload ALL modules 2038 */ 2039 static void 2040 unload_modules(void) 2041 { 2042 module_t *module_free; 2043 create_list_t *create_free; 2044 remove_list_t *remove_free; 2045 2046 while (create_head != NULL) { 2047 create_free = create_head; 2048 create_head = create_head->next; 2049 2050 if ((create_free->create->flags & TYPE_RE) == TYPE_RE) { 2051 regfree(&(create_free->node_type_comp)); 2052 } 2053 if ((create_free->create->flags & DRV_RE) == DRV_RE) { 2054 regfree(&(create_free->drv_name_comp)); 2055 } 2056 free(create_free); 2057 } 2058 2059 while (remove_head != NULL) { 2060 remove_free = remove_head; 2061 remove_head = remove_head->next; 2062 free(remove_free); 2063 } 2064 2065 while (module_head != NULL) { 2066 2067 if ((module_head->minor_fini != NULL) && 2068 ((module_head->flags & MODULE_ACTIVE) == MODULE_ACTIVE)) { 2069 (void) (*(module_head->minor_fini))(); 2070 } 2071 2072 vprint(MODLOAD_MID, "unloading module %s\n", module_head->name); 2073 free(module_head->name); 2074 (void) dlclose(module_head->dlhandle); 2075 2076 module_free = module_head; 2077 module_head = module_head->next; 2078 free(module_free); 2079 } 2080 } 2081 2082 /* 2083 * Load devfsadm logical link processing modules. 2084 */ 2085 static void 2086 load_modules(void) 2087 { 2088 DIR *mod_dir; 2089 struct dirent *entp; 2090 char cdir[PATH_MAX + 1]; 2091 char *last; 2092 char *mdir = module_dirs; 2093 char *fcn = "load_modules: "; 2094 2095 while (*mdir != '\0') { 2096 2097 while (*mdir == ':') { 2098 mdir++; 2099 } 2100 2101 if (*mdir == '\0') { 2102 continue; 2103 } 2104 2105 last = strchr(mdir, ':'); 2106 2107 if (last == NULL) { 2108 last = mdir + strlen(mdir); 2109 } 2110 2111 (void) strncpy(cdir, mdir, last - mdir); 2112 cdir[last - mdir] = '\0'; 2113 mdir += strlen(cdir); 2114 2115 if ((mod_dir = opendir(cdir)) == NULL) { 2116 vprint(MODLOAD_MID, "%sopendir(%s): %s\n", 2117 fcn, cdir, strerror(errno)); 2118 continue; 2119 } 2120 2121 while ((entp = readdir(mod_dir)) != NULL) { 2122 2123 if ((strcmp(entp->d_name, ".") == 0) || 2124 (strcmp(entp->d_name, "..") == 0)) { 2125 continue; 2126 } 2127 2128 load_module(entp->d_name, cdir); 2129 } 2130 s_closedir(mod_dir); 2131 } 2132 } 2133 2134 static void 2135 load_module(char *mname, char *cdir) 2136 { 2137 _devfsadm_create_reg_t *create_reg; 2138 _devfsadm_remove_reg_V1_t *remove_reg; 2139 create_list_t *create_list_element; 2140 create_list_t **create_list_next; 2141 remove_list_t *remove_list_element; 2142 remove_list_t **remove_list_next; 2143 char epath[PATH_MAX + 1], *end; 2144 char *fcn = "load_module: "; 2145 char *dlerrstr; 2146 void *dlhandle; 2147 module_t *module; 2148 int flags; 2149 int n; 2150 int i; 2151 2152 /* ignore any file which does not end in '.so' */ 2153 if ((end = strstr(mname, MODULE_SUFFIX)) != NULL) { 2154 if (end[strlen(MODULE_SUFFIX)] != '\0') { 2155 return; 2156 } 2157 } else { 2158 return; 2159 } 2160 2161 (void) snprintf(epath, sizeof (epath), "%s/%s", cdir, mname); 2162 2163 if ((dlhandle = dlopen(epath, RTLD_LAZY)) == NULL) { 2164 dlerrstr = dlerror(); 2165 err_print(DLOPEN_FAILED, epath, 2166 dlerrstr ? dlerrstr : "unknown error"); 2167 return; 2168 } 2169 2170 /* dlsym the _devfsadm_create_reg structure */ 2171 if (NULL == (create_reg = (_devfsadm_create_reg_t *) 2172 dlsym(dlhandle, _DEVFSADM_CREATE_REG))) { 2173 vprint(MODLOAD_MID, "dlsym(%s, %s): symbol not found\n", epath, 2174 _DEVFSADM_CREATE_REG); 2175 } else { 2176 vprint(MODLOAD_MID, "%sdlsym(%s, %s) succeeded\n", 2177 fcn, epath, _DEVFSADM_CREATE_REG); 2178 } 2179 2180 /* dlsym the _devfsadm_remove_reg structure */ 2181 if (NULL == (remove_reg = (_devfsadm_remove_reg_V1_t *) 2182 dlsym(dlhandle, _DEVFSADM_REMOVE_REG))) { 2183 vprint(MODLOAD_MID, "dlsym(%s,\n\t%s): symbol not found\n", 2184 epath, _DEVFSADM_REMOVE_REG); 2185 } else { 2186 vprint(MODLOAD_MID, "dlsym(%s, %s): succeeded\n", 2187 epath, _DEVFSADM_REMOVE_REG); 2188 } 2189 2190 vprint(MODLOAD_MID, "module %s loaded\n", epath); 2191 2192 module = (module_t *)s_malloc(sizeof (module_t)); 2193 module->name = s_strdup(epath); 2194 module->dlhandle = dlhandle; 2195 2196 /* dlsym other module functions, to be called later */ 2197 module->minor_fini = (int (*)())dlsym(dlhandle, MINOR_FINI); 2198 module->minor_init = (int (*)())dlsym(dlhandle, MINOR_INIT); 2199 module->flags = 0; 2200 2201 /* 2202 * put a ptr to each struct devfsadm_create on "create_head" 2203 * list sorted in interpose_lvl. 2204 */ 2205 if (create_reg != NULL) { 2206 for (i = 0; i < create_reg->count; i++) { 2207 int flags = create_reg->tblp[i].flags; 2208 2209 create_list_element = (create_list_t *) 2210 s_malloc(sizeof (create_list_t)); 2211 2212 create_list_element->create = &(create_reg->tblp[i]); 2213 create_list_element->modptr = module; 2214 2215 if (((flags & CREATE_MASK) != 0) && 2216 ((flags & CREATE_MASK) != CREATE_DEFER)) { 2217 free(create_list_element); 2218 err_print("illegal flag combination in " 2219 "module create\n"); 2220 err_print(IGNORING_ENTRY, i, epath); 2221 continue; 2222 } 2223 2224 if (((flags & TYPE_MASK) == 0) ^ 2225 (create_reg->tblp[i].node_type == NULL)) { 2226 free(create_list_element); 2227 err_print("flags value incompatible with " 2228 "node_type value in module create\n"); 2229 err_print(IGNORING_ENTRY, i, epath); 2230 continue; 2231 } 2232 2233 if (((flags & TYPE_MASK) != 0) && 2234 ((flags & TYPE_MASK) != TYPE_EXACT) && 2235 ((flags & TYPE_MASK) != TYPE_RE) && 2236 ((flags & TYPE_MASK) != TYPE_PARTIAL)) { 2237 free(create_list_element); 2238 err_print("illegal TYPE_* flag combination in " 2239 "module create\n"); 2240 err_print(IGNORING_ENTRY, i, epath); 2241 continue; 2242 } 2243 2244 /* precompile regular expression for efficiency */ 2245 if ((flags & TYPE_RE) == TYPE_RE) { 2246 if ((n = regcomp(&(create_list_element-> 2247 node_type_comp), 2248 create_reg->tblp[i].node_type, 2249 REG_EXTENDED)) != 0) { 2250 free(create_list_element); 2251 err_print(REGCOMP_FAILED, 2252 create_reg->tblp[i].node_type, 2253 n); 2254 err_print(IGNORING_ENTRY, i, epath); 2255 continue; 2256 } 2257 } 2258 2259 if (((flags & DRV_MASK) == 0) ^ 2260 (create_reg->tblp[i].drv_name == NULL)) { 2261 if ((flags & TYPE_RE) == TYPE_RE) { 2262 regfree(&(create_list_element-> 2263 node_type_comp)); 2264 } 2265 free(create_list_element); 2266 err_print("flags value incompatible with " 2267 "drv_name value in module create\n"); 2268 err_print(IGNORING_ENTRY, i, epath); 2269 continue; 2270 } 2271 2272 if (((flags & DRV_MASK) != 0) && 2273 ((flags & DRV_MASK) != DRV_EXACT) && 2274 ((flags & DRV_MASK) != DRV_RE)) { 2275 if ((flags & TYPE_RE) == TYPE_RE) { 2276 regfree(&(create_list_element-> 2277 node_type_comp)); 2278 } 2279 free(create_list_element); 2280 err_print("illegal DRV_* flag combination in " 2281 "module create\n"); 2282 err_print(IGNORING_ENTRY, i, epath); 2283 continue; 2284 } 2285 2286 /* precompile regular expression for efficiency */ 2287 if ((create_reg->tblp[i].flags & DRV_RE) == DRV_RE) { 2288 if ((n = regcomp(&(create_list_element-> 2289 drv_name_comp), 2290 create_reg->tblp[i].drv_name, 2291 REG_EXTENDED)) != 0) { 2292 if ((flags & TYPE_RE) == TYPE_RE) { 2293 regfree(&(create_list_element-> 2294 node_type_comp)); 2295 } 2296 free(create_list_element); 2297 err_print(REGCOMP_FAILED, 2298 create_reg->tblp[i].drv_name, 2299 n); 2300 err_print(IGNORING_ENTRY, i, epath); 2301 continue; 2302 } 2303 } 2304 2305 2306 /* add to list sorted by interpose level */ 2307 for (create_list_next = &(create_head); 2308 (*create_list_next != NULL) && 2309 (*create_list_next)->create->interpose_lvl >= 2310 create_list_element->create->interpose_lvl; 2311 create_list_next = 2312 &((*create_list_next)->next)); 2313 create_list_element->next = *create_list_next; 2314 *create_list_next = create_list_element; 2315 } 2316 } 2317 2318 /* 2319 * put a ptr to each struct devfsadm_remove on "remove_head" 2320 * list sorted by interpose_lvl. 2321 */ 2322 flags = 0; 2323 if (remove_reg != NULL) { 2324 if (remove_reg->version < DEVFSADM_V1) 2325 flags |= RM_NOINTERPOSE; 2326 for (i = 0; i < remove_reg->count; i++) { 2327 2328 remove_list_element = (remove_list_t *) 2329 s_malloc(sizeof (remove_list_t)); 2330 2331 remove_list_element->remove = &(remove_reg->tblp[i]); 2332 remove_list_element->remove->flags |= flags; 2333 remove_list_element->modptr = module; 2334 2335 for (remove_list_next = &(remove_head); 2336 (*remove_list_next != NULL) && 2337 (*remove_list_next)->remove->interpose_lvl >= 2338 remove_list_element->remove->interpose_lvl; 2339 remove_list_next = 2340 &((*remove_list_next)->next)); 2341 remove_list_element->next = *remove_list_next; 2342 *remove_list_next = remove_list_element; 2343 } 2344 } 2345 2346 module->next = module_head; 2347 module_head = module; 2348 } 2349 2350 /* 2351 * After we have completed a CACHE_STATE, if a SYNC_STATE does not occur 2352 * within 'timeout' secs the minor_fini_thread needs to do a SYNC_STATE 2353 * so that we still call the minor_fini routines. 2354 */ 2355 /*ARGSUSED*/ 2356 static void 2357 minor_fini_thread(void *arg) 2358 { 2359 timestruc_t abstime; 2360 2361 vprint(INITFINI_MID, "minor_fini_thread starting\n"); 2362 2363 (void) mutex_lock(&minor_fini_mutex); 2364 for (;;) { 2365 /* wait the gather period, or until signaled */ 2366 abstime.tv_sec = time(NULL) + minor_fini_timeout; 2367 abstime.tv_nsec = 0; 2368 (void) cond_timedwait(&minor_fini_cv, 2369 &minor_fini_mutex, &abstime); 2370 2371 /* if minor_fini was canceled, go wait again */ 2372 if (minor_fini_canceled == TRUE) 2373 continue; 2374 2375 /* if minor_fini was delayed, go wait again */ 2376 if (minor_fini_delayed == TRUE) { 2377 minor_fini_delayed = FALSE; 2378 continue; 2379 } 2380 2381 /* done with cancellations and delays, do the SYNC_STATE */ 2382 (void) mutex_unlock(&minor_fini_mutex); 2383 2384 lock_dev(); 2385 unlock_dev(SYNC_STATE); 2386 vprint(INITFINI_MID, "minor_fini sync done\n"); 2387 2388 (void) mutex_lock(&minor_fini_mutex); 2389 } 2390 } 2391 2392 2393 /* 2394 * Attempt to initialize module, if a minor_init routine exists. Set 2395 * the active flag if the routine exists and succeeds. If it doesn't 2396 * exist, just set the active flag. 2397 */ 2398 static int 2399 call_minor_init(module_t *module) 2400 { 2401 char *fcn = "call_minor_init: "; 2402 2403 if ((module->flags & MODULE_ACTIVE) == MODULE_ACTIVE) { 2404 return (DEVFSADM_SUCCESS); 2405 } 2406 2407 vprint(INITFINI_MID, "%smodule %s. current state: inactive\n", 2408 fcn, module->name); 2409 2410 if (module->minor_init == NULL) { 2411 module->flags |= MODULE_ACTIVE; 2412 vprint(INITFINI_MID, "minor_init not defined\n"); 2413 return (DEVFSADM_SUCCESS); 2414 } 2415 2416 if ((*(module->minor_init))() == DEVFSADM_FAILURE) { 2417 err_print(FAILED_FOR_MODULE, MINOR_INIT, module->name); 2418 return (DEVFSADM_FAILURE); 2419 } 2420 2421 vprint(INITFINI_MID, "minor_init() returns DEVFSADM_SUCCESS. " 2422 "new state: active\n"); 2423 2424 module->flags |= MODULE_ACTIVE; 2425 return (DEVFSADM_SUCCESS); 2426 } 2427 2428 /* 2429 * Creates a symlink 'link' to the physical path of node:minor. 2430 * Construct link contents, then call create_link_common(). 2431 */ 2432 /*ARGSUSED*/ 2433 int 2434 devfsadm_mklink(char *link, di_node_t node, di_minor_t minor, int flags) 2435 { 2436 char rcontents[PATH_MAX]; 2437 char devlink[PATH_MAX]; 2438 char phy_path[PATH_MAX]; 2439 char *acontents; 2440 char *dev_path; 2441 int numslashes; 2442 int rv; 2443 int i, link_exists; 2444 int last_was_slash = FALSE; 2445 2446 /* 2447 * try to use devices path 2448 */ 2449 if ((node == lnode) && (minor == lminor)) { 2450 acontents = lphy_path; 2451 } else if (di_minor_type(minor) == DDM_ALIAS) { 2452 /* use /pseudo/clone@0:<driver> as the phys path */ 2453 (void) snprintf(phy_path, sizeof (phy_path), 2454 "/pseudo/clone@0:%s", 2455 di_driver_name(di_minor_devinfo(minor))); 2456 acontents = phy_path; 2457 } else { 2458 if ((dev_path = di_devfs_path(node)) == NULL) { 2459 err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 2460 devfsadm_exit(1); 2461 } 2462 (void) snprintf(phy_path, sizeof (phy_path), "%s:%s", 2463 dev_path, di_minor_name(minor)); 2464 di_devfs_path_free(dev_path); 2465 acontents = phy_path; 2466 } 2467 2468 /* prepend link with dev_dir contents */ 2469 (void) strlcpy(devlink, dev_dir, sizeof (devlink)); 2470 (void) strlcat(devlink, "/", sizeof (devlink)); 2471 (void) strlcat(devlink, link, sizeof (devlink)); 2472 2473 /* 2474 * Calculate # of ../ to add. Account for double '//' in path. 2475 * Ignore all leading slashes. 2476 */ 2477 for (i = 0; link[i] == '/'; i++) 2478 ; 2479 for (numslashes = 0; link[i] != '\0'; i++) { 2480 if (link[i] == '/') { 2481 if (last_was_slash == FALSE) { 2482 numslashes++; 2483 last_was_slash = TRUE; 2484 } 2485 } else { 2486 last_was_slash = FALSE; 2487 } 2488 } 2489 /* Don't count any trailing '/' */ 2490 if (link[i-1] == '/') { 2491 numslashes--; 2492 } 2493 2494 rcontents[0] = '\0'; 2495 do { 2496 (void) strlcat(rcontents, "../", sizeof (rcontents)); 2497 } while (numslashes-- != 0); 2498 2499 (void) strlcat(rcontents, "devices", sizeof (rcontents)); 2500 (void) strlcat(rcontents, acontents, sizeof (rcontents)); 2501 2502 if (devlinks_debug == TRUE) { 2503 vprint(INFO_MID, "adding link %s ==> %s\n", devlink, rcontents); 2504 } 2505 2506 if ((rv = create_link_common(devlink, rcontents, &link_exists)) 2507 == DEVFSADM_SUCCESS) { 2508 linknew = TRUE; 2509 add_link_to_cache(link, acontents); 2510 } else { 2511 linknew = FALSE; 2512 } 2513 2514 if (link_exists == TRUE) { 2515 /* Link exists or was just created */ 2516 (void) di_devlink_add_link(devlink_cache, link, rcontents, 2517 DI_PRIMARY_LINK); 2518 2519 if (system_labeled && (flags & DA_ADD)) { 2520 /* 2521 * Add this to the list of allocatable devices. If this 2522 * is a hotplugged, removable disk, add it as rmdisk. 2523 */ 2524 int instance = di_instance(node); 2525 2526 if ((flags & DA_CD) && 2527 (_da_check_for_usb(devlink, root_dir) == 1)) { 2528 (void) da_add_list(&devlist, devlink, instance, 2529 DA_ADD|DA_RMDISK); 2530 update_devdb = DA_RMDISK; 2531 } else if (linknew == TRUE) { 2532 (void) da_add_list(&devlist, devlink, instance, 2533 flags); 2534 update_devdb = flags; 2535 } 2536 } 2537 } 2538 2539 return (rv); 2540 } 2541 2542 /* 2543 * Creates a symlink link to primary_link. Calculates relative 2544 * directory offsets, then calls link_common(). 2545 */ 2546 /*ARGSUSED*/ 2547 int 2548 devfsadm_secondary_link(char *link, char *primary_link, int flags) 2549 { 2550 char contents[PATH_MAX + 1]; 2551 char devlink[PATH_MAX + 1]; 2552 int rv, link_exists; 2553 char *fpath; 2554 char *tpath; 2555 char *op; 2556 2557 /* prepend link with dev_dir contents */ 2558 (void) strcpy(devlink, dev_dir); 2559 (void) strcat(devlink, "/"); 2560 (void) strcat(devlink, link); 2561 /* 2562 * building extra link, so use first link as link contents, but first 2563 * make it relative. 2564 */ 2565 fpath = link; 2566 tpath = primary_link; 2567 op = contents; 2568 2569 while (*fpath == *tpath && *fpath != '\0') { 2570 fpath++, tpath++; 2571 } 2572 2573 /* Count directories to go up, if any, and add "../" */ 2574 while (*fpath != '\0') { 2575 if (*fpath == '/') { 2576 (void) strcpy(op, "../"); 2577 op += 3; 2578 } 2579 fpath++; 2580 } 2581 2582 /* 2583 * Back up to the start of the current path component, in 2584 * case in the middle 2585 */ 2586 while (tpath != primary_link && *(tpath-1) != '/') { 2587 tpath--; 2588 } 2589 (void) strcpy(op, tpath); 2590 2591 if (devlinks_debug == TRUE) { 2592 vprint(INFO_MID, "adding extra link %s ==> %s\n", 2593 devlink, contents); 2594 } 2595 2596 if ((rv = create_link_common(devlink, contents, &link_exists)) 2597 == DEVFSADM_SUCCESS) { 2598 /* 2599 * we need to save the ultimate /devices contents, and not the 2600 * secondary link, since hotcleanup only looks at /devices path. 2601 * Since we don't have devices path here, we can try to get it 2602 * by readlink'ing the secondary link. This assumes the primary 2603 * link was created first. 2604 */ 2605 add_link_to_cache(link, lphy_path); 2606 linknew = TRUE; 2607 if (system_labeled && 2608 ((flags & DA_AUDIO) && (flags & DA_ADD))) { 2609 /* 2610 * Add this device to the list of allocatable devices. 2611 */ 2612 int instance = 0; 2613 2614 op = strrchr(contents, '/'); 2615 op++; 2616 (void) sscanf(op, "%d", &instance); 2617 (void) da_add_list(&devlist, devlink, instance, flags); 2618 update_devdb = flags; 2619 } 2620 } else { 2621 linknew = FALSE; 2622 } 2623 2624 /* 2625 * If link exists or was just created, add it to the database 2626 */ 2627 if (link_exists == TRUE) { 2628 (void) di_devlink_add_link(devlink_cache, link, contents, 2629 DI_SECONDARY_LINK); 2630 } 2631 2632 return (rv); 2633 } 2634 2635 /* returns pointer to the devices directory */ 2636 char * 2637 devfsadm_get_devices_dir() 2638 { 2639 return (devices_dir); 2640 } 2641 2642 /* 2643 * Does the actual link creation. VERBOSE_MID only used if there is 2644 * a change. CHATTY_MID used otherwise. 2645 */ 2646 static int 2647 create_link_common(char *devlink, char *contents, int *exists) 2648 { 2649 int try; 2650 int linksize; 2651 int max_tries = 0; 2652 static int prev_link_existed = TRUE; 2653 char checkcontents[PATH_MAX + 1]; 2654 char *hide; 2655 2656 *exists = FALSE; 2657 2658 /* Database is not updated when file_mods == FALSE */ 2659 if (file_mods == FALSE) { 2660 linksize = readlink(devlink, checkcontents, PATH_MAX); 2661 if (linksize > 0) { 2662 checkcontents[linksize] = '\0'; 2663 if (strcmp(checkcontents, contents) != 0) { 2664 vprint(CHATTY_MID, REMOVING_LINK, 2665 devlink, checkcontents); 2666 return (DEVFSADM_SUCCESS); 2667 } else { 2668 vprint(CHATTY_MID, "link exists and is correct:" 2669 " %s -> %s\n", devlink, contents); 2670 /* failure only in that the link existed */ 2671 return (DEVFSADM_FAILURE); 2672 } 2673 } else { 2674 vprint(VERBOSE_MID, CREATING_LINK, devlink, contents); 2675 return (DEVFSADM_SUCCESS); 2676 } 2677 } 2678 2679 /* 2680 * systems calls are expensive, so predict whether to readlink 2681 * or symlink first, based on previous attempt 2682 */ 2683 if (prev_link_existed == FALSE) { 2684 try = CREATE_LINK; 2685 } else { 2686 try = READ_LINK; 2687 } 2688 2689 while (++max_tries <= 3) { 2690 2691 switch (try) { 2692 case CREATE_LINK: 2693 2694 if (symlink(contents, devlink) == 0) { 2695 vprint(VERBOSE_MID, CREATING_LINK, devlink, 2696 contents); 2697 prev_link_existed = FALSE; 2698 /* link successfully created */ 2699 *exists = TRUE; 2700 set_logindev_perms(devlink); 2701 return (DEVFSADM_SUCCESS); 2702 } else { 2703 switch (errno) { 2704 2705 case ENOENT: 2706 /* dirpath to node doesn't exist */ 2707 hide = strrchr(devlink, '/'); 2708 *hide = '\0'; 2709 s_mkdirp(devlink, S_IRWXU|S_IRGRP| 2710 S_IXGRP|S_IROTH|S_IXOTH); 2711 *hide = '/'; 2712 break; 2713 case EEXIST: 2714 try = READ_LINK; 2715 break; 2716 default: 2717 err_print(SYMLINK_FAILED, devlink, 2718 contents, strerror(errno)); 2719 return (DEVFSADM_FAILURE); 2720 } 2721 } 2722 break; 2723 2724 case READ_LINK: 2725 2726 linksize = readlink(devlink, checkcontents, PATH_MAX); 2727 if (linksize >= 0) { 2728 checkcontents[linksize] = '\0'; 2729 if (strcmp(checkcontents, contents) != 0) { 2730 s_unlink(devlink); 2731 vprint(VERBOSE_MID, REMOVING_LINK, 2732 devlink, checkcontents); 2733 try = CREATE_LINK; 2734 } else { 2735 prev_link_existed = TRUE; 2736 vprint(CHATTY_MID, 2737 "link exists and is correct:" 2738 " %s -> %s\n", devlink, 2739 contents); 2740 *exists = TRUE; 2741 /* failure in that the link existed */ 2742 return (DEVFSADM_FAILURE); 2743 } 2744 } else { 2745 switch (errno) { 2746 case EINVAL: 2747 /* not a symlink, remove and create */ 2748 s_unlink(devlink); 2749 default: 2750 /* maybe it didn't exist at all */ 2751 try = CREATE_LINK; 2752 break; 2753 } 2754 } 2755 break; 2756 } 2757 } 2758 err_print(MAX_ATTEMPTS, devlink, contents); 2759 return (DEVFSADM_FAILURE); 2760 } 2761 2762 static void 2763 set_logindev_perms(char *devlink) 2764 { 2765 struct login_dev *newdev; 2766 struct passwd pwd, *resp; 2767 char pwd_buf[PATH_MAX]; 2768 int rv; 2769 struct stat sb; 2770 char *devfs_path = NULL; 2771 2772 /* 2773 * We only want logindev perms to be set when a device is 2774 * hotplugged or an application requests synchronous creates. 2775 * So we enable this only in daemon mode. In addition, 2776 * login(1) only fixes the std. /dev dir. So we don't 2777 * change perms if alternate root is set. 2778 * login_dev_enable is TRUE only in these cases. 2779 */ 2780 if (login_dev_enable != TRUE) 2781 return; 2782 2783 /* 2784 * Normally, /etc/logindevperm has few (8 - 10 entries) which 2785 * may be regular expressions (globs were converted to RE). 2786 * So just do a linear search through the list. 2787 */ 2788 for (newdev = login_dev_cache; newdev; newdev = newdev->ldev_next) { 2789 vprint(FILES_MID, "matching %s with %s\n", devlink, 2790 newdev->ldev_device); 2791 2792 if (regexec(&newdev->ldev_device_regex, devlink, 0, 2793 NULL, 0) == 0) { 2794 vprint(FILES_MID, "matched %s with %s\n", devlink, 2795 newdev->ldev_device); 2796 break; 2797 } 2798 } 2799 2800 if (newdev == NULL) 2801 return; 2802 2803 /* 2804 * we have a match, now find the driver associated with this 2805 * minor node using a snapshot on the physical path 2806 */ 2807 (void) resolve_link(devlink, NULL, NULL, &devfs_path, 0); 2808 if (devfs_path) { 2809 di_node_t node; 2810 char *drv = NULL; 2811 struct driver_list *list; 2812 char *p; 2813 2814 /* truncate on : so we can take a snapshot */ 2815 (void) strcpy(pwd_buf, devfs_path); 2816 p = strrchr(pwd_buf, ':'); 2817 if (p == NULL) { 2818 free(devfs_path); 2819 return; 2820 } 2821 *p = '\0'; 2822 2823 vprint(FILES_MID, "link=%s->physpath=%s\n", 2824 devlink, pwd_buf); 2825 2826 node = di_init(pwd_buf, DINFOMINOR); 2827 2828 if (node) { 2829 drv = di_driver_name(node); 2830 2831 if (drv) { 2832 vprint(FILES_MID, "%s: driver is %s\n", 2833 devlink, drv); 2834 } 2835 di_fini(node); 2836 } 2837 /* search thru the driver list specified in logindevperm */ 2838 list = newdev->ldev_driver_list; 2839 if ((drv != NULL) && (list != NULL)) { 2840 while (list) { 2841 if (strcmp(list->driver_name, 2842 drv) == 0) { 2843 vprint(FILES_MID, 2844 "driver %s match!\n", drv); 2845 break; 2846 } 2847 list = list->next; 2848 } 2849 if (list == NULL) { 2850 vprint(FILES_MID, "no driver match!\n"); 2851 free(devfs_path); 2852 return; 2853 } 2854 } 2855 free(devfs_path); 2856 } else { 2857 return; 2858 } 2859 2860 vprint(FILES_MID, "changing permissions of %s\n", devlink); 2861 2862 /* 2863 * We have a match. We now attempt to determine the 2864 * owner and group of the console user. 2865 * 2866 * stat() the console device newdev->ldev_console 2867 * which will always exist - it will have the right owner but 2868 * not the right group. Use getpwuid_r() to determine group for this 2869 * uid. 2870 * Note, it is safe to use name service here since if name services 2871 * are not available (during boot or in single-user mode), then 2872 * console owner will be root and its gid can be found in 2873 * local files. 2874 */ 2875 if (stat(newdev->ldev_console, &sb) == -1) { 2876 vprint(VERBOSE_MID, STAT_FAILED, newdev->ldev_console, 2877 strerror(errno)); 2878 return; 2879 } 2880 2881 resp = NULL; 2882 rv = getpwuid_r(sb.st_uid, &pwd, pwd_buf, sizeof (pwd_buf), &resp); 2883 if (rv || resp == NULL) { 2884 rv = rv ? rv : EINVAL; 2885 vprint(VERBOSE_MID, GID_FAILED, sb.st_uid, 2886 strerror(rv)); 2887 return; 2888 } 2889 2890 assert(&pwd == resp); 2891 2892 sb.st_gid = resp->pw_gid; 2893 2894 if (chmod(devlink, newdev->ldev_perms) == -1) { 2895 vprint(VERBOSE_MID, CHMOD_FAILED, devlink, 2896 strerror(errno)); 2897 return; 2898 } 2899 2900 if (chown(devlink, sb.st_uid, sb.st_gid) == -1) { 2901 vprint(VERBOSE_MID, CHOWN_FAILED, devlink, 2902 strerror(errno)); 2903 } 2904 } 2905 2906 /* 2907 * Reset /devices node with appropriate permissions and 2908 * ownership as specified in /etc/minor_perm. 2909 */ 2910 static void 2911 reset_node_permissions(di_node_t node, di_minor_t minor) 2912 { 2913 int spectype; 2914 char phy_path[PATH_MAX + 1]; 2915 mode_t mode; 2916 dev_t dev; 2917 uid_t uid; 2918 gid_t gid; 2919 struct stat sb; 2920 char *dev_path, *aminor = NULL; 2921 2922 /* lphy_path starts with / */ 2923 if ((dev_path = di_devfs_path(node)) == NULL) { 2924 err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 2925 devfsadm_exit(1); 2926 } 2927 (void) strcpy(lphy_path, dev_path); 2928 di_devfs_path_free(dev_path); 2929 2930 (void) strcat(lphy_path, ":"); 2931 if (di_minor_type(minor) == DDM_ALIAS) { 2932 char *driver; 2933 aminor = di_minor_name(minor); 2934 driver = di_driver_name(di_minor_devinfo(minor)); 2935 (void) strcat(lphy_path, driver); 2936 } else 2937 (void) strcat(lphy_path, di_minor_name(minor)); 2938 2939 (void) strcpy(phy_path, devices_dir); 2940 (void) strcat(phy_path, lphy_path); 2941 2942 lnode = node; 2943 lminor = minor; 2944 2945 vprint(CHATTY_MID, "reset_node_permissions: phy_path=%s lphy_path=%s\n", 2946 phy_path, lphy_path); 2947 2948 dev = di_minor_devt(minor); 2949 spectype = di_minor_spectype(minor); /* block or char */ 2950 2951 getattr(phy_path, aminor, spectype, dev, &mode, &uid, &gid); 2952 2953 /* 2954 * compare and set permissions and ownership 2955 * 2956 * Under devfs, a quick insertion and removal of USB devices 2957 * would cause stat of physical path to fail. In this case, 2958 * we emit a verbose message, but don't print errors. 2959 */ 2960 if ((stat(phy_path, &sb) == -1) || (sb.st_rdev != dev)) { 2961 vprint(VERBOSE_MID, NO_DEVFS_NODE, phy_path); 2962 return; 2963 } 2964 2965 /* 2966 * If we are here for a new device 2967 * If device allocation is on 2968 * then 2969 * set ownership to root:other and permissions to 0000 2970 * else 2971 * set ownership and permissions as specified in minor_perm 2972 * If we are here for an existing device 2973 * If device allocation is to be turned on 2974 * then 2975 * reset ownership to root:other and permissions to 0000 2976 * else if device allocation is to be turned off 2977 * reset ownership and permissions to those specified in 2978 * minor_perm 2979 * else 2980 * preserve existing/user-modified ownership and 2981 * permissions 2982 * 2983 * devfs indicates a new device by faking access time to be zero. 2984 */ 2985 if (sb.st_atime != 0) { 2986 int i; 2987 char *nt; 2988 2989 if ((devalloc_flag == 0) && (devalloc_is_on != 1)) 2990 /* 2991 * Leave existing devices as they are if we are not 2992 * turning device allocation on/off. 2993 */ 2994 return; 2995 2996 nt = di_minor_nodetype(minor); 2997 2998 if (nt == NULL) 2999 return; 3000 3001 for (i = 0; devalloc_list[i]; i++) { 3002 if (strcmp(nt, devalloc_list[i]) == 0) 3003 /* 3004 * One of the types recognized by devalloc, 3005 * reset attrs. 3006 */ 3007 break; 3008 } 3009 if (devalloc_list[i] == NULL) 3010 return; 3011 } 3012 3013 if (file_mods == FALSE) { 3014 /* Nothing more to do if simulating */ 3015 vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode); 3016 return; 3017 } 3018 3019 if ((devalloc_flag == DA_ON) || (devalloc_is_on == 1)) { 3020 /* 3021 * we are here either to turn device allocation on 3022 * or to add a new device while device allocation in on 3023 */ 3024 mode = DEALLOC_MODE; 3025 uid = DA_UID; 3026 gid = DA_GID; 3027 } 3028 3029 if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) || 3030 (sb.st_mode != mode)) { 3031 if (chmod(phy_path, mode) == -1) 3032 vprint(VERBOSE_MID, CHMOD_FAILED, 3033 phy_path, strerror(errno)); 3034 } 3035 if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) || 3036 (sb.st_uid != uid || sb.st_gid != gid)) { 3037 if (chown(phy_path, uid, gid) == -1) 3038 vprint(VERBOSE_MID, CHOWN_FAILED, 3039 phy_path, strerror(errno)); 3040 } 3041 3042 /* Report that we actually did something */ 3043 vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode); 3044 } 3045 3046 /* 3047 * Removes logical link and the minor node it refers to. If file is a 3048 * link, we recurse and try to remove the minor node (or link if path is 3049 * a double link) that file's link contents refer to. 3050 */ 3051 static void 3052 devfsadm_rm_work(char *file, int recurse, int file_type) 3053 { 3054 char *fcn = "devfsadm_rm_work: "; 3055 int linksize; 3056 char contents[PATH_MAX + 1]; 3057 char nextfile[PATH_MAX + 1]; 3058 char newfile[PATH_MAX + 1]; 3059 char *ptr; 3060 3061 vprint(REMOVE_MID, "%s%s\n", fcn, file); 3062 3063 /* TYPE_LINK split into multiple if's due to excessive indentations */ 3064 if (file_type == TYPE_LINK) { 3065 (void) strcpy(newfile, dev_dir); 3066 (void) strcat(newfile, "/"); 3067 (void) strcat(newfile, file); 3068 } 3069 3070 if ((file_type == TYPE_LINK) && (recurse == TRUE) && 3071 ((linksize = readlink(newfile, contents, PATH_MAX)) > 0)) { 3072 contents[linksize] = '\0'; 3073 3074 if (is_minor_node(contents, &ptr) == DEVFSADM_TRUE) { 3075 devfsadm_rm_work(++ptr, FALSE, TYPE_DEVICES); 3076 } else { 3077 if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) { 3078 devfsadm_rm_work(&contents[strlen(DEV) + 1], 3079 TRUE, TYPE_LINK); 3080 } else { 3081 if ((ptr = strrchr(file, '/')) != NULL) { 3082 *ptr = '\0'; 3083 (void) strcpy(nextfile, file); 3084 *ptr = '/'; 3085 (void) strcat(nextfile, "/"); 3086 } else { 3087 (void) strcpy(nextfile, ""); 3088 } 3089 (void) strcat(nextfile, contents); 3090 devfsadm_rm_work(nextfile, TRUE, TYPE_LINK); 3091 } 3092 } 3093 } 3094 3095 if (file_type == TYPE_LINK) { 3096 vprint(VERBOSE_MID, DEVFSADM_UNLINK, newfile); 3097 if (file_mods == TRUE) { 3098 rm_link_from_cache(file); 3099 s_unlink(newfile); 3100 rm_parent_dir_if_empty(newfile); 3101 invalidate_enumerate_cache(); 3102 (void) di_devlink_rm_link(devlink_cache, file); 3103 } 3104 } 3105 3106 /* 3107 * Note: we don't remove /devices entries because they are 3108 * covered by devfs. 3109 */ 3110 } 3111 3112 void 3113 devfsadm_rm_link(char *file) 3114 { 3115 devfsadm_rm_work(file, FALSE, TYPE_LINK); 3116 } 3117 3118 void 3119 devfsadm_rm_all(char *file) 3120 { 3121 devfsadm_rm_work(file, TRUE, TYPE_LINK); 3122 } 3123 3124 static int 3125 s_rmdir(char *path) 3126 { 3127 int i; 3128 char *rpath, *dir; 3129 const char *fcn = "s_rmdir"; 3130 3131 /* 3132 * Certain directories are created at install time by packages. 3133 * Some of them (listed in packaged_dirs[]) are required by apps 3134 * and need to be present even when empty. 3135 */ 3136 vprint(REMOVE_MID, "%s: checking if %s is packaged\n", fcn, path); 3137 3138 rpath = path + strlen(dev_dir) + 1; 3139 3140 for (i = 0; (dir = packaged_dirs[i]) != NULL; i++) { 3141 if (*rpath == *dir) { 3142 if (strcmp(rpath, dir) == 0) { 3143 vprint(REMOVE_MID, "%s: skipping packaged dir: " 3144 "%s\n", fcn, path); 3145 errno = EEXIST; 3146 return (-1); 3147 } 3148 } 3149 } 3150 3151 return (rmdir(path)); 3152 } 3153 3154 /* 3155 * Try to remove any empty directories up the tree. It is assumed that 3156 * pathname is a file that was removed, so start with its parent, and 3157 * work up the tree. 3158 */ 3159 static void 3160 rm_parent_dir_if_empty(char *pathname) 3161 { 3162 char *ptr, path[PATH_MAX + 1]; 3163 char *fcn = "rm_parent_dir_if_empty: "; 3164 3165 vprint(REMOVE_MID, "%schecking %s if empty\n", fcn, pathname); 3166 3167 (void) strcpy(path, pathname); 3168 3169 /* 3170 * ascend up the dir tree, deleting all empty dirs. 3171 * Return immediately if a dir is not empty. 3172 */ 3173 for (;;) { 3174 3175 if ((ptr = strrchr(path, '/')) == NULL) { 3176 return; 3177 } 3178 3179 *ptr = '\0'; 3180 3181 if (finddev_emptydir(path)) { 3182 /* directory is empty */ 3183 if (s_rmdir(path) == 0) { 3184 vprint(REMOVE_MID, 3185 "%sremoving empty dir %s\n", fcn, path); 3186 } else if (errno == EEXIST) { 3187 vprint(REMOVE_MID, 3188 "%sfailed to remove dir: %s\n", fcn, path); 3189 return; 3190 } 3191 } else { 3192 /* some other file is here, so return */ 3193 vprint(REMOVE_MID, "%sdir not empty: %s\n", fcn, path); 3194 return; 3195 } 3196 } 3197 } 3198 3199 /* 3200 * This function and all the functions it calls below were added to 3201 * handle the unique problem with world wide names (WWN). The problem is 3202 * that if a WWN device is moved to another address on the same controller 3203 * its logical link will change, while the physical node remains the same. 3204 * The result is that two logical links will point to the same physical path 3205 * in /devices, the valid link and a stale link. This function will 3206 * find all the stale nodes, though at a significant performance cost. 3207 * 3208 * Caching is used to increase performance. 3209 * A cache will be built from disk if the cache tag doesn't already exist. 3210 * The cache tag is a regular expression "dir_re", which selects a 3211 * subset of disks to search from typically something like 3212 * "dev/cXt[0-9]+d[0-9]+s[0-9]+". After the cache is built, consistency must 3213 * be maintained, so entries are added as new links are created, and removed 3214 * as old links are deleted. The whole cache is flushed if we are a daemon, 3215 * and another devfsadm process ran in between. 3216 * 3217 * Once the cache is built, this function finds the cache which matches 3218 * dir_re, and then it searches all links in that cache looking for 3219 * any link whose contents match "valid_link_contents" with a corresponding link 3220 * which does not match "valid_link". Any such matches are stale and removed. 3221 */ 3222 void 3223 devfsadm_rm_stale_links(char *dir_re, char *valid_link, di_node_t node, 3224 di_minor_t minor) 3225 { 3226 link_t *link; 3227 linkhead_t *head; 3228 char phy_path[PATH_MAX + 1]; 3229 char *valid_link_contents; 3230 char *dev_path; 3231 char rmlink[PATH_MAX + 1]; 3232 3233 /* 3234 * try to use devices path 3235 */ 3236 if ((node == lnode) && (minor == lminor)) { 3237 valid_link_contents = lphy_path; 3238 } else { 3239 if ((dev_path = di_devfs_path(node)) == NULL) { 3240 err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 3241 devfsadm_exit(1); 3242 } 3243 (void) strcpy(phy_path, dev_path); 3244 di_devfs_path_free(dev_path); 3245 3246 (void) strcat(phy_path, ":"); 3247 (void) strcat(phy_path, di_minor_name(minor)); 3248 valid_link_contents = phy_path; 3249 } 3250 3251 /* 3252 * As an optimization, check to make sure the corresponding 3253 * devlink was just created before continuing. 3254 */ 3255 3256 if (linknew == FALSE) { 3257 return; 3258 } 3259 3260 head = get_cached_links(dir_re); 3261 3262 assert(head->nextlink == NULL); 3263 3264 for (link = head->link; link != NULL; link = head->nextlink) { 3265 /* 3266 * See hot_cleanup() for why we do this 3267 */ 3268 head->nextlink = link->next; 3269 if ((strcmp(link->contents, valid_link_contents) == 0) && 3270 (strcmp(link->devlink, valid_link) != 0)) { 3271 vprint(CHATTY_MID, "removing %s -> %s\n" 3272 "valid link is: %s -> %s\n", 3273 link->devlink, link->contents, 3274 valid_link, valid_link_contents); 3275 /* 3276 * Use a copy of the cached link name as the 3277 * cache entry will go away during link removal 3278 */ 3279 (void) snprintf(rmlink, sizeof (rmlink), "%s", 3280 link->devlink); 3281 devfsadm_rm_link(rmlink); 3282 } 3283 } 3284 } 3285 3286 /* 3287 * Return previously created cache, or create cache. 3288 */ 3289 static linkhead_t * 3290 get_cached_links(char *dir_re) 3291 { 3292 recurse_dev_t rd; 3293 linkhead_t *linkhead; 3294 int n; 3295 3296 vprint(BUILDCACHE_MID, "get_cached_links: %s\n", dir_re); 3297 3298 for (linkhead = headlinkhead; linkhead != NULL; 3299 linkhead = linkhead->nexthead) { 3300 if (strcmp(linkhead->dir_re, dir_re) == 0) { 3301 return (linkhead); 3302 } 3303 } 3304 3305 /* 3306 * This tag is not in cache, so add it, along with all its 3307 * matching /dev entries. This is the only time we go to disk. 3308 */ 3309 linkhead = s_malloc(sizeof (linkhead_t)); 3310 linkhead->nexthead = headlinkhead; 3311 headlinkhead = linkhead; 3312 linkhead->dir_re = s_strdup(dir_re); 3313 3314 if ((n = regcomp(&(linkhead->dir_re_compiled), dir_re, 3315 REG_EXTENDED)) != 0) { 3316 err_print(REGCOMP_FAILED, dir_re, n); 3317 } 3318 3319 linkhead->nextlink = NULL; 3320 linkhead->link = NULL; 3321 3322 rd.fcn = build_devlink_list; 3323 rd.data = (void *)linkhead; 3324 3325 vprint(BUILDCACHE_MID, "get_cached_links: calling recurse_dev_re\n"); 3326 3327 /* call build_devlink_list for each directory in the dir_re RE */ 3328 if (dir_re[0] == '/') { 3329 recurse_dev_re("/", &dir_re[1], &rd); 3330 } else { 3331 recurse_dev_re(dev_dir, dir_re, &rd); 3332 } 3333 3334 return (linkhead); 3335 } 3336 3337 static void 3338 build_devlink_list(char *devlink, void *data) 3339 { 3340 char *fcn = "build_devlink_list: "; 3341 char *ptr; 3342 char *r_contents; 3343 char *r_devlink; 3344 char contents[PATH_MAX + 1]; 3345 char newlink[PATH_MAX + 1]; 3346 char stage_link[PATH_MAX + 1]; 3347 int linksize; 3348 linkhead_t *linkhead = (linkhead_t *)data; 3349 link_t *link; 3350 int i = 0; 3351 3352 vprint(BUILDCACHE_MID, "%scheck_link: %s\n", fcn, devlink); 3353 3354 (void) strcpy(newlink, devlink); 3355 3356 do { 3357 linksize = readlink(newlink, contents, PATH_MAX); 3358 if (linksize <= 0) { 3359 /* 3360 * The first pass through the do loop we may readlink() 3361 * non-symlink files(EINVAL) from false regexec matches. 3362 * Suppress error messages in those cases or if the link 3363 * content is the empty string. 3364 */ 3365 if (linksize < 0 && (i || errno != EINVAL)) 3366 err_print(READLINK_FAILED, "build_devlink_list", 3367 newlink, strerror(errno)); 3368 return; 3369 } 3370 contents[linksize] = '\0'; 3371 i = 1; 3372 3373 if (is_minor_node(contents, &r_contents) == DEVFSADM_FALSE) { 3374 /* 3375 * assume that link contents is really a pointer to 3376 * another link, so recurse and read its link contents. 3377 * 3378 * some link contents are absolute: 3379 * /dev/audio -> /dev/sound/0 3380 */ 3381 if (strncmp(contents, DEV "/", 3382 strlen(DEV) + strlen("/")) != 0) { 3383 3384 if ((ptr = strrchr(newlink, '/')) == NULL) { 3385 vprint(REMOVE_MID, "%s%s -> %s invalid " 3386 "link. missing '/'\n", fcn, 3387 newlink, contents); 3388 return; 3389 } 3390 *ptr = '\0'; 3391 (void) strcpy(stage_link, newlink); 3392 *ptr = '/'; 3393 (void) strcat(stage_link, "/"); 3394 (void) strcat(stage_link, contents); 3395 (void) strcpy(newlink, stage_link); 3396 } else { 3397 (void) strcpy(newlink, dev_dir); 3398 (void) strcat(newlink, "/"); 3399 (void) strcat(newlink, 3400 &contents[strlen(DEV) + strlen("/")]); 3401 } 3402 3403 } else { 3404 newlink[0] = '\0'; 3405 } 3406 } while (newlink[0] != '\0'); 3407 3408 if (strncmp(devlink, dev_dir, strlen(dev_dir)) != 0) { 3409 vprint(BUILDCACHE_MID, "%sinvalid link: %s\n", fcn, devlink); 3410 return; 3411 } 3412 3413 r_devlink = devlink + strlen(dev_dir); 3414 3415 if (r_devlink[0] != '/') 3416 return; 3417 3418 link = s_malloc(sizeof (link_t)); 3419 3420 /* don't store the '/' after rootdir/dev */ 3421 r_devlink += 1; 3422 3423 vprint(BUILDCACHE_MID, "%scaching link: %s\n", fcn, r_devlink); 3424 link->devlink = s_strdup(r_devlink); 3425 3426 link->contents = s_strdup(r_contents); 3427 3428 link->next = linkhead->link; 3429 linkhead->link = link; 3430 } 3431 3432 /* 3433 * to be consistent, devlink must not begin with / and must be 3434 * relative to /dev/, whereas physpath must contain / and be 3435 * relative to /devices. 3436 */ 3437 static void 3438 add_link_to_cache(char *devlink, char *physpath) 3439 { 3440 linkhead_t *linkhead; 3441 link_t *link; 3442 int added = 0; 3443 3444 if (file_mods == FALSE) { 3445 return; 3446 } 3447 3448 vprint(CACHE_MID, "add_link_to_cache: %s -> %s ", 3449 devlink, physpath); 3450 3451 for (linkhead = headlinkhead; linkhead != NULL; 3452 linkhead = linkhead->nexthead) { 3453 if (regexec(&(linkhead->dir_re_compiled), devlink, 0, NULL, 3454 0) == 0) { 3455 added++; 3456 link = s_malloc(sizeof (link_t)); 3457 link->devlink = s_strdup(devlink); 3458 link->contents = s_strdup(physpath); 3459 link->next = linkhead->link; 3460 linkhead->link = link; 3461 } 3462 } 3463 3464 vprint(CACHE_MID, 3465 " %d %s\n", added, added == 0 ? "NOT ADDED" : "ADDED"); 3466 } 3467 3468 /* 3469 * Remove devlink from cache. Devlink must be relative to /dev/ and not start 3470 * with /. 3471 */ 3472 static void 3473 rm_link_from_cache(char *devlink) 3474 { 3475 linkhead_t *linkhead; 3476 link_t **linkp; 3477 link_t *save; 3478 3479 vprint(CACHE_MID, "rm_link_from_cache enter: %s\n", devlink); 3480 3481 for (linkhead = headlinkhead; linkhead != NULL; 3482 linkhead = linkhead->nexthead) { 3483 if (regexec(&(linkhead->dir_re_compiled), devlink, 0, NULL, 3484 0) == 0) { 3485 3486 for (linkp = &(linkhead->link); *linkp != NULL; ) { 3487 if ((strcmp((*linkp)->devlink, devlink) == 0)) { 3488 save = *linkp; 3489 *linkp = (*linkp)->next; 3490 /* 3491 * We are removing our caller's 3492 * "next" link. Update the nextlink 3493 * field in the head so that our 3494 * callers accesses the next valid 3495 * link 3496 */ 3497 if (linkhead->nextlink == save) 3498 linkhead->nextlink = *linkp; 3499 free(save->devlink); 3500 free(save->contents); 3501 free(save); 3502 vprint(CACHE_MID, " %s FREED FROM " 3503 "CACHE\n", devlink); 3504 } else { 3505 linkp = &((*linkp)->next); 3506 } 3507 } 3508 } 3509 } 3510 } 3511 3512 static void 3513 rm_all_links_from_cache() 3514 { 3515 linkhead_t *linkhead; 3516 linkhead_t *nextlinkhead; 3517 link_t *link; 3518 link_t *nextlink; 3519 3520 vprint(CACHE_MID, "rm_all_links_from_cache\n"); 3521 3522 for (linkhead = headlinkhead; linkhead != NULL; 3523 linkhead = nextlinkhead) { 3524 3525 nextlinkhead = linkhead->nexthead; 3526 assert(linkhead->nextlink == NULL); 3527 for (link = linkhead->link; link != NULL; link = nextlink) { 3528 nextlink = link->next; 3529 free(link->devlink); 3530 free(link->contents); 3531 free(link); 3532 } 3533 regfree(&(linkhead->dir_re_compiled)); 3534 free(linkhead->dir_re); 3535 free(linkhead); 3536 } 3537 headlinkhead = NULL; 3538 } 3539 3540 /* 3541 * Called when the kernel has modified the incore path_to_inst data. This 3542 * function will schedule a flush of the data to the filesystem. 3543 */ 3544 static void 3545 devfs_instance_mod(void) 3546 { 3547 char *fcn = "devfs_instance_mod: "; 3548 vprint(PATH2INST_MID, "%senter\n", fcn); 3549 3550 /* signal instance thread */ 3551 (void) mutex_lock(&count_lock); 3552 inst_count++; 3553 (void) cond_signal(&cv); 3554 (void) mutex_unlock(&count_lock); 3555 } 3556 3557 static void 3558 instance_flush_thread(void) 3559 { 3560 int i; 3561 int idle; 3562 3563 for (;;) { 3564 3565 (void) mutex_lock(&count_lock); 3566 while (inst_count == 0) { 3567 (void) cond_wait(&cv, &count_lock); 3568 } 3569 inst_count = 0; 3570 3571 vprint(PATH2INST_MID, "signaled to flush path_to_inst." 3572 " Enter delay loop\n"); 3573 /* 3574 * Wait MAX_IDLE_DELAY seconds after getting the last flush 3575 * path_to_inst event before invoking a flush, but never wait 3576 * more than MAX_DELAY seconds after getting the first event. 3577 */ 3578 for (idle = 0, i = 0; i < MAX_DELAY; i++) { 3579 3580 (void) mutex_unlock(&count_lock); 3581 (void) sleep(1); 3582 (void) mutex_lock(&count_lock); 3583 3584 /* shorten the delay if we are idle */ 3585 if (inst_count == 0) { 3586 idle++; 3587 if (idle > MAX_IDLE_DELAY) { 3588 break; 3589 } 3590 } else { 3591 inst_count = idle = 0; 3592 } 3593 } 3594 3595 (void) mutex_unlock(&count_lock); 3596 3597 flush_path_to_inst(); 3598 } 3599 } 3600 3601 /* 3602 * Helper function for flush_path_to_inst() below; this routine calls the 3603 * inst_sync syscall to flush the path_to_inst database to the given file. 3604 */ 3605 static int 3606 do_inst_sync(char *filename) 3607 { 3608 void (*sigsaved)(int); 3609 int err = 0; 3610 3611 vprint(INSTSYNC_MID, "do_inst_sync: about to flush %s\n", filename); 3612 sigsaved = sigset(SIGSYS, SIG_IGN); 3613 if (inst_sync(filename, 0) == -1) 3614 err = errno; 3615 (void) sigset(SIGSYS, sigsaved); 3616 3617 switch (err) { 3618 case 0: 3619 return (DEVFSADM_SUCCESS); 3620 case EALREADY: /* no-op, path_to_inst already up to date */ 3621 return (EALREADY); 3622 case ENOSYS: 3623 err_print(CANT_LOAD_SYSCALL); 3624 break; 3625 case EPERM: 3626 err_print(SUPER_TO_SYNC); 3627 break; 3628 default: 3629 err_print(INSTSYNC_FAILED, filename, strerror(err)); 3630 break; 3631 } 3632 return (DEVFSADM_FAILURE); 3633 } 3634 3635 /* 3636 * Flush the kernel's path_to_inst database to /etc/path_to_inst. To do so 3637 * safely, the database is flushed to a temporary file, then moved into place. 3638 * 3639 * The following files are used during this process: 3640 * /etc/path_to_inst: The path_to_inst file 3641 * /etc/path_to_inst.<pid>: Contains data flushed from the kernel 3642 * /etc/path_to_inst.old: The backup file 3643 * /etc/path_to_inst.old.<pid>: Temp file for creating backup 3644 * 3645 */ 3646 static void 3647 flush_path_to_inst(void) 3648 { 3649 char *new_inst_file = NULL; 3650 char *old_inst_file = NULL; 3651 char *old_inst_file_npid = NULL; 3652 FILE *inst_file_fp = NULL; 3653 FILE *old_inst_file_fp = NULL; 3654 struct stat sb; 3655 int err = 0; 3656 int c; 3657 int inst_strlen; 3658 3659 vprint(PATH2INST_MID, "flush_path_to_inst: %s\n", 3660 (flush_path_to_inst_enable == TRUE) ? "ENABLED" : "DISABLED"); 3661 3662 if (flush_path_to_inst_enable == FALSE) { 3663 return; 3664 } 3665 3666 inst_strlen = strlen(inst_file); 3667 new_inst_file = s_malloc(inst_strlen + PID_STR_LEN + 2); 3668 old_inst_file = s_malloc(inst_strlen + PID_STR_LEN + 6); 3669 old_inst_file_npid = s_malloc(inst_strlen + 3670 sizeof (INSTANCE_FILE_SUFFIX)); 3671 3672 (void) snprintf(new_inst_file, inst_strlen + PID_STR_LEN + 2, 3673 "%s.%ld", inst_file, getpid()); 3674 3675 if (stat(new_inst_file, &sb) == 0) { 3676 s_unlink(new_inst_file); 3677 } 3678 3679 if ((err = do_inst_sync(new_inst_file)) != DEVFSADM_SUCCESS) { 3680 goto out; 3681 /*NOTREACHED*/ 3682 } 3683 3684 /* 3685 * Now we deal with the somewhat tricky updating and renaming 3686 * of this critical piece of kernel state. 3687 */ 3688 3689 /* 3690 * Copy the current instance file into a temporary file. 3691 * Then rename the temporary file into the backup (.old) 3692 * file and rename the newly flushed kernel data into 3693 * the instance file. 3694 * Of course if 'inst_file' doesn't exist, there's much 3695 * less for us to do .. tee hee. 3696 */ 3697 if ((inst_file_fp = fopen(inst_file, "r")) == NULL) { 3698 /* 3699 * No such file. Rename the new onto the old 3700 */ 3701 if ((err = rename(new_inst_file, inst_file)) != 0) 3702 err_print(RENAME_FAILED, inst_file, strerror(errno)); 3703 goto out; 3704 /*NOTREACHED*/ 3705 } 3706 3707 (void) snprintf(old_inst_file, inst_strlen + PID_STR_LEN + 6, 3708 "%s.old.%ld", inst_file, getpid()); 3709 3710 if (stat(old_inst_file, &sb) == 0) { 3711 s_unlink(old_inst_file); 3712 } 3713 3714 if ((old_inst_file_fp = fopen(old_inst_file, "w")) == NULL) { 3715 /* 3716 * Can't open the 'old_inst_file' file for writing. 3717 * This is somewhat strange given that the syscall 3718 * just succeeded to write a file out.. hmm.. maybe 3719 * the fs just filled up or something nasty. 3720 * 3721 * Anyway, abort what we've done so far. 3722 */ 3723 err_print(CANT_UPDATE, old_inst_file); 3724 err = DEVFSADM_FAILURE; 3725 goto out; 3726 /*NOTREACHED*/ 3727 } 3728 3729 /* 3730 * Copy current instance file into the temporary file 3731 */ 3732 err = 0; 3733 while ((c = getc(inst_file_fp)) != EOF) { 3734 if ((err = putc(c, old_inst_file_fp)) == EOF) { 3735 break; 3736 } 3737 } 3738 3739 if (fclose(old_inst_file_fp) == EOF || err == EOF) { 3740 vprint(INFO_MID, CANT_UPDATE, old_inst_file); 3741 err = DEVFSADM_FAILURE; 3742 goto out; 3743 /* NOTREACHED */ 3744 } 3745 3746 /* 3747 * Set permissions to be the same on the backup as 3748 * /etc/path_to_inst. 3749 */ 3750 (void) chmod(old_inst_file, 0444); 3751 3752 /* 3753 * So far, everything we've done is more or less reversible. 3754 * But now we're going to commit ourselves. 3755 */ 3756 3757 (void) snprintf(old_inst_file_npid, 3758 inst_strlen + sizeof (INSTANCE_FILE_SUFFIX), 3759 "%s%s", inst_file, INSTANCE_FILE_SUFFIX); 3760 3761 if ((err = rename(old_inst_file, old_inst_file_npid)) != 0) { 3762 err_print(RENAME_FAILED, old_inst_file_npid, 3763 strerror(errno)); 3764 } else if ((err = rename(new_inst_file, inst_file)) != 0) { 3765 err_print(RENAME_FAILED, inst_file, strerror(errno)); 3766 } 3767 3768 out: 3769 if (inst_file_fp != NULL) { 3770 if (fclose(inst_file_fp) == EOF) { 3771 err_print(FCLOSE_FAILED, inst_file, strerror(errno)); 3772 } 3773 } 3774 3775 if (stat(new_inst_file, &sb) == 0) { 3776 s_unlink(new_inst_file); 3777 } 3778 free(new_inst_file); 3779 3780 if (stat(old_inst_file, &sb) == 0) { 3781 s_unlink(old_inst_file); 3782 } 3783 free(old_inst_file); 3784 3785 free(old_inst_file_npid); 3786 3787 if (err != 0 && err != EALREADY) { 3788 err_print(FAILED_TO_UPDATE, inst_file); 3789 } 3790 } 3791 3792 /* 3793 * detach from tty. For daemon mode. 3794 */ 3795 void 3796 detachfromtty() 3797 { 3798 (void) setsid(); 3799 if (DEVFSADM_DEBUG_ON == TRUE) { 3800 return; 3801 } 3802 3803 (void) close(0); 3804 (void) close(1); 3805 (void) close(2); 3806 (void) open("/dev/null", O_RDWR, 0); 3807 (void) dup(0); 3808 (void) dup(0); 3809 openlog(DEVFSADMD, LOG_PID, LOG_DAEMON); 3810 (void) setlogmask(LOG_UPTO(LOG_INFO)); 3811 logflag = TRUE; 3812 } 3813 3814 /* 3815 * Use an advisory lock to synchronize updates to /dev. If the lock is 3816 * held by another process, block in the fcntl() system call until that 3817 * process drops the lock or exits. The lock file itself is 3818 * DEV_LOCK_FILE. The process id of the current and last process owning 3819 * the lock is kept in the lock file. After acquiring the lock, read the 3820 * process id and return it. It is the process ID which last owned the 3821 * lock, and will be used to determine if caches need to be flushed. 3822 * 3823 * NOTE: if the devlink database is held open by the caller, it may 3824 * be closed by this routine. This is to enforce the following lock ordering: 3825 * 1) /dev lock 2) database open 3826 */ 3827 pid_t 3828 enter_dev_lock() 3829 { 3830 struct flock lock; 3831 int n; 3832 pid_t pid; 3833 pid_t last_owner_pid; 3834 3835 if (file_mods == FALSE) { 3836 return (0); 3837 } 3838 3839 (void) snprintf(dev_lockfile, sizeof (dev_lockfile), 3840 "%s/%s", etc_dev_dir, DEV_LOCK_FILE); 3841 3842 vprint(LOCK_MID, "enter_dev_lock: lock file %s\n", dev_lockfile); 3843 3844 dev_lock_fd = open(dev_lockfile, O_CREAT|O_RDWR, 0644); 3845 if (dev_lock_fd < 0) { 3846 err_print(OPEN_FAILED, dev_lockfile, strerror(errno)); 3847 devfsadm_exit(1); 3848 } 3849 3850 lock.l_type = F_WRLCK; 3851 lock.l_whence = SEEK_SET; 3852 lock.l_start = 0; 3853 lock.l_len = 0; 3854 3855 /* try for the lock, but don't wait */ 3856 if (fcntl(dev_lock_fd, F_SETLK, &lock) == -1) { 3857 if ((errno == EACCES) || (errno == EAGAIN)) { 3858 pid = 0; 3859 n = read(dev_lock_fd, &pid, sizeof (pid_t)); 3860 vprint(LOCK_MID, "waiting for PID %d to complete\n", 3861 (int)pid); 3862 if (lseek(dev_lock_fd, 0, SEEK_SET) == (off_t)-1) { 3863 err_print(LSEEK_FAILED, dev_lockfile, 3864 strerror(errno)); 3865 devfsadm_exit(1); 3866 } 3867 /* 3868 * wait for the dev lock. If we have the database open, 3869 * close it first - the order of lock acquisition should 3870 * always be: 1) dev_lock 2) database 3871 * This is to prevent deadlocks with any locks the 3872 * database code may hold. 3873 */ 3874 (void) di_devlink_close(&devlink_cache, 0); 3875 3876 /* send any sysevents that were queued up. */ 3877 process_syseventq(); 3878 3879 if (fcntl(dev_lock_fd, F_SETLKW, &lock) == -1) { 3880 err_print(LOCK_FAILED, dev_lockfile, 3881 strerror(errno)); 3882 devfsadm_exit(1); 3883 } 3884 } 3885 } 3886 3887 hold_dev_lock = TRUE; 3888 pid = 0; 3889 n = read(dev_lock_fd, &pid, sizeof (pid_t)); 3890 if (n == sizeof (pid_t) && pid == getpid()) { 3891 return (pid); 3892 } 3893 3894 last_owner_pid = pid; 3895 3896 if (lseek(dev_lock_fd, 0, SEEK_SET) == (off_t)-1) { 3897 err_print(LSEEK_FAILED, dev_lockfile, strerror(errno)); 3898 devfsadm_exit(1); 3899 } 3900 pid = getpid(); 3901 n = write(dev_lock_fd, &pid, sizeof (pid_t)); 3902 if (n != sizeof (pid_t)) { 3903 err_print(WRITE_FAILED, dev_lockfile, strerror(errno)); 3904 devfsadm_exit(1); 3905 } 3906 3907 return (last_owner_pid); 3908 } 3909 3910 /* 3911 * Drop the advisory /dev lock, close lock file. Close and re-open the 3912 * file every time so to ensure a resync if for some reason the lock file 3913 * gets removed. 3914 */ 3915 void 3916 exit_dev_lock() 3917 { 3918 struct flock unlock; 3919 3920 if (hold_dev_lock == FALSE) { 3921 return; 3922 } 3923 3924 vprint(LOCK_MID, "exit_dev_lock: lock file %s\n", dev_lockfile); 3925 3926 unlock.l_type = F_UNLCK; 3927 unlock.l_whence = SEEK_SET; 3928 unlock.l_start = 0; 3929 unlock.l_len = 0; 3930 3931 if (fcntl(dev_lock_fd, F_SETLK, &unlock) == -1) { 3932 err_print(UNLOCK_FAILED, dev_lockfile, strerror(errno)); 3933 } 3934 3935 hold_dev_lock = FALSE; 3936 3937 if (close(dev_lock_fd) == -1) { 3938 err_print(CLOSE_FAILED, dev_lockfile, strerror(errno)); 3939 devfsadm_exit(1); 3940 } 3941 } 3942 3943 /* 3944 * 3945 * Use an advisory lock to ensure that only one daemon process is active 3946 * in the system at any point in time. If the lock is held by another 3947 * process, do not block but return the pid owner of the lock to the 3948 * caller immediately. The lock is cleared if the holding daemon process 3949 * exits for any reason even if the lock file remains, so the daemon can 3950 * be restarted if necessary. The lock file is DAEMON_LOCK_FILE. 3951 */ 3952 pid_t 3953 enter_daemon_lock(void) 3954 { 3955 struct flock lock; 3956 3957 (void) snprintf(daemon_lockfile, sizeof (daemon_lockfile), 3958 "%s/%s", etc_dev_dir, DAEMON_LOCK_FILE); 3959 3960 vprint(LOCK_MID, "enter_daemon_lock: lock file %s\n", daemon_lockfile); 3961 3962 daemon_lock_fd = open(daemon_lockfile, O_CREAT|O_RDWR, 0644); 3963 if (daemon_lock_fd < 0) { 3964 err_print(OPEN_FAILED, daemon_lockfile, strerror(errno)); 3965 devfsadm_exit(1); 3966 } 3967 3968 lock.l_type = F_WRLCK; 3969 lock.l_whence = SEEK_SET; 3970 lock.l_start = 0; 3971 lock.l_len = 0; 3972 3973 if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { 3974 3975 if (errno == EAGAIN || errno == EDEADLK) { 3976 if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) { 3977 err_print(LOCK_FAILED, daemon_lockfile, 3978 strerror(errno)); 3979 devfsadm_exit(1); 3980 } 3981 return (lock.l_pid); 3982 } 3983 } 3984 hold_daemon_lock = TRUE; 3985 return (getpid()); 3986 } 3987 3988 /* 3989 * Drop the advisory daemon lock, close lock file 3990 */ 3991 void 3992 exit_daemon_lock(void) 3993 { 3994 struct flock lock; 3995 3996 if (hold_daemon_lock == FALSE) { 3997 return; 3998 } 3999 4000 vprint(LOCK_MID, "exit_daemon_lock: lock file %s\n", daemon_lockfile); 4001 4002 lock.l_type = F_UNLCK; 4003 lock.l_whence = SEEK_SET; 4004 lock.l_start = 0; 4005 lock.l_len = 0; 4006 4007 if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) { 4008 err_print(UNLOCK_FAILED, daemon_lockfile, strerror(errno)); 4009 } 4010 4011 if (close(daemon_lock_fd) == -1) { 4012 err_print(CLOSE_FAILED, daemon_lockfile, strerror(errno)); 4013 devfsadm_exit(1); 4014 } 4015 } 4016 4017 /* 4018 * Called to removed danging nodes in two different modes: RM_PRE, RM_POST. 4019 * RM_PRE mode is called before processing the entire devinfo tree, and RM_POST 4020 * is called after processing the entire devinfo tree. 4021 */ 4022 static void 4023 pre_and_post_cleanup(int flags) 4024 { 4025 remove_list_t *rm; 4026 recurse_dev_t rd; 4027 cleanup_data_t cleanup_data; 4028 char *fcn = "pre_and_post_cleanup: "; 4029 4030 if (build_dev == FALSE) 4031 return; 4032 4033 vprint(CHATTY_MID, "attempting %s-cleanup\n", 4034 flags == RM_PRE ? "pre" : "post"); 4035 vprint(REMOVE_MID, "%sflags = %d\n", fcn, flags); 4036 4037 /* 4038 * the generic function recurse_dev_re is shared among different 4039 * functions, so set the method and data that it should use for 4040 * matches. 4041 */ 4042 rd.fcn = matching_dev; 4043 rd.data = (void *)&cleanup_data; 4044 cleanup_data.flags = flags; 4045 4046 (void) mutex_lock(&nfp_mutex); 4047 nfphash_create(); 4048 4049 for (rm = remove_head; rm != NULL; rm = rm->next) { 4050 if ((flags & rm->remove->flags) == flags) { 4051 cleanup_data.rm = rm; 4052 /* 4053 * If reached this point, RM_PRE or RM_POST cleanup is 4054 * desired. clean_ok() decides whether to clean 4055 * under the given circumstances. 4056 */ 4057 vprint(REMOVE_MID, "%scleanup: PRE or POST\n", fcn); 4058 if (clean_ok(rm->remove) == DEVFSADM_SUCCESS) { 4059 vprint(REMOVE_MID, "cleanup: cleanup OK\n"); 4060 recurse_dev_re(dev_dir, rm->remove-> 4061 dev_dirs_re, &rd); 4062 } 4063 } 4064 } 4065 nfphash_destroy(); 4066 (void) mutex_unlock(&nfp_mutex); 4067 } 4068 4069 /* 4070 * clean_ok() determines whether cleanup should be done according 4071 * to the following matrix: 4072 * 4073 * command line arguments RM_PRE RM_POST RM_PRE && RM_POST && 4074 * RM_ALWAYS RM_ALWAYS 4075 * ---------------------- ------ ----- --------- ---------- 4076 * 4077 * <neither -c nor -C> - - pre-clean post-clean 4078 * 4079 * -C pre-clean post-clean pre-clean post-clean 4080 * 4081 * -C -c class pre-clean post-clean pre-clean post-clean 4082 * if class if class if class if class 4083 * matches matches matches matches 4084 * 4085 * -c class - - pre-clean post-clean 4086 * if class if class 4087 * matches matches 4088 * 4089 */ 4090 static int 4091 clean_ok(devfsadm_remove_V1_t *remove) 4092 { 4093 int i; 4094 4095 if (single_drv == TRUE) { 4096 /* no cleanup at all when using -i option */ 4097 return (DEVFSADM_FAILURE); 4098 } 4099 4100 /* 4101 * no cleanup if drivers are not loaded. We make an exception 4102 * for the "disks" program however, since disks has a public 4103 * cleanup flag (-C) and disk drivers are usually never 4104 * unloaded. 4105 */ 4106 if (load_attach_drv == FALSE && strcmp(prog, DISKS) != 0) { 4107 return (DEVFSADM_FAILURE); 4108 } 4109 4110 /* if the cleanup flag was not specified, return false */ 4111 if ((cleanup == FALSE) && ((remove->flags & RM_ALWAYS) == 0)) { 4112 return (DEVFSADM_FAILURE); 4113 } 4114 4115 if (num_classes == 0) { 4116 return (DEVFSADM_SUCCESS); 4117 } 4118 4119 /* 4120 * if reached this point, check to see if the class in the given 4121 * remove structure matches a class given on the command line 4122 */ 4123 4124 for (i = 0; i < num_classes; i++) { 4125 if (strcmp(remove->device_class, classes[i]) == 0) { 4126 return (DEVFSADM_SUCCESS); 4127 } 4128 } 4129 4130 return (DEVFSADM_FAILURE); 4131 } 4132 4133 /* 4134 * Called to remove dangling nodes after receiving a hotplug event 4135 * containing the physical node pathname to be removed. 4136 */ 4137 void 4138 hot_cleanup(char *node_path, char *minor_name, char *ev_subclass, 4139 char *driver_name, int instance) 4140 { 4141 link_t *link; 4142 linkhead_t *head; 4143 remove_list_t *rm; 4144 char *fcn = "hot_cleanup: "; 4145 char path[PATH_MAX + 1]; 4146 int path_len; 4147 char rmlink[PATH_MAX + 1]; 4148 nvlist_t *nvl = NULL; 4149 int skip; 4150 int ret; 4151 4152 /* 4153 * dev links can go away as part of hot cleanup. 4154 * So first build event attributes in order capture dev links. 4155 */ 4156 if (ev_subclass != NULL) 4157 nvl = build_event_attributes(EC_DEV_REMOVE, ev_subclass, 4158 node_path, DI_NODE_NIL, driver_name, instance, minor_name); 4159 4160 (void) strcpy(path, node_path); 4161 (void) strcat(path, ":"); 4162 (void) strcat(path, minor_name == NULL ? "" : minor_name); 4163 4164 path_len = strlen(path); 4165 4166 vprint(REMOVE_MID, "%spath=%s\n", fcn, path); 4167 4168 (void) mutex_lock(&nfp_mutex); 4169 nfphash_create(); 4170 4171 for (rm = remove_head; rm != NULL; rm = rm->next) { 4172 if ((RM_HOT & rm->remove->flags) == RM_HOT) { 4173 head = get_cached_links(rm->remove->dev_dirs_re); 4174 assert(head->nextlink == NULL); 4175 for (link = head->link; 4176 link != NULL; link = head->nextlink) { 4177 /* 4178 * The remove callback below may remove 4179 * the current and/or any or all of the 4180 * subsequent links in the list. 4181 * Save the next link in the head. If 4182 * the callback removes the next link 4183 * the saved pointer in the head will be 4184 * updated by the callback to point at 4185 * the next valid link. 4186 */ 4187 head->nextlink = link->next; 4188 4189 /* 4190 * if devlink is in no-further-process hash, 4191 * skip its remove 4192 */ 4193 if (nfphash_lookup(link->devlink) != NULL) 4194 continue; 4195 4196 if (minor_name) 4197 skip = strcmp(link->contents, path); 4198 else 4199 skip = strncmp(link->contents, path, 4200 path_len); 4201 if (skip || 4202 (call_minor_init(rm->modptr) == 4203 DEVFSADM_FAILURE)) 4204 continue; 4205 4206 vprint(REMOVE_MID, 4207 "%sremoving %s -> %s\n", fcn, 4208 link->devlink, link->contents); 4209 /* 4210 * Use a copy of the cached link name 4211 * as the cache entry will go away 4212 * during link removal 4213 */ 4214 (void) snprintf(rmlink, sizeof (rmlink), 4215 "%s", link->devlink); 4216 if (rm->remove->flags & RM_NOINTERPOSE) { 4217 ((void (*)(char *)) 4218 (rm->remove->callback_fcn))(rmlink); 4219 } else { 4220 ret = ((int (*)(char *)) 4221 (rm->remove->callback_fcn))(rmlink); 4222 if (ret == DEVFSADM_TERMINATE) 4223 nfphash_insert(rmlink); 4224 } 4225 } 4226 } 4227 } 4228 4229 nfphash_destroy(); 4230 (void) mutex_unlock(&nfp_mutex); 4231 4232 /* update device allocation database */ 4233 if (system_labeled) { 4234 int ret = 0; 4235 int devtype = 0; 4236 char devname[MAXNAMELEN]; 4237 4238 devname[0] = '\0'; 4239 if (strstr(node_path, DA_SOUND_NAME)) 4240 devtype = DA_AUDIO; 4241 else if (strstr(node_path, "disk")) 4242 devtype = DA_RMDISK; 4243 else 4244 goto out; 4245 ret = da_remove_list(&devlist, NULL, devtype, devname, 4246 sizeof (devname)); 4247 if (ret != -1) 4248 (void) _update_devalloc_db(&devlist, devtype, DA_REMOVE, 4249 devname, root_dir); 4250 } 4251 4252 out: 4253 /* now log an event */ 4254 if (nvl) { 4255 log_event(EC_DEV_REMOVE, ev_subclass, nvl); 4256 free(nvl); 4257 } 4258 } 4259 4260 /* 4261 * Open the dir current_dir. For every file which matches the first dir 4262 * component of path_re, recurse. If there are no more *dir* path 4263 * components left in path_re (ie no more /), then call function rd->fcn. 4264 */ 4265 static void 4266 recurse_dev_re(char *current_dir, char *path_re, recurse_dev_t *rd) 4267 { 4268 regex_t re1; 4269 char *slash; 4270 char new_path[PATH_MAX + 1]; 4271 char *anchored_path_re; 4272 size_t len; 4273 finddevhdl_t fhandle; 4274 const char *fp; 4275 4276 vprint(RECURSEDEV_MID, "recurse_dev_re: curr = %s path=%s\n", 4277 current_dir, path_re); 4278 4279 if (finddev_readdir(current_dir, &fhandle) != 0) 4280 return; 4281 4282 len = strlen(path_re); 4283 if ((slash = strchr(path_re, '/')) != NULL) { 4284 len = (slash - path_re); 4285 } 4286 4287 anchored_path_re = s_malloc(len + 3); 4288 (void) sprintf(anchored_path_re, "^%.*s$", len, path_re); 4289 4290 if (regcomp(&re1, anchored_path_re, REG_EXTENDED) != 0) { 4291 free(anchored_path_re); 4292 goto out; 4293 } 4294 4295 free(anchored_path_re); 4296 4297 while ((fp = finddev_next(fhandle)) != NULL) { 4298 4299 if (regexec(&re1, fp, 0, NULL, 0) == 0) { 4300 /* match */ 4301 (void) strcpy(new_path, current_dir); 4302 (void) strcat(new_path, "/"); 4303 (void) strcat(new_path, fp); 4304 4305 vprint(RECURSEDEV_MID, "recurse_dev_re: match, new " 4306 "path = %s\n", new_path); 4307 4308 if (slash != NULL) { 4309 recurse_dev_re(new_path, slash + 1, rd); 4310 } else { 4311 /* reached the leaf component of path_re */ 4312 vprint(RECURSEDEV_MID, 4313 "recurse_dev_re: calling fcn\n"); 4314 (*(rd->fcn))(new_path, rd->data); 4315 } 4316 } 4317 } 4318 4319 regfree(&re1); 4320 4321 out: 4322 finddev_close(fhandle); 4323 } 4324 4325 /* 4326 * Found a devpath which matches a RE in the remove structure. 4327 * Now check to see if it is dangling. 4328 */ 4329 static void 4330 matching_dev(char *devpath, void *data) 4331 { 4332 cleanup_data_t *cleanup_data = data; 4333 int norm_len = strlen(dev_dir) + strlen("/"); 4334 int ret; 4335 char *fcn = "matching_dev: "; 4336 4337 vprint(RECURSEDEV_MID, "%sexamining devpath = '%s'\n", fcn, 4338 devpath); 4339 4340 /* 4341 * If the link is in the no-further-process hash 4342 * don't do any remove operation on it. 4343 */ 4344 if (nfphash_lookup(devpath + norm_len) != NULL) 4345 return; 4346 4347 if (resolve_link(devpath, NULL, NULL, NULL, 1) == TRUE) { 4348 if (call_minor_init(cleanup_data->rm->modptr) == 4349 DEVFSADM_FAILURE) { 4350 return; 4351 } 4352 4353 devpath += norm_len; 4354 4355 vprint(RECURSEDEV_MID, "%scalling" 4356 " callback %s\n", fcn, devpath); 4357 if (cleanup_data->rm->remove->flags & RM_NOINTERPOSE) 4358 ((void (*)(char *)) 4359 (cleanup_data->rm->remove->callback_fcn))(devpath); 4360 else { 4361 ret = ((int (*)(char *)) 4362 (cleanup_data->rm->remove->callback_fcn))(devpath); 4363 if (ret == DEVFSADM_TERMINATE) { 4364 /* 4365 * We want no further remove processing for 4366 * this link. Add it to the nfp_hash; 4367 */ 4368 nfphash_insert(devpath); 4369 } 4370 } 4371 } 4372 } 4373 4374 int 4375 devfsadm_read_link(char *link, char **devfs_path) 4376 { 4377 char devlink[PATH_MAX]; 4378 4379 *devfs_path = NULL; 4380 4381 /* prepend link with dev_dir contents */ 4382 (void) strcpy(devlink, dev_dir); 4383 (void) strcat(devlink, "/"); 4384 (void) strcat(devlink, link); 4385 4386 /* We *don't* want a stat of the /devices node */ 4387 (void) resolve_link(devlink, NULL, NULL, devfs_path, 0); 4388 4389 return (*devfs_path ? DEVFSADM_SUCCESS : DEVFSADM_FAILURE); 4390 } 4391 4392 int 4393 devfsadm_link_valid(char *link) 4394 { 4395 struct stat sb; 4396 char devlink[PATH_MAX + 1], *contents = NULL; 4397 int rv, type; 4398 int instance = 0; 4399 4400 /* prepend link with dev_dir contents */ 4401 (void) strcpy(devlink, dev_dir); 4402 (void) strcat(devlink, "/"); 4403 (void) strcat(devlink, link); 4404 4405 if (!device_exists(devlink) || lstat(devlink, &sb) != 0) { 4406 return (DEVFSADM_FALSE); 4407 } 4408 4409 contents = NULL; 4410 type = 0; 4411 if (resolve_link(devlink, &contents, &type, NULL, 1) == TRUE) { 4412 rv = DEVFSADM_FALSE; 4413 } else { 4414 rv = DEVFSADM_TRUE; 4415 } 4416 4417 /* 4418 * The link exists. Add it to the database 4419 */ 4420 (void) di_devlink_add_link(devlink_cache, link, contents, type); 4421 if (system_labeled && (rv == DEVFSADM_TRUE) && 4422 strstr(devlink, DA_AUDIO_NAME) && contents) { 4423 (void) sscanf(contents, "%*[a-z]%d", &instance); 4424 (void) da_add_list(&devlist, devlink, instance, 4425 DA_ADD|DA_AUDIO); 4426 _update_devalloc_db(&devlist, 0, DA_ADD, NULL, root_dir); 4427 } 4428 free(contents); 4429 4430 return (rv); 4431 } 4432 4433 /* 4434 * devpath: Absolute path to /dev link 4435 * content_p: Returns malloced string (link content) 4436 * type_p: Returns link type: primary or secondary 4437 * devfs_path: Returns malloced string: /devices path w/out "/devices" 4438 * dangle: if set, check if link is dangling 4439 * Returns: 4440 * TRUE if dangling 4441 * FALSE if not or if caller doesn't care 4442 * Caller is assumed to have initialized pointer contents to NULL 4443 */ 4444 static int 4445 resolve_link(char *devpath, char **content_p, int *type_p, char **devfs_path, 4446 int dangle) 4447 { 4448 char contents[PATH_MAX + 1]; 4449 char stage_link[PATH_MAX + 1]; 4450 char *fcn = "resolve_link: "; 4451 char *ptr; 4452 int linksize; 4453 int rv = TRUE; 4454 struct stat sb; 4455 4456 linksize = readlink(devpath, contents, PATH_MAX); 4457 4458 if (linksize <= 0) { 4459 return (FALSE); 4460 } else { 4461 contents[linksize] = '\0'; 4462 } 4463 vprint(REMOVE_MID, "%s %s -> %s\n", fcn, devpath, contents); 4464 4465 if (content_p) { 4466 *content_p = s_strdup(contents); 4467 } 4468 4469 /* 4470 * Check to see if this is a link pointing to another link in /dev. The 4471 * cheap way to do this is to look for a lack of ../devices/. 4472 */ 4473 4474 if (is_minor_node(contents, &ptr) == DEVFSADM_FALSE) { 4475 4476 if (type_p) { 4477 *type_p = DI_SECONDARY_LINK; 4478 } 4479 4480 /* 4481 * assume that linkcontents is really a pointer to another 4482 * link, and if so recurse and read its link contents. 4483 */ 4484 if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) { 4485 (void) strcpy(stage_link, dev_dir); 4486 (void) strcat(stage_link, "/"); 4487 (void) strcpy(stage_link, 4488 &contents[strlen(DEV) + strlen("/")]); 4489 } else { 4490 if ((ptr = strrchr(devpath, '/')) == NULL) { 4491 vprint(REMOVE_MID, "%s%s -> %s invalid link. " 4492 "missing '/'\n", fcn, devpath, 4493 contents); 4494 return (TRUE); 4495 } 4496 *ptr = '\0'; 4497 (void) strcpy(stage_link, devpath); 4498 *ptr = '/'; 4499 (void) strcat(stage_link, "/"); 4500 (void) strcat(stage_link, contents); 4501 } 4502 return (resolve_link(stage_link, NULL, NULL, devfs_path, 4503 dangle)); 4504 } 4505 4506 /* Current link points at a /devices minor node */ 4507 if (type_p) { 4508 *type_p = DI_PRIMARY_LINK; 4509 } 4510 4511 if (devfs_path) 4512 *devfs_path = s_strdup(ptr); 4513 4514 rv = FALSE; 4515 if (dangle) 4516 rv = (stat(ptr - strlen(DEVICES), &sb) == -1); 4517 4518 vprint(REMOVE_MID, "%slink=%s, returning %s\n", fcn, 4519 devpath, ((rv == TRUE) ? "TRUE" : "FALSE")); 4520 4521 return (rv); 4522 } 4523 4524 /* 4525 * Returns the substring of interest, given a path. 4526 */ 4527 static char * 4528 alloc_cmp_str(const char *path, devfsadm_enumerate_t *dep) 4529 { 4530 uint_t match; 4531 char *np, *ap, *mp; 4532 char *cmp_str = NULL; 4533 char at[] = "@"; 4534 char *fcn = "alloc_cmp_str"; 4535 4536 np = ap = mp = NULL; 4537 4538 /* 4539 * extract match flags from the flags argument. 4540 */ 4541 match = (dep->flags & MATCH_MASK); 4542 4543 vprint(ENUM_MID, "%s: enumeration match type: 0x%x" 4544 " path: %s\n", fcn, match, path); 4545 4546 /* 4547 * MATCH_CALLBACK and MATCH_ALL are the only flags 4548 * which may be used if "path" is a /dev path 4549 */ 4550 if (match == MATCH_CALLBACK) { 4551 if (dep->sel_fcn == NULL) { 4552 vprint(ENUM_MID, "%s: invalid enumerate" 4553 " callback: path: %s\n", fcn, path); 4554 return (NULL); 4555 } 4556 cmp_str = dep->sel_fcn(path, dep->cb_arg); 4557 return (cmp_str); 4558 } 4559 4560 cmp_str = s_strdup(path); 4561 4562 if (match == MATCH_ALL) { 4563 return (cmp_str); 4564 } 4565 4566 /* 4567 * The remaining flags make sense only for /devices 4568 * paths 4569 */ 4570 if ((mp = strrchr(cmp_str, ':')) == NULL) { 4571 vprint(ENUM_MID, "%s: invalid path: %s\n", 4572 fcn, path); 4573 goto err; 4574 } 4575 4576 if (match == MATCH_MINOR) { 4577 /* A NULL "match_arg" values implies entire minor */ 4578 if (get_component(mp + 1, dep->match_arg) == NULL) { 4579 vprint(ENUM_MID, "%s: invalid minor component:" 4580 " path: %s\n", fcn, path); 4581 goto err; 4582 } 4583 return (cmp_str); 4584 } 4585 4586 if ((np = strrchr(cmp_str, '/')) == NULL) { 4587 vprint(ENUM_MID, "%s: invalid path: %s\n", fcn, path); 4588 goto err; 4589 } 4590 4591 if (match == MATCH_PARENT) { 4592 if (strcmp(cmp_str, "/") == 0) { 4593 vprint(ENUM_MID, "%s: invalid path: %s\n", 4594 fcn, path); 4595 goto err; 4596 } 4597 4598 if (np == cmp_str) { 4599 *(np + 1) = '\0'; 4600 } else { 4601 *np = '\0'; 4602 } 4603 return (cmp_str); 4604 } 4605 4606 /* ap can be NULL - Leaf address may not exist or be empty string */ 4607 ap = strchr(np+1, '@'); 4608 4609 /* minor is no longer of interest */ 4610 *mp = '\0'; 4611 4612 if (match == MATCH_NODE) { 4613 if (ap) 4614 *ap = '\0'; 4615 return (cmp_str); 4616 } else if (match == MATCH_ADDR) { 4617 /* 4618 * The empty string is a valid address. The only MATCH_ADDR 4619 * allowed in this case is against the whole address or 4620 * the first component of the address (match_arg=NULL/"0"/"1") 4621 * Note that in this case, the path won't have an "@" 4622 * As a result ap will be NULL. We fake up an ap = @'\0' 4623 * so that get_component() will work correctly. 4624 */ 4625 if (ap == NULL) { 4626 ap = at; 4627 } 4628 4629 if (get_component(ap + 1, dep->match_arg) == NULL) { 4630 vprint(ENUM_MID, "%s: invalid leaf addr. component:" 4631 " path: %s\n", fcn, path); 4632 goto err; 4633 } 4634 return (cmp_str); 4635 } 4636 4637 vprint(ENUM_MID, "%s: invalid enumeration flags: 0x%x" 4638 " path: %s\n", fcn, dep->flags, path); 4639 4640 /*FALLTHRU*/ 4641 err: 4642 free(cmp_str); 4643 return (NULL); 4644 } 4645 4646 4647 /* 4648 * "str" is expected to be a string with components separated by ',' 4649 * The terminating null char is considered a separator. 4650 * get_component() will remove the portion of the string beyond 4651 * the component indicated. 4652 * If comp_str is NULL, the entire "str" is returned. 4653 */ 4654 static char * 4655 get_component(char *str, const char *comp_str) 4656 { 4657 long comp; 4658 char *cp; 4659 4660 if (str == NULL) { 4661 return (NULL); 4662 } 4663 4664 if (comp_str == NULL) { 4665 return (str); 4666 } 4667 4668 errno = 0; 4669 comp = strtol(comp_str, &cp, 10); 4670 if (errno != 0 || *cp != '\0' || comp < 0) { 4671 return (NULL); 4672 } 4673 4674 if (comp == 0) 4675 return (str); 4676 4677 for (cp = str; ; cp++) { 4678 if (*cp == ',' || *cp == '\0') 4679 comp--; 4680 if (*cp == '\0' || comp <= 0) { 4681 break; 4682 } 4683 } 4684 4685 if (comp == 0) { 4686 *cp = '\0'; 4687 } else { 4688 str = NULL; 4689 } 4690 4691 return (str); 4692 } 4693 4694 4695 /* 4696 * Enumerate serves as a generic counter as well as a means to determine 4697 * logical unit/controller numbers for such items as disk and tape 4698 * drives. 4699 * 4700 * rules[] is an array of devfsadm_enumerate_t structures which defines 4701 * the enumeration rules to be used for a specified set of links in /dev. 4702 * The set of links is specified through regular expressions (of the flavor 4703 * described in regex(5)). These regular expressions are used to determine 4704 * the set of links in /dev to examine. The last path component in these 4705 * regular expressions MUST contain a parenthesized subexpression surrounding 4706 * the RE which is to be considered the enumerating component. The subexp 4707 * member in a rule is the subexpression number of the enumerating 4708 * component. Subexpressions in the last path component are numbered starting 4709 * from 1. 4710 * 4711 * A cache of current id assignments is built up from existing symlinks and 4712 * new assignments use the lowest unused id. Assignments are based on a 4713 * match of a specified substring of a symlink's contents. If the specified 4714 * component for the devfs_path argument matches the corresponding substring 4715 * for a existing symlink's contents, the cached id is returned. Else, a new 4716 * id is created and returned in *buf. *buf must be freed by the caller. 4717 * 4718 * An id assignment may be governed by a combination of rules, each rule 4719 * applicable to a different subset of links in /dev. For example, controller 4720 * numbers may be determined by a combination of disk symlinks in /dev/[r]dsk 4721 * and controller symlinks in /dev/cfg, with the two sets requiring different 4722 * rules to derive the "substring of interest". In such cases, the rules 4723 * array will have more than one element. 4724 */ 4725 int 4726 devfsadm_enumerate_int(char *devfs_path, int index, char **buf, 4727 devfsadm_enumerate_t rules[], int nrules) 4728 { 4729 return (find_enum_id(rules, nrules, 4730 devfs_path, index, "0", INTEGER, buf, 0)); 4731 } 4732 4733 int 4734 disk_enumerate_int(char *devfs_path, int index, char **buf, 4735 devfsadm_enumerate_t rules[], int nrules) 4736 { 4737 return (find_enum_id(rules, nrules, 4738 devfs_path, index, "0", INTEGER, buf, 1)); 4739 } 4740 4741 /* 4742 * Same as above, but allows a starting value to be specified. 4743 * Private to devfsadm.... used by devlinks. 4744 */ 4745 static int 4746 devfsadm_enumerate_int_start(char *devfs_path, int index, char **buf, 4747 devfsadm_enumerate_t rules[], int nrules, char *start) 4748 { 4749 return (find_enum_id(rules, nrules, 4750 devfs_path, index, start, INTEGER, buf, 0)); 4751 } 4752 4753 /* 4754 * devfsadm_enumerate_char serves as a generic counter returning 4755 * a single letter. 4756 */ 4757 int 4758 devfsadm_enumerate_char(char *devfs_path, int index, char **buf, 4759 devfsadm_enumerate_t rules[], int nrules) 4760 { 4761 return (find_enum_id(rules, nrules, 4762 devfs_path, index, "a", LETTER, buf, 0)); 4763 } 4764 4765 /* 4766 * Same as above, but allows a starting char to be specified. 4767 * Private to devfsadm - used by ports module (port_link.c) 4768 */ 4769 int 4770 devfsadm_enumerate_char_start(char *devfs_path, int index, char **buf, 4771 devfsadm_enumerate_t rules[], int nrules, char *start) 4772 { 4773 return (find_enum_id(rules, nrules, 4774 devfs_path, index, start, LETTER, buf, 0)); 4775 } 4776 4777 4778 /* 4779 * For a given numeral_set (see get_cached_set for desc of numeral_set), 4780 * search all cached entries looking for matches on a specified substring 4781 * of devfs_path. The substring is derived from devfs_path based on the 4782 * rule specified by "index". If a match is found on a cached entry, 4783 * return the enumerated id in buf. Otherwise, create a new id by calling 4784 * new_id, then cache and return that entry. 4785 */ 4786 static int 4787 find_enum_id(devfsadm_enumerate_t rules[], int nrules, 4788 char *devfs_path, int index, char *min, int type, char **buf, 4789 int multiple) 4790 { 4791 numeral_t *matchnp; 4792 numeral_t *numeral; 4793 int matchcount = 0; 4794 char *cmp_str; 4795 char *fcn = "find_enum_id"; 4796 numeral_set_t *set; 4797 4798 if (rules == NULL) { 4799 vprint(ENUM_MID, "%s: no rules. path: %s\n", 4800 fcn, devfs_path ? devfs_path : "<NULL path>"); 4801 return (DEVFSADM_FAILURE); 4802 } 4803 4804 if (devfs_path == NULL) { 4805 vprint(ENUM_MID, "%s: NULL path\n", fcn); 4806 return (DEVFSADM_FAILURE); 4807 } 4808 4809 if (nrules <= 0 || index < 0 || index >= nrules || buf == NULL) { 4810 vprint(ENUM_MID, "%s: invalid arguments. path: %s\n", 4811 fcn, devfs_path); 4812 return (DEVFSADM_FAILURE); 4813 } 4814 4815 *buf = NULL; 4816 4817 4818 cmp_str = alloc_cmp_str(devfs_path, &rules[index]); 4819 if (cmp_str == NULL) { 4820 return (DEVFSADM_FAILURE); 4821 } 4822 4823 if ((set = get_enum_cache(rules, nrules)) == NULL) { 4824 free(cmp_str); 4825 return (DEVFSADM_FAILURE); 4826 } 4827 4828 assert(nrules == set->re_count); 4829 4830 /* 4831 * Check and see if a matching entry is already cached. 4832 */ 4833 matchcount = lookup_enum_cache(set, cmp_str, rules, index, 4834 &matchnp); 4835 4836 if (matchcount < 0 || matchcount > 1) { 4837 free(cmp_str); 4838 if (multiple && matchcount > 1) 4839 return (DEVFSADM_MULTIPLE); 4840 else 4841 return (DEVFSADM_FAILURE); 4842 } 4843 4844 /* if matching entry already cached, return it */ 4845 if (matchcount == 1) { 4846 /* should never create a link with a reserved ID */ 4847 vprint(ENUM_MID, "%s: 1 match w/ ID: %s\n", fcn, matchnp->id); 4848 assert(matchnp->flags == 0); 4849 *buf = s_strdup(matchnp->id); 4850 free(cmp_str); 4851 return (DEVFSADM_SUCCESS); 4852 } 4853 4854 /* 4855 * no cached entry, initialize a numeral struct 4856 * by calling new_id() and cache onto the numeral_set 4857 */ 4858 numeral = s_malloc(sizeof (numeral_t)); 4859 numeral->id = new_id(set->headnumeral, type, min); 4860 numeral->full_path = s_strdup(devfs_path); 4861 numeral->rule_index = index; 4862 numeral->cmp_str = cmp_str; 4863 cmp_str = NULL; 4864 numeral->flags = 0; 4865 vprint(RSRV_MID, "%s: alloc new_id: %s numeral flags = %d\n", 4866 fcn, numeral->id, numeral->flags); 4867 4868 4869 /* insert to head of list for fast lookups */ 4870 numeral->next = set->headnumeral; 4871 set->headnumeral = numeral; 4872 4873 *buf = s_strdup(numeral->id); 4874 return (DEVFSADM_SUCCESS); 4875 } 4876 4877 4878 /* 4879 * Looks up the specified cache for a match with a specified string 4880 * Returns: 4881 * -1 : on error. 4882 * 0/1/2 : Number of matches. 4883 * Returns the matching element only if there is a single match. 4884 * If the "uncached" flag is set, derives the "cmp_str" afresh 4885 * for the match instead of using cached values. 4886 */ 4887 static int 4888 lookup_enum_cache(numeral_set_t *set, char *cmp_str, 4889 devfsadm_enumerate_t rules[], int index, numeral_t **matchnpp) 4890 { 4891 int matchcount = 0, rv = -1; 4892 int uncached; 4893 numeral_t *np; 4894 char *fcn = "lookup_enum_cache"; 4895 char *cp; 4896 4897 *matchnpp = NULL; 4898 4899 assert(index < set->re_count); 4900 4901 if (cmp_str == NULL) { 4902 return (-1); 4903 } 4904 4905 uncached = 0; 4906 if ((rules[index].flags & MATCH_UNCACHED) == MATCH_UNCACHED) { 4907 uncached = 1; 4908 } 4909 4910 /* 4911 * Check and see if a matching entry is already cached. 4912 */ 4913 for (np = set->headnumeral; np != NULL; np = np->next) { 4914 4915 /* 4916 * Skip reserved IDs 4917 */ 4918 if (np->flags & NUMERAL_RESERVED) { 4919 vprint(RSRV_MID, "lookup_enum_cache: " 4920 "Cannot Match with reserved ID (%s), " 4921 "skipping\n", np->id); 4922 assert(np->flags == NUMERAL_RESERVED); 4923 continue; 4924 } else { 4925 vprint(RSRV_MID, "lookup_enum_cache: " 4926 "Attempting match with numeral ID: %s" 4927 " numeral flags = %d\n", np->id, np->flags); 4928 assert(np->flags == 0); 4929 } 4930 4931 if (np->cmp_str == NULL) { 4932 vprint(ENUM_MID, "%s: invalid entry in enumerate" 4933 " cache. path: %s\n", fcn, np->full_path); 4934 return (-1); 4935 } 4936 4937 if (uncached) { 4938 vprint(CHATTY_MID, "%s: bypassing enumerate cache." 4939 " path: %s\n", fcn, cmp_str); 4940 cp = alloc_cmp_str(np->full_path, 4941 &rules[np->rule_index]); 4942 if (cp == NULL) 4943 return (-1); 4944 rv = strcmp(cmp_str, cp); 4945 free(cp); 4946 } else { 4947 rv = strcmp(cmp_str, np->cmp_str); 4948 } 4949 4950 if (rv == 0) { 4951 if (matchcount++ != 0) { 4952 break; /* more than 1 match. */ 4953 } 4954 *matchnpp = np; 4955 } 4956 } 4957 4958 return (matchcount); 4959 } 4960 4961 #ifdef DEBUG 4962 static void 4963 dump_enum_cache(numeral_set_t *setp) 4964 { 4965 int i; 4966 numeral_t *np; 4967 char *fcn = "dump_enum_cache"; 4968 4969 vprint(ENUM_MID, "%s: re_count = %d\n", fcn, setp->re_count); 4970 for (i = 0; i < setp->re_count; i++) { 4971 vprint(ENUM_MID, "%s: re[%d] = %s\n", fcn, i, setp->re[i]); 4972 } 4973 4974 for (np = setp->headnumeral; np != NULL; np = np->next) { 4975 vprint(ENUM_MID, "%s: id: %s\n", fcn, np->id); 4976 vprint(ENUM_MID, "%s: full_path: %s\n", fcn, np->full_path); 4977 vprint(ENUM_MID, "%s: rule_index: %d\n", fcn, np->rule_index); 4978 vprint(ENUM_MID, "%s: cmp_str: %s\n", fcn, np->cmp_str); 4979 vprint(ENUM_MID, "%s: flags: %d\n", fcn, np->flags); 4980 } 4981 } 4982 #endif 4983 4984 /* 4985 * For a given set of regular expressions in rules[], this function returns 4986 * either a previously cached struct numeral_set or it will create and 4987 * cache a new struct numeral_set. There is only one struct numeral_set 4988 * for the combination of REs present in rules[]. Each numeral_set contains 4989 * the regular expressions in rules[] used for cache selection AND a linked 4990 * list of struct numerals, ONE FOR EACH *UNIQUE* numeral or character ID 4991 * selected by the grouping parenthesized subexpression found in the last 4992 * path component of each rules[].re. For example, the RE: "rmt/([0-9]+)" 4993 * selects all the logical nodes of the correct form in dev/rmt/. 4994 * Each rmt/X will store a *single* struct numeral... ie 0, 1, 2 each get a 4995 * single struct numeral. There is no need to store more than a single logical 4996 * node matching X since the information desired in the devfspath would be 4997 * identical for the portion of the devfspath of interest. (the part up to, 4998 * but not including the minor name in this example.) 4999 * 5000 * If the given numeral_set is not yet cached, call enumerate_recurse to 5001 * create it. 5002 */ 5003 static numeral_set_t * 5004 get_enum_cache(devfsadm_enumerate_t rules[], int nrules) 5005 { 5006 /* linked list of numeral sets */ 5007 numeral_set_t *setp; 5008 int i; 5009 int ret; 5010 char *path_left; 5011 enumerate_file_t *entry; 5012 char *fcn = "get_enum_cache"; 5013 5014 /* 5015 * See if we've already cached this numeral set. 5016 */ 5017 for (setp = head_numeral_set; setp != NULL; setp = setp->next) { 5018 /* 5019 * check all regexp's passed in function against 5020 * those in cached set. 5021 */ 5022 if (nrules != setp->re_count) { 5023 continue; 5024 } 5025 5026 for (i = 0; i < nrules; i++) { 5027 if (strcmp(setp->re[i], rules[i].re) != 0) { 5028 break; 5029 } 5030 } 5031 5032 if (i == nrules) { 5033 return (setp); 5034 } 5035 } 5036 5037 /* 5038 * If the MATCH_UNCACHED flag is set, we should not be here. 5039 */ 5040 for (i = 0; i < nrules; i++) { 5041 if ((rules[i].flags & MATCH_UNCACHED) == MATCH_UNCACHED) { 5042 vprint(ENUM_MID, "%s: invalid enumeration flags: " 5043 "0x%x\n", fcn, rules[i].flags); 5044 return (NULL); 5045 } 5046 } 5047 5048 /* 5049 * Since we made it here, we have not yet cached the given set of 5050 * logical nodes matching the passed re. Create a cached entry 5051 * struct numeral_set and populate it with a minimal set of 5052 * logical nodes from /dev. 5053 */ 5054 5055 setp = s_malloc(sizeof (numeral_set_t)); 5056 setp->re = s_malloc(sizeof (char *) * nrules); 5057 for (i = 0; i < nrules; i++) { 5058 setp->re[i] = s_strdup(rules[i].re); 5059 } 5060 setp->re_count = nrules; 5061 setp->headnumeral = NULL; 5062 5063 /* put this new cached set on the cached set list */ 5064 setp->next = head_numeral_set; 5065 head_numeral_set = setp; 5066 5067 /* 5068 * For each RE, search the "reserved" list to create numeral IDs that 5069 * are reserved. 5070 */ 5071 for (entry = enumerate_reserved; entry; entry = entry->er_next) { 5072 5073 vprint(RSRV_MID, "parsing rstring: %s\n", entry->er_file); 5074 5075 for (i = 0; i < nrules; i++) { 5076 path_left = s_strdup(setp->re[i]); 5077 vprint(RSRV_MID, "parsing rule RE: %s\n", path_left); 5078 ret = enumerate_parse(entry->er_file, path_left, 5079 setp, rules, i); 5080 free(path_left); 5081 if (ret == 1) { 5082 /* 5083 * We found the reserved ID for this entry. 5084 * We still keep the entry since it is needed 5085 * by the new link bypass code in disks 5086 */ 5087 vprint(RSRV_MID, "found rsv ID: rstring: %s " 5088 "rule RE: %s\n", entry->er_file, path_left); 5089 break; 5090 } 5091 } 5092 } 5093 5094 /* 5095 * For each RE, search disk and cache any matches on the 5096 * numeral list. 5097 */ 5098 for (i = 0; i < nrules; i++) { 5099 path_left = s_strdup(setp->re[i]); 5100 enumerate_recurse(dev_dir, path_left, setp, rules, i); 5101 free(path_left); 5102 } 5103 5104 #ifdef DEBUG 5105 dump_enum_cache(setp); 5106 #endif 5107 5108 return (setp); 5109 } 5110 5111 5112 /* 5113 * This function stats the pathname namebuf. If this is a directory 5114 * entry, we recurse down dname/fname until we find the first symbolic 5115 * link, and then stat and return it. This is valid for the same reason 5116 * that we only need to read a single pathname for multiple matching 5117 * logical ID's... ie, all the logical nodes should contain identical 5118 * physical paths for the parts we are interested. 5119 */ 5120 int 5121 get_stat_info(char *namebuf, struct stat *sb) 5122 { 5123 char *cp; 5124 finddevhdl_t fhandle; 5125 const char *fp; 5126 5127 if (lstat(namebuf, sb) < 0) { 5128 (void) err_print(LSTAT_FAILED, namebuf, strerror(errno)); 5129 return (DEVFSADM_FAILURE); 5130 } 5131 5132 if ((sb->st_mode & S_IFMT) == S_IFLNK) { 5133 return (DEVFSADM_SUCCESS); 5134 } 5135 5136 /* 5137 * If it is a dir, recurse down until we find a link and 5138 * then use the link. 5139 */ 5140 if ((sb->st_mode & S_IFMT) == S_IFDIR) { 5141 5142 if (finddev_readdir(namebuf, &fhandle) != 0) { 5143 return (DEVFSADM_FAILURE); 5144 } 5145 5146 /* 5147 * Search each dir entry looking for a symlink. Return 5148 * the first symlink found in namebuf. Recurse dirs. 5149 */ 5150 while ((fp = finddev_next(fhandle)) != NULL) { 5151 cp = namebuf + strlen(namebuf); 5152 if ((strlcat(namebuf, "/", PATH_MAX) >= PATH_MAX) || 5153 (strlcat(namebuf, fp, PATH_MAX) >= PATH_MAX)) { 5154 *cp = '\0'; 5155 finddev_close(fhandle); 5156 return (DEVFSADM_FAILURE); 5157 } 5158 if (get_stat_info(namebuf, sb) == DEVFSADM_SUCCESS) { 5159 finddev_close(fhandle); 5160 return (DEVFSADM_SUCCESS); 5161 } 5162 *cp = '\0'; 5163 } 5164 finddev_close(fhandle); 5165 } 5166 5167 /* no symlink found, so return error */ 5168 return (DEVFSADM_FAILURE); 5169 } 5170 5171 /* 5172 * An existing matching ID was not found, so this function is called to 5173 * create the next lowest ID. In the INTEGER case, return the next 5174 * lowest unused integer. In the case of LETTER, return the next lowest 5175 * unused letter. Return empty string if all 26 are used. 5176 * Only IDs >= min will be returned. 5177 */ 5178 char * 5179 new_id(numeral_t *numeral, int type, char *min) 5180 { 5181 int imin; 5182 temp_t *temp; 5183 temp_t *ptr; 5184 temp_t **previous; 5185 temp_t *head = NULL; 5186 char *retval; 5187 static char tempbuff[8]; 5188 numeral_t *np; 5189 5190 if (type == LETTER) { 5191 5192 char letter[26], i; 5193 5194 if (numeral == NULL) { 5195 return (s_strdup(min)); 5196 } 5197 5198 for (i = 0; i < 26; i++) { 5199 letter[i] = 0; 5200 } 5201 5202 for (np = numeral; np != NULL; np = np->next) { 5203 assert(np->flags == 0 || 5204 np->flags == NUMERAL_RESERVED); 5205 letter[*np->id - 'a']++; 5206 } 5207 5208 imin = *min - 'a'; 5209 5210 for (i = imin; i < 26; i++) { 5211 if (letter[i] == 0) { 5212 retval = s_malloc(2); 5213 retval[0] = 'a' + i; 5214 retval[1] = '\0'; 5215 return (retval); 5216 } 5217 } 5218 5219 return (s_strdup("")); 5220 } 5221 5222 if (type == INTEGER) { 5223 5224 if (numeral == NULL) { 5225 return (s_strdup(min)); 5226 } 5227 5228 imin = atoi(min); 5229 5230 /* sort list */ 5231 for (np = numeral; np != NULL; np = np->next) { 5232 assert(np->flags == 0 || 5233 np->flags == NUMERAL_RESERVED); 5234 temp = s_malloc(sizeof (temp_t)); 5235 temp->integer = atoi(np->id); 5236 temp->next = NULL; 5237 5238 previous = &head; 5239 for (ptr = head; ptr != NULL; ptr = ptr->next) { 5240 if (temp->integer < ptr->integer) { 5241 temp->next = ptr; 5242 *previous = temp; 5243 break; 5244 } 5245 previous = &(ptr->next); 5246 } 5247 if (ptr == NULL) { 5248 *previous = temp; 5249 } 5250 } 5251 5252 /* now search sorted list for first hole >= imin */ 5253 for (ptr = head; ptr != NULL; ptr = ptr->next) { 5254 if (imin == ptr->integer) { 5255 imin++; 5256 } else { 5257 if (imin < ptr->integer) { 5258 break; 5259 } 5260 } 5261 5262 } 5263 5264 /* free temp list */ 5265 for (ptr = head; ptr != NULL; ) { 5266 temp = ptr; 5267 ptr = ptr->next; 5268 free(temp); 5269 } 5270 5271 (void) sprintf(tempbuff, "%d", imin); 5272 return (s_strdup(tempbuff)); 5273 } 5274 5275 return (s_strdup("")); 5276 } 5277 5278 static int 5279 enumerate_parse(char *rsvstr, char *path_left, numeral_set_t *setp, 5280 devfsadm_enumerate_t rules[], int index) 5281 { 5282 char *slash1 = NULL; 5283 char *slash2 = NULL; 5284 char *numeral_id; 5285 char *path_left_save; 5286 char *rsvstr_save; 5287 int ret = 0; 5288 static int warned = 0; 5289 5290 rsvstr_save = rsvstr; 5291 path_left_save = path_left; 5292 5293 if (rsvstr == NULL || rsvstr[0] == '\0' || rsvstr[0] == '/') { 5294 if (!warned) { 5295 err_print("invalid reserved filepath: %s\n", 5296 rsvstr ? rsvstr : "<NULL>"); 5297 warned = 1; 5298 } 5299 return (0); 5300 } 5301 5302 vprint(RSRV_MID, "processing rule: %s, rstring: %s\n", 5303 path_left, rsvstr); 5304 5305 5306 for (;;) { 5307 /* get rid of any extra '/' in the reserve string */ 5308 while (*rsvstr == '/') { 5309 rsvstr++; 5310 } 5311 5312 /* get rid of any extra '/' in the RE */ 5313 while (*path_left == '/') { 5314 path_left++; 5315 } 5316 5317 if (slash1 = strchr(path_left, '/')) { 5318 *slash1 = '\0'; 5319 } 5320 if (slash2 = strchr(rsvstr, '/')) { 5321 *slash2 = '\0'; 5322 } 5323 5324 if ((slash1 != NULL) ^ (slash2 != NULL)) { 5325 ret = 0; 5326 vprint(RSRV_MID, "mismatch in # of path components\n"); 5327 goto out; 5328 } 5329 5330 /* 5331 * Returns true if path_left matches the list entry. 5332 * If it is the last path component, pass subexp 5333 * so that it will return the corresponding ID in 5334 * numeral_id. 5335 */ 5336 numeral_id = NULL; 5337 if (match_path_component(path_left, rsvstr, &numeral_id, 5338 slash1 ? 0 : rules[index].subexp)) { 5339 5340 /* We have a match. */ 5341 if (slash1 == NULL) { 5342 /* Is last path component */ 5343 vprint(RSRV_MID, "match and last component\n"); 5344 create_reserved_numeral(setp, numeral_id); 5345 if (numeral_id != NULL) { 5346 free(numeral_id); 5347 } 5348 ret = 1; 5349 goto out; 5350 } else { 5351 /* Not last path component. Continue parsing */ 5352 *slash1 = '/'; 5353 *slash2 = '/'; 5354 path_left = slash1 + 1; 5355 rsvstr = slash2 + 1; 5356 vprint(RSRV_MID, 5357 "match and NOT last component\n"); 5358 continue; 5359 } 5360 } else { 5361 /* No match */ 5362 ret = 0; 5363 vprint(RSRV_MID, "No match: rule RE = %s, " 5364 "rstring = %s\n", path_left, rsvstr); 5365 goto out; 5366 } 5367 } 5368 5369 out: 5370 if (slash1) 5371 *slash1 = '/'; 5372 if (slash2) 5373 *slash2 = '/'; 5374 5375 if (ret == 1) { 5376 vprint(RSRV_MID, "match: rule RE: %s, rstring: %s\n", 5377 path_left_save, rsvstr_save); 5378 } else { 5379 vprint(RSRV_MID, "NO match: rule RE: %s, rstring: %s\n", 5380 path_left_save, rsvstr_save); 5381 } 5382 5383 return (ret); 5384 } 5385 5386 /* 5387 * Search current_dir for all files which match the first path component 5388 * of path_left, which is an RE. If a match is found, but there are more 5389 * components of path_left, then recurse, otherwise, if we have reached 5390 * the last component of path_left, call create_cached_numerals for each 5391 * file. At some point, recurse_dev_re() should be rewritten so that this 5392 * function can be eliminated. 5393 */ 5394 static void 5395 enumerate_recurse(char *current_dir, char *path_left, numeral_set_t *setp, 5396 devfsadm_enumerate_t rules[], int index) 5397 { 5398 char *slash; 5399 char *new_path; 5400 char *numeral_id; 5401 finddevhdl_t fhandle; 5402 const char *fp; 5403 5404 if (finddev_readdir(current_dir, &fhandle) != 0) { 5405 return; 5406 } 5407 5408 /* get rid of any extra '/' */ 5409 while (*path_left == '/') { 5410 path_left++; 5411 } 5412 5413 if (slash = strchr(path_left, '/')) { 5414 *slash = '\0'; 5415 } 5416 5417 while ((fp = finddev_next(fhandle)) != NULL) { 5418 5419 /* 5420 * Returns true if path_left matches the list entry. 5421 * If it is the last path component, pass subexp 5422 * so that it will return the corresponding ID in 5423 * numeral_id. 5424 */ 5425 numeral_id = NULL; 5426 if (match_path_component(path_left, (char *)fp, &numeral_id, 5427 slash ? 0 : rules[index].subexp)) { 5428 5429 new_path = s_malloc(strlen(current_dir) + 5430 strlen(fp) + 2); 5431 5432 (void) strcpy(new_path, current_dir); 5433 (void) strcat(new_path, "/"); 5434 (void) strcat(new_path, fp); 5435 5436 if (slash != NULL) { 5437 enumerate_recurse(new_path, slash + 1, 5438 setp, rules, index); 5439 } else { 5440 create_cached_numeral(new_path, setp, 5441 numeral_id, rules, index); 5442 if (numeral_id != NULL) { 5443 free(numeral_id); 5444 } 5445 } 5446 free(new_path); 5447 } 5448 } 5449 5450 if (slash != NULL) { 5451 *slash = '/'; 5452 } 5453 finddev_close(fhandle); 5454 } 5455 5456 5457 /* 5458 * Returns true if file matches file_re. If subexp is non-zero, it means 5459 * we are searching the last path component and need to return the 5460 * parenthesized subexpression subexp in id. 5461 * 5462 */ 5463 static int 5464 match_path_component(char *file_re, char *file, char **id, int subexp) 5465 { 5466 regex_t re1; 5467 int match = 0; 5468 int nelements; 5469 regmatch_t *pmatch; 5470 5471 if (subexp != 0) { 5472 nelements = subexp + 1; 5473 pmatch = (regmatch_t *) 5474 s_malloc(sizeof (regmatch_t) * nelements); 5475 } else { 5476 pmatch = NULL; 5477 nelements = 0; 5478 } 5479 5480 if (regcomp(&re1, file_re, REG_EXTENDED) != 0) { 5481 if (pmatch != NULL) { 5482 free(pmatch); 5483 } 5484 return (0); 5485 } 5486 5487 if (regexec(&re1, file, nelements, pmatch, 0) == 0) { 5488 match = 1; 5489 } 5490 5491 if ((match != 0) && (subexp != 0)) { 5492 int size = pmatch[subexp].rm_eo - pmatch[subexp].rm_so; 5493 *id = s_malloc(size + 1); 5494 (void) strncpy(*id, &file[pmatch[subexp].rm_so], size); 5495 (*id)[size] = '\0'; 5496 } 5497 5498 if (pmatch != NULL) { 5499 free(pmatch); 5500 } 5501 regfree(&re1); 5502 return (match); 5503 } 5504 5505 static void 5506 create_reserved_numeral(numeral_set_t *setp, char *numeral_id) 5507 { 5508 numeral_t *np; 5509 5510 vprint(RSRV_MID, "Attempting to create reserved numeral: %s\n", 5511 numeral_id); 5512 5513 /* 5514 * We found a numeral_id from an entry in the enumerate_reserved file 5515 * which matched the re passed in from devfsadm_enumerate. We only 5516 * need to make sure ONE copy of numeral_id exists on the numeral list. 5517 * We only need to store /dev/dsk/cNtod0s0 and no other entries 5518 * hanging off of controller N. 5519 */ 5520 for (np = setp->headnumeral; np != NULL; np = np->next) { 5521 if (strcmp(numeral_id, np->id) == 0) { 5522 vprint(RSRV_MID, "ID: %s, already reserved\n", np->id); 5523 assert(np->flags == NUMERAL_RESERVED); 5524 return; 5525 } else { 5526 assert(np->flags == 0 || 5527 np->flags == NUMERAL_RESERVED); 5528 } 5529 } 5530 5531 /* NOT on list, so add it */ 5532 np = s_malloc(sizeof (numeral_t)); 5533 np->id = s_strdup(numeral_id); 5534 np->full_path = NULL; 5535 np->rule_index = 0; 5536 np->cmp_str = NULL; 5537 np->flags = NUMERAL_RESERVED; 5538 np->next = setp->headnumeral; 5539 setp->headnumeral = np; 5540 5541 vprint(RSRV_MID, "Reserved numeral ID: %s\n", np->id); 5542 } 5543 5544 /* 5545 * This function is called for every file which matched the leaf 5546 * component of the RE. If the "numeral_id" is not already on the 5547 * numeral set's numeral list, add it and its physical path. 5548 */ 5549 static void 5550 create_cached_numeral(char *path, numeral_set_t *setp, char *numeral_id, 5551 devfsadm_enumerate_t rules[], int index) 5552 { 5553 char linkbuf[PATH_MAX + 1]; 5554 char lpath[PATH_MAX + 1]; 5555 char *linkptr, *cmp_str; 5556 numeral_t *np; 5557 int linksize; 5558 struct stat sb; 5559 const char *fcn = "create_cached_numeral"; 5560 5561 assert(index >= 0 && index < setp->re_count); 5562 assert(strcmp(rules[index].re, setp->re[index]) == 0); 5563 5564 /* 5565 * We found a numeral_id from an entry in /dev which matched 5566 * the re passed in from devfsadm_enumerate. We only need to make sure 5567 * ONE copy of numeral_id exists on the numeral list. We only need 5568 * to store /dev/dsk/cNtod0s0 and no other entries hanging off 5569 * of controller N. 5570 */ 5571 for (np = setp->headnumeral; np != NULL; np = np->next) { 5572 assert(np->flags == 0 || np->flags == NUMERAL_RESERVED); 5573 if (strcmp(numeral_id, np->id) == 0) { 5574 /* 5575 * Note that we can't assert that the flags field 5576 * of the numeral is 0, since both reserved and 5577 * unreserved links in /dev come here 5578 */ 5579 if (np->flags == NUMERAL_RESERVED) { 5580 vprint(RSRV_MID, "ID derived from /dev link is" 5581 " reserved: %s\n", np->id); 5582 } else { 5583 vprint(RSRV_MID, "ID derived from /dev link is" 5584 " NOT reserved: %s\n", np->id); 5585 } 5586 return; 5587 } 5588 } 5589 5590 /* NOT on list, so add it */ 5591 5592 (void) strcpy(lpath, path); 5593 /* 5594 * If path is a dir, it is changed to the first symbolic link it find 5595 * if it finds one. 5596 */ 5597 if (get_stat_info(lpath, &sb) == DEVFSADM_FAILURE) { 5598 return; 5599 } 5600 5601 /* If we get here, we found a symlink */ 5602 linksize = readlink(lpath, linkbuf, PATH_MAX); 5603 5604 if (linksize <= 0) { 5605 err_print(READLINK_FAILED, fcn, lpath, strerror(errno)); 5606 return; 5607 } 5608 5609 linkbuf[linksize] = '\0'; 5610 5611 /* 5612 * the following just points linkptr to the root of the /devices 5613 * node if it is a minor node, otherwise, to the first char of 5614 * linkbuf if it is a link. 5615 */ 5616 (void) is_minor_node(linkbuf, &linkptr); 5617 5618 cmp_str = alloc_cmp_str(linkptr, &rules[index]); 5619 if (cmp_str == NULL) { 5620 return; 5621 } 5622 5623 np = s_malloc(sizeof (numeral_t)); 5624 5625 np->id = s_strdup(numeral_id); 5626 np->full_path = s_strdup(linkptr); 5627 np->rule_index = index; 5628 np->cmp_str = cmp_str; 5629 np->flags = 0; 5630 5631 np->next = setp->headnumeral; 5632 setp->headnumeral = np; 5633 } 5634 5635 5636 /* 5637 * This should be called either before or after granting access to a 5638 * command line version of devfsadm running, since it may have changed 5639 * the state of /dev. It forces future enumerate calls to re-build 5640 * cached information from /dev. 5641 */ 5642 void 5643 invalidate_enumerate_cache(void) 5644 { 5645 numeral_set_t *setp; 5646 numeral_set_t *savedsetp; 5647 numeral_t *savednumset; 5648 numeral_t *numset; 5649 int i; 5650 5651 for (setp = head_numeral_set; setp != NULL; ) { 5652 /* 5653 * check all regexp's passed in function against 5654 * those in cached set. 5655 */ 5656 5657 savedsetp = setp; 5658 setp = setp->next; 5659 5660 for (i = 0; i < savedsetp->re_count; i++) { 5661 free(savedsetp->re[i]); 5662 } 5663 free(savedsetp->re); 5664 5665 for (numset = savedsetp->headnumeral; numset != NULL; ) { 5666 savednumset = numset; 5667 numset = numset->next; 5668 assert(savednumset->rule_index < savedsetp->re_count); 5669 free(savednumset->id); 5670 free(savednumset->full_path); 5671 free(savednumset->cmp_str); 5672 free(savednumset); 5673 } 5674 free(savedsetp); 5675 } 5676 head_numeral_set = NULL; 5677 } 5678 5679 /* 5680 * Copies over links from /dev to <root>/dev and device special files in 5681 * /devices to <root>/devices, preserving the existing file modes. If 5682 * the link or special file already exists on <root>, skip the copy. (it 5683 * would exist only if a package hard coded it there, so assume package 5684 * knows best?). Use /etc/name_to_major and <root>/etc/name_to_major to 5685 * make translations for major numbers on device special files. No need to 5686 * make a translation on minor_perm since if the file was created in the 5687 * miniroot then it would presumably have the same minor_perm entry in 5688 * <root>/etc/minor_perm. To be used only by install. 5689 */ 5690 int 5691 devfsadm_copy(void) 5692 { 5693 char filename[PATH_MAX + 1]; 5694 5695 /* load the installed root's name_to_major for translations */ 5696 (void) snprintf(filename, sizeof (filename), "%s%s", root_dir, 5697 NAME_TO_MAJOR); 5698 if (load_n2m_table(filename) == DEVFSADM_FAILURE) { 5699 return (DEVFSADM_FAILURE); 5700 } 5701 5702 /* Copy /dev to target disk. No need to copy /devices with devfs */ 5703 (void) nftw(DEV, devfsadm_copy_file, 20, FTW_PHYS); 5704 5705 /* Let install handle copying over path_to_inst */ 5706 5707 return (DEVFSADM_SUCCESS); 5708 } 5709 5710 /* 5711 * This function copies links, dirs, and device special files. 5712 * Note that it always returns DEVFSADM_SUCCESS, so that nftw doesn't 5713 * abort. 5714 */ 5715 /*ARGSUSED*/ 5716 static int 5717 devfsadm_copy_file(const char *file, const struct stat *stat, 5718 int flags, struct FTW *ftw) 5719 { 5720 struct stat sp; 5721 dev_t newdev; 5722 char newfile[PATH_MAX + 1]; 5723 char linkcontents[PATH_MAX + 1]; 5724 int bytes; 5725 const char *fcn = "devfsadm_copy_file"; 5726 5727 (void) strcpy(newfile, root_dir); 5728 (void) strcat(newfile, "/"); 5729 (void) strcat(newfile, file); 5730 5731 if (lstat(newfile, &sp) == 0) { 5732 /* newfile already exists, so no need to continue */ 5733 return (DEVFSADM_SUCCESS); 5734 } 5735 5736 if (((stat->st_mode & S_IFMT) == S_IFBLK) || 5737 ((stat->st_mode & S_IFMT) == S_IFCHR)) { 5738 if (translate_major(stat->st_rdev, &newdev) == 5739 DEVFSADM_FAILURE) { 5740 return (DEVFSADM_SUCCESS); 5741 } 5742 if (mknod(newfile, stat->st_mode, newdev) == -1) { 5743 err_print(MKNOD_FAILED, newfile, strerror(errno)); 5744 return (DEVFSADM_SUCCESS); 5745 } 5746 } else if ((stat->st_mode & S_IFMT) == S_IFDIR) { 5747 if (mknod(newfile, stat->st_mode, 0) == -1) { 5748 err_print(MKNOD_FAILED, newfile, strerror(errno)); 5749 return (DEVFSADM_SUCCESS); 5750 } 5751 } else if ((stat->st_mode & S_IFMT) == S_IFLNK) { 5752 if ((bytes = readlink(file, linkcontents, PATH_MAX)) == -1) { 5753 err_print(READLINK_FAILED, fcn, file, strerror(errno)); 5754 return (DEVFSADM_SUCCESS); 5755 } 5756 linkcontents[bytes] = '\0'; 5757 if (symlink(linkcontents, newfile) == -1) { 5758 err_print(SYMLINK_FAILED, newfile, newfile, 5759 strerror(errno)); 5760 return (DEVFSADM_SUCCESS); 5761 } 5762 } 5763 5764 (void) lchown(newfile, stat->st_uid, stat->st_gid); 5765 return (DEVFSADM_SUCCESS); 5766 } 5767 5768 /* 5769 * Given a dev_t from the running kernel, return the new_dev_t 5770 * by translating to the major number found on the installed 5771 * target's root name_to_major file. 5772 */ 5773 static int 5774 translate_major(dev_t old_dev, dev_t *new_dev) 5775 { 5776 major_t oldmajor; 5777 major_t newmajor; 5778 minor_t oldminor; 5779 minor_t newminor; 5780 char cdriver[FILENAME_MAX + 1]; 5781 char driver[FILENAME_MAX + 1]; 5782 char *fcn = "translate_major: "; 5783 5784 oldmajor = major(old_dev); 5785 if (modctl(MODGETNAME, driver, sizeof (driver), 5786 &oldmajor) != 0) { 5787 return (DEVFSADM_FAILURE); 5788 } 5789 5790 if (strcmp(driver, "clone") != 0) { 5791 /* non-clone case */ 5792 5793 /* look up major number is target's name2major */ 5794 if (get_major_no(driver, &newmajor) == DEVFSADM_FAILURE) { 5795 return (DEVFSADM_FAILURE); 5796 } 5797 5798 *new_dev = makedev(newmajor, minor(old_dev)); 5799 if (old_dev != *new_dev) { 5800 vprint(CHATTY_MID, "%sdriver: %s old: %lu,%lu " 5801 "new: %lu,%lu\n", fcn, driver, major(old_dev), 5802 minor(old_dev), major(*new_dev), 5803 minor(*new_dev)); 5804 } 5805 return (DEVFSADM_SUCCESS); 5806 } else { 5807 /* 5808 * The clone is a special case. Look at its minor 5809 * number since it is the major number of the real driver. 5810 */ 5811 if (get_major_no(driver, &newmajor) == DEVFSADM_FAILURE) { 5812 return (DEVFSADM_FAILURE); 5813 } 5814 5815 oldminor = minor(old_dev); 5816 if (modctl(MODGETNAME, cdriver, sizeof (cdriver), 5817 &oldminor) != 0) { 5818 err_print(MODGETNAME_FAILED, oldminor); 5819 return (DEVFSADM_FAILURE); 5820 } 5821 5822 if (get_major_no(cdriver, &newminor) == DEVFSADM_FAILURE) { 5823 return (DEVFSADM_FAILURE); 5824 } 5825 5826 *new_dev = makedev(newmajor, newminor); 5827 if (old_dev != *new_dev) { 5828 vprint(CHATTY_MID, "%sdriver: %s old: " 5829 "%lu,%lu new: %lu,%lu\n", fcn, driver, 5830 major(old_dev), minor(old_dev), 5831 major(*new_dev), minor(*new_dev)); 5832 } 5833 return (DEVFSADM_SUCCESS); 5834 } 5835 } 5836 5837 /* 5838 * 5839 * Find the major number for driver, searching the n2m_list that was 5840 * built in load_n2m_table(). 5841 */ 5842 static int 5843 get_major_no(char *driver, major_t *major) 5844 { 5845 n2m_t *ptr; 5846 5847 for (ptr = n2m_list; ptr != NULL; ptr = ptr->next) { 5848 if (strcmp(ptr->driver, driver) == 0) { 5849 *major = ptr->major; 5850 return (DEVFSADM_SUCCESS); 5851 } 5852 } 5853 err_print(FIND_MAJOR_FAILED, driver); 5854 return (DEVFSADM_FAILURE); 5855 } 5856 5857 /* 5858 * Loads a name_to_major table into memory. Used only for suninstall's 5859 * private -R option to devfsadm, to translate major numbers from the 5860 * running to the installed target disk. 5861 */ 5862 static int 5863 load_n2m_table(char *file) 5864 { 5865 FILE *fp; 5866 char line[1024], *cp; 5867 char driver[PATH_MAX + 1]; 5868 major_t major; 5869 n2m_t *ptr; 5870 int ln = 0; 5871 5872 if ((fp = fopen(file, "r")) == NULL) { 5873 err_print(FOPEN_FAILED, file, strerror(errno)); 5874 return (DEVFSADM_FAILURE); 5875 } 5876 5877 while (fgets(line, sizeof (line), fp) != NULL) { 5878 ln++; 5879 /* cut off comments starting with '#' */ 5880 if ((cp = strchr(line, '#')) != NULL) 5881 *cp = '\0'; 5882 /* ignore comment or blank lines */ 5883 if (is_blank(line)) 5884 continue; 5885 /* sanity-check */ 5886 if (sscanf(line, "%1024s%lu", driver, &major) != 2) { 5887 err_print(IGNORING_LINE_IN, ln, file); 5888 continue; 5889 } 5890 ptr = (n2m_t *)s_malloc(sizeof (n2m_t)); 5891 ptr->major = major; 5892 ptr->driver = s_strdup(driver); 5893 ptr->next = n2m_list; 5894 n2m_list = ptr; 5895 } 5896 if (fclose(fp) == EOF) { 5897 err_print(FCLOSE_FAILED, file, strerror(errno)); 5898 } 5899 return (DEVFSADM_SUCCESS); 5900 } 5901 5902 /* 5903 * Called at devfsadm startup to read the file /etc/dev/enumerate_reserved 5904 * Creates a linked list of devlinks from which reserved IDs can be derived 5905 */ 5906 static void 5907 read_enumerate_file(void) 5908 { 5909 FILE *fp; 5910 int linenum; 5911 char line[PATH_MAX+1]; 5912 enumerate_file_t *entry; 5913 struct stat current_sb; 5914 static struct stat cached_sb; 5915 static int cached = FALSE; 5916 5917 assert(enumerate_file); 5918 5919 if (stat(enumerate_file, ¤t_sb) == -1) { 5920 vprint(RSRV_MID, "No reserved file: %s\n", enumerate_file); 5921 cached = FALSE; 5922 if (enumerate_reserved != NULL) { 5923 vprint(RSRV_MID, "invalidating %s cache\n", 5924 enumerate_file); 5925 } 5926 while (enumerate_reserved != NULL) { 5927 entry = enumerate_reserved; 5928 enumerate_reserved = entry->er_next; 5929 free(entry->er_file); 5930 free(entry->er_id); 5931 free(entry); 5932 } 5933 return; 5934 } 5935 5936 /* if already cached, check to see if it is still valid */ 5937 if (cached == TRUE) { 5938 5939 if (current_sb.st_mtime == cached_sb.st_mtime) { 5940 vprint(RSRV_MID, "%s cache valid\n", enumerate_file); 5941 vprint(FILES_MID, "%s cache valid\n", enumerate_file); 5942 return; 5943 } 5944 5945 vprint(RSRV_MID, "invalidating %s cache\n", enumerate_file); 5946 vprint(FILES_MID, "invalidating %s cache\n", enumerate_file); 5947 5948 while (enumerate_reserved != NULL) { 5949 entry = enumerate_reserved; 5950 enumerate_reserved = entry->er_next; 5951 free(entry->er_file); 5952 free(entry->er_id); 5953 free(entry); 5954 } 5955 vprint(RSRV_MID, "Recaching file: %s\n", enumerate_file); 5956 } else { 5957 vprint(RSRV_MID, "Caching file (first time): %s\n", 5958 enumerate_file); 5959 cached = TRUE; 5960 } 5961 5962 (void) stat(enumerate_file, &cached_sb); 5963 5964 if ((fp = fopen(enumerate_file, "r")) == NULL) { 5965 err_print(FOPEN_FAILED, enumerate_file, strerror(errno)); 5966 return; 5967 } 5968 5969 vprint(RSRV_MID, "Reading reserve file: %s\n", enumerate_file); 5970 linenum = 0; 5971 while (fgets(line, sizeof (line), fp) != NULL) { 5972 char *cp, *ncp; 5973 5974 linenum++; 5975 5976 /* remove newline */ 5977 cp = strchr(line, '\n'); 5978 if (cp) 5979 *cp = '\0'; 5980 5981 vprint(RSRV_MID, "Reserve file: line %d: %s\n", 5982 linenum, line); 5983 5984 /* skip over space and tab */ 5985 for (cp = line; *cp == ' ' || *cp == '\t'; cp++); 5986 5987 if (*cp == '\0' || *cp == '#') { 5988 vprint(RSRV_MID, "Skipping line: '%s'\n", line); 5989 continue; /* blank line or comment line */ 5990 } 5991 5992 ncp = cp; 5993 5994 /* delete trailing blanks */ 5995 for (; *cp != ' ' && *cp != '\t' && *cp != '\0'; cp++); 5996 *cp = '\0'; 5997 5998 entry = s_zalloc(sizeof (enumerate_file_t)); 5999 entry->er_file = s_strdup(ncp); 6000 entry->er_id = NULL; 6001 entry->er_next = enumerate_reserved; 6002 enumerate_reserved = entry; 6003 } 6004 6005 if (fclose(fp) == EOF) { 6006 err_print(FCLOSE_FAILED, enumerate_file, strerror(errno)); 6007 } 6008 } 6009 6010 /* 6011 * Called at devfsadm startup to read in the devlink.tab file. Creates 6012 * a linked list of devlinktab_list structures which will be 6013 * searched for every minor node. 6014 */ 6015 static void 6016 read_devlinktab_file(void) 6017 { 6018 devlinktab_list_t *headp = NULL; 6019 devlinktab_list_t *entryp; 6020 devlinktab_list_t **previous; 6021 devlinktab_list_t *save; 6022 char line[MAX_DEVLINK_LINE], *cp; 6023 char *selector; 6024 char *p_link; 6025 char *s_link; 6026 FILE *fp; 6027 int i; 6028 static struct stat cached_sb; 6029 struct stat current_sb; 6030 static int cached = FALSE; 6031 6032 if (devlinktab_file == NULL) { 6033 return; 6034 } 6035 6036 (void) stat(devlinktab_file, ¤t_sb); 6037 6038 /* if already cached, check to see if it is still valid */ 6039 if (cached == TRUE) { 6040 6041 if (current_sb.st_mtime == cached_sb.st_mtime) { 6042 vprint(FILES_MID, "%s cache valid\n", devlinktab_file); 6043 return; 6044 } 6045 6046 vprint(FILES_MID, "invalidating %s cache\n", devlinktab_file); 6047 6048 while (devlinktab_list != NULL) { 6049 free_link_list(devlinktab_list->p_link); 6050 free_link_list(devlinktab_list->s_link); 6051 free_selector_list(devlinktab_list->selector); 6052 free(devlinktab_list->selector_pattern); 6053 free(devlinktab_list->p_link_pattern); 6054 if (devlinktab_list->s_link_pattern != NULL) { 6055 free(devlinktab_list->s_link_pattern); 6056 } 6057 save = devlinktab_list; 6058 devlinktab_list = devlinktab_list->next; 6059 free(save); 6060 } 6061 } else { 6062 cached = TRUE; 6063 } 6064 6065 (void) stat(devlinktab_file, &cached_sb); 6066 6067 if ((fp = fopen(devlinktab_file, "r")) == NULL) { 6068 err_print(FOPEN_FAILED, devlinktab_file, strerror(errno)); 6069 return; 6070 } 6071 6072 previous = &headp; 6073 6074 while (fgets(line, sizeof (line), fp) != NULL) { 6075 devlinktab_line++; 6076 i = strlen(line); 6077 if (line[i-1] == NEWLINE) { 6078 line[i-1] = '\0'; 6079 } else if (i == sizeof (line-1)) { 6080 err_print(LINE_TOO_LONG, devlinktab_line, 6081 devlinktab_file, sizeof (line)-1); 6082 while (((i = getc(fp)) != '\n') && (i != EOF)); 6083 continue; 6084 } 6085 6086 /* cut off comments starting with '#' */ 6087 if ((cp = strchr(line, '#')) != NULL) 6088 *cp = '\0'; 6089 /* ignore comment or blank lines */ 6090 if (is_blank(line)) 6091 continue; 6092 6093 vprint(DEVLINK_MID, "table: %s line %d: '%s'\n", 6094 devlinktab_file, devlinktab_line, line); 6095 6096 /* break each entry into fields. s_link may be NULL */ 6097 if (split_devlinktab_entry(line, &selector, &p_link, 6098 &s_link) == DEVFSADM_FAILURE) { 6099 vprint(DEVLINK_MID, "split_entry returns failure\n"); 6100 continue; 6101 } else { 6102 vprint(DEVLINK_MID, "split_entry selector='%s' " 6103 "p_link='%s' s_link='%s'\n\n", selector, 6104 p_link, (s_link == NULL) ? "" : s_link); 6105 } 6106 6107 entryp = (devlinktab_list_t *) 6108 s_malloc(sizeof (devlinktab_list_t)); 6109 6110 entryp->line_number = devlinktab_line; 6111 6112 if ((entryp->selector = 6113 create_selector_list(selector)) == NULL) { 6114 free(entryp); 6115 continue; 6116 } 6117 entryp->selector_pattern = s_strdup(selector); 6118 6119 if ((entryp->p_link = create_link_list(p_link)) == NULL) { 6120 free_selector_list(entryp->selector); 6121 free(entryp->selector_pattern); 6122 free(entryp); 6123 continue; 6124 } 6125 6126 entryp->p_link_pattern = s_strdup(p_link); 6127 6128 if (s_link != NULL) { 6129 if ((entryp->s_link = 6130 create_link_list(s_link)) == NULL) { 6131 free_selector_list(entryp->selector); 6132 free_link_list(entryp->p_link); 6133 free(entryp->selector_pattern); 6134 free(entryp->p_link_pattern); 6135 free(entryp); 6136 continue; 6137 } 6138 entryp->s_link_pattern = s_strdup(s_link); 6139 } else { 6140 entryp->s_link = NULL; 6141 entryp->s_link_pattern = NULL; 6142 6143 } 6144 6145 /* append to end of list */ 6146 6147 entryp->next = NULL; 6148 *previous = entryp; 6149 previous = &(entryp->next); 6150 } 6151 if (fclose(fp) == EOF) { 6152 err_print(FCLOSE_FAILED, devlinktab_file, strerror(errno)); 6153 } 6154 devlinktab_list = headp; 6155 } 6156 6157 /* 6158 * 6159 * For a single line entry in devlink.tab, split the line into fields 6160 * selector, p_link, and an optionally s_link. If s_link field is not 6161 * present, then return NULL in s_link (not NULL string). 6162 */ 6163 static int 6164 split_devlinktab_entry(char *entry, char **selector, char **p_link, 6165 char **s_link) 6166 { 6167 char *tab; 6168 6169 *selector = entry; 6170 6171 if ((tab = strchr(entry, TAB)) != NULL) { 6172 *tab = '\0'; 6173 *p_link = ++tab; 6174 } else { 6175 err_print(MISSING_TAB, devlinktab_line, devlinktab_file); 6176 return (DEVFSADM_FAILURE); 6177 } 6178 6179 if (*p_link == '\0') { 6180 err_print(MISSING_DEVNAME, devlinktab_line, devlinktab_file); 6181 return (DEVFSADM_FAILURE); 6182 } 6183 6184 if ((tab = strchr(*p_link, TAB)) != NULL) { 6185 *tab = '\0'; 6186 *s_link = ++tab; 6187 if (strchr(*s_link, TAB) != NULL) { 6188 err_print(TOO_MANY_FIELDS, devlinktab_line, 6189 devlinktab_file); 6190 return (DEVFSADM_FAILURE); 6191 } 6192 } else { 6193 *s_link = NULL; 6194 } 6195 6196 return (DEVFSADM_SUCCESS); 6197 } 6198 6199 /* 6200 * For a given devfs_spec field, for each element in the field, add it to 6201 * a linked list of devfs_spec structures. Return the linked list in 6202 * devfs_spec_list. 6203 */ 6204 static selector_list_t * 6205 create_selector_list(char *selector) 6206 { 6207 char *key; 6208 char *val; 6209 int error = FALSE; 6210 selector_list_t *head_selector_list = NULL; 6211 selector_list_t *selector_list; 6212 6213 /* parse_devfs_spec splits the next field into keyword & value */ 6214 while ((*selector != NULL) && (error == FALSE)) { 6215 if (parse_selector(&selector, &key, 6216 &val) == DEVFSADM_FAILURE) { 6217 error = TRUE; 6218 break; 6219 } else { 6220 selector_list = (selector_list_t *) 6221 s_malloc(sizeof (selector_list_t)); 6222 if (strcmp(NAME_S, key) == 0) { 6223 selector_list->key = NAME; 6224 } else if (strcmp(TYPE_S, key) == 0) { 6225 selector_list->key = TYPE; 6226 } else if (strncmp(ADDR_S, key, ADDR_S_LEN) == 0) { 6227 selector_list->key = ADDR; 6228 if (key[ADDR_S_LEN] == '\0') { 6229 selector_list->arg = 0; 6230 } else if (isdigit(key[ADDR_S_LEN]) != 6231 FALSE) { 6232 selector_list->arg = 6233 atoi(&key[ADDR_S_LEN]); 6234 } else { 6235 error = TRUE; 6236 free(selector_list); 6237 err_print(BADKEYWORD, key, 6238 devlinktab_line, 6239 devlinktab_file); 6240 break; 6241 } 6242 } else if (strncmp(MINOR_S, key, 6243 MINOR_S_LEN) == 0) { 6244 selector_list->key = MINOR; 6245 if (key[MINOR_S_LEN] == '\0') { 6246 selector_list->arg = 0; 6247 } else if (isdigit(key[MINOR_S_LEN]) != 6248 FALSE) { 6249 selector_list->arg = 6250 atoi(&key[MINOR_S_LEN]); 6251 } else { 6252 error = TRUE; 6253 free(selector_list); 6254 err_print(BADKEYWORD, key, 6255 devlinktab_line, 6256 devlinktab_file); 6257 break; 6258 } 6259 vprint(DEVLINK_MID, "MINOR = %s\n", val); 6260 } else { 6261 err_print(UNRECOGNIZED_KEY, key, 6262 devlinktab_line, devlinktab_file); 6263 error = TRUE; 6264 free(selector_list); 6265 break; 6266 } 6267 selector_list->val = s_strdup(val); 6268 selector_list->next = head_selector_list; 6269 head_selector_list = selector_list; 6270 vprint(DEVLINK_MID, "key='%s' val='%s' arg=%d\n", 6271 key, val, selector_list->arg); 6272 } 6273 } 6274 6275 if ((error == FALSE) && (head_selector_list != NULL)) { 6276 return (head_selector_list); 6277 } else { 6278 /* parse failed. Free any allocated structs */ 6279 free_selector_list(head_selector_list); 6280 return (NULL); 6281 } 6282 } 6283 6284 /* 6285 * Takes a semicolon separated list of selector elements and breaks up 6286 * into a keyword-value pair. semicolon and equal characters are 6287 * replaced with NULL's. On success, selector is updated to point to the 6288 * terminating NULL character terminating the keyword-value pair, and the 6289 * function returns DEVFSADM_SUCCESS. If there is a syntax error, 6290 * devfs_spec is not modified and function returns DEVFSADM_FAILURE. 6291 */ 6292 static int 6293 parse_selector(char **selector, char **key, char **val) 6294 { 6295 char *equal; 6296 char *semi_colon; 6297 6298 *key = *selector; 6299 6300 if ((equal = strchr(*key, '=')) != NULL) { 6301 *equal = '\0'; 6302 } else { 6303 err_print(MISSING_EQUAL, devlinktab_line, devlinktab_file); 6304 return (DEVFSADM_FAILURE); 6305 } 6306 6307 *val = ++equal; 6308 if ((semi_colon = strchr(equal, ';')) != NULL) { 6309 *semi_colon = '\0'; 6310 *selector = semi_colon + 1; 6311 } else { 6312 *selector = equal + strlen(equal); 6313 } 6314 return (DEVFSADM_SUCCESS); 6315 } 6316 6317 /* 6318 * link is either the second or third field of devlink.tab. Parse link 6319 * into a linked list of devlink structures and return ptr to list. Each 6320 * list element is either a constant string, or one of the following 6321 * escape sequences: \M, \A, \N, or \D. The first three escape sequences 6322 * take a numerical argument. 6323 */ 6324 static link_list_t * 6325 create_link_list(char *link) 6326 { 6327 int x = 0; 6328 int error = FALSE; 6329 int counter_found = FALSE; 6330 link_list_t *head = NULL; 6331 link_list_t **ptr; 6332 link_list_t *link_list; 6333 char constant[MAX_DEVLINK_LINE]; 6334 char *error_str; 6335 6336 if (link == NULL) { 6337 return (NULL); 6338 } 6339 6340 while ((*link != '\0') && (error == FALSE)) { 6341 link_list = (link_list_t *)s_malloc(sizeof (link_list_t)); 6342 link_list->next = NULL; 6343 6344 while ((*link != '\0') && (*link != '\\')) { 6345 /* a non-escaped string */ 6346 constant[x++] = *(link++); 6347 } 6348 if (x != 0) { 6349 constant[x] = '\0'; 6350 link_list->type = CONSTANT; 6351 link_list->constant = s_strdup(constant); 6352 x = 0; 6353 vprint(DEVLINK_MID, "CONSTANT FOUND %s\n", constant); 6354 } else { 6355 switch (*(++link)) { 6356 case 'M': 6357 link_list->type = MINOR; 6358 break; 6359 case 'A': 6360 link_list->type = ADDR; 6361 break; 6362 case 'N': 6363 if (counter_found == TRUE) { 6364 error = TRUE; 6365 error_str = "multiple counters " 6366 "not permitted"; 6367 free(link_list); 6368 } else { 6369 counter_found = TRUE; 6370 link_list->type = COUNTER; 6371 } 6372 break; 6373 case 'D': 6374 link_list->type = NAME; 6375 break; 6376 default: 6377 error = TRUE; 6378 free(link_list); 6379 error_str = "unrecognized escape sequence"; 6380 break; 6381 } 6382 if (*(link++) != 'D') { 6383 if (isdigit(*link) == FALSE) { 6384 error_str = "escape sequence must be " 6385 "followed by a digit\n"; 6386 error = TRUE; 6387 free(link_list); 6388 } else { 6389 link_list->arg = 6390 (int)strtoul(link, &link, 10); 6391 vprint(DEVLINK_MID, "link_list->arg = " 6392 "%d\n", link_list->arg); 6393 } 6394 } 6395 } 6396 /* append link_list struct to end of list */ 6397 if (error == FALSE) { 6398 for (ptr = &head; *ptr != NULL; ptr = &((*ptr)->next)); 6399 *ptr = link_list; 6400 } 6401 } 6402 6403 if (error == FALSE) { 6404 return (head); 6405 } else { 6406 err_print(CONFIG_INCORRECT, devlinktab_line, devlinktab_file, 6407 error_str); 6408 free_link_list(head); 6409 return (NULL); 6410 } 6411 } 6412 6413 /* 6414 * Called for each minor node devfsadm processes; for each minor node, 6415 * look for matches in the devlinktab_list list which was created on 6416 * startup read_devlinktab_file(). If there is a match, call build_links() 6417 * to build a logical devlink and a possible extra devlink. 6418 */ 6419 static int 6420 process_devlink_compat(di_minor_t minor, di_node_t node) 6421 { 6422 int link_built = FALSE; 6423 devlinktab_list_t *entry; 6424 char *nodetype; 6425 char *dev_path; 6426 6427 if (devlinks_debug == TRUE) { 6428 nodetype = di_minor_nodetype(minor); 6429 assert(nodetype != NULL); 6430 if ((dev_path = di_devfs_path(node)) != NULL) { 6431 vprint(INFO_MID, "'%s' entry: %s:%s\n", nodetype, 6432 dev_path, 6433 di_minor_name(minor) ? di_minor_name(minor) : 6434 ""); 6435 di_devfs_path_free(dev_path); 6436 } 6437 6438 } 6439 6440 6441 /* don't process devlink.tab if devfsadm invoked with -c <class> */ 6442 if (num_classes > 0) { 6443 return (FALSE); 6444 } 6445 6446 for (entry = devlinktab_list; entry != NULL; entry = entry->next) { 6447 if (devlink_matches(entry, minor, node) == DEVFSADM_SUCCESS) { 6448 link_built = TRUE; 6449 (void) build_links(entry, minor, node); 6450 } 6451 } 6452 return (link_built); 6453 } 6454 6455 /* 6456 * For a given devlink.tab devlinktab_list entry, see if the selector 6457 * field matches this minor node. If it does, return DEVFSADM_SUCCESS, 6458 * otherwise DEVFSADM_FAILURE. 6459 */ 6460 static int 6461 devlink_matches(devlinktab_list_t *entry, di_minor_t minor, di_node_t node) 6462 { 6463 selector_list_t *selector = entry->selector; 6464 char *addr; 6465 char *minor_name; 6466 char *node_type; 6467 6468 for (; selector != NULL; selector = selector->next) { 6469 switch (selector->key) { 6470 case NAME: 6471 if (strcmp(di_node_name(node), selector->val) != 0) { 6472 return (DEVFSADM_FAILURE); 6473 } 6474 break; 6475 case TYPE: 6476 node_type = di_minor_nodetype(minor); 6477 assert(node_type != NULL); 6478 if (strcmp(node_type, selector->val) != 0) { 6479 return (DEVFSADM_FAILURE); 6480 } 6481 break; 6482 case ADDR: 6483 if ((addr = di_bus_addr(node)) == NULL) { 6484 return (DEVFSADM_FAILURE); 6485 } 6486 if (selector->arg == 0) { 6487 if (strcmp(addr, selector->val) != 0) { 6488 return (DEVFSADM_FAILURE); 6489 } 6490 } else { 6491 if (compare_field(addr, selector->val, 6492 selector->arg) == DEVFSADM_FAILURE) { 6493 return (DEVFSADM_FAILURE); 6494 } 6495 } 6496 break; 6497 case MINOR: 6498 if ((minor_name = di_minor_name(minor)) == NULL) { 6499 return (DEVFSADM_FAILURE); 6500 } 6501 if (selector->arg == 0) { 6502 if (strcmp(minor_name, selector->val) != 0) { 6503 return (DEVFSADM_FAILURE); 6504 } 6505 } else { 6506 if (compare_field(minor_name, selector->val, 6507 selector->arg) == DEVFSADM_FAILURE) { 6508 return (DEVFSADM_FAILURE); 6509 } 6510 } 6511 break; 6512 default: 6513 return (DEVFSADM_FAILURE); 6514 } 6515 } 6516 6517 return (DEVFSADM_SUCCESS); 6518 } 6519 6520 /* 6521 * For the given minor node and devlinktab_list entry from devlink.tab, 6522 * build a logical dev link and a possible extra devlink. 6523 * Return DEVFSADM_SUCCESS if link is created, otherwise DEVFSADM_FAILURE. 6524 */ 6525 static int 6526 build_links(devlinktab_list_t *entry, di_minor_t minor, di_node_t node) 6527 { 6528 char secondary_link[PATH_MAX + 1]; 6529 char primary_link[PATH_MAX + 1]; 6530 char contents[PATH_MAX + 1]; 6531 char *dev_path; 6532 6533 if ((dev_path = di_devfs_path(node)) == NULL) { 6534 err_print(DI_DEVFS_PATH_FAILED, strerror(errno)); 6535 devfsadm_exit(1); 6536 } 6537 (void) strcpy(contents, dev_path); 6538 di_devfs_path_free(dev_path); 6539 6540 (void) strcat(contents, ":"); 6541 (void) strcat(contents, di_minor_name(minor)); 6542 6543 if (construct_devlink(primary_link, entry->p_link, contents, 6544 minor, node, 6545 entry->p_link_pattern) == DEVFSADM_FAILURE) { 6546 return (DEVFSADM_FAILURE); 6547 } 6548 (void) devfsadm_mklink(primary_link, node, minor, 0); 6549 6550 if (entry->s_link == NULL) { 6551 return (DEVFSADM_SUCCESS); 6552 } 6553 6554 if (construct_devlink(secondary_link, entry->s_link, 6555 primary_link, minor, node, 6556 entry->s_link_pattern) == DEVFSADM_FAILURE) { 6557 return (DEVFSADM_FAILURE); 6558 } 6559 6560 (void) devfsadm_secondary_link(secondary_link, primary_link, 0); 6561 6562 return (DEVFSADM_SUCCESS); 6563 } 6564 6565 /* 6566 * The counter rule for devlink.tab entries is implemented via 6567 * devfsadm_enumerate_int_start(). One of the arguments to this function 6568 * is a path, where each path component is treated as a regular expression. 6569 * For devlink.tab entries, this path regular expression is derived from 6570 * the devlink spec. get_anchored_re() accepts path regular expressions derived 6571 * from devlink.tab entries and inserts the anchors '^' and '$' at the beginning 6572 * and end respectively of each path component. This is done to prevent 6573 * false matches. For example, without anchors, "a/([0-9]+)" will match "ab/c9" 6574 * and incorrect links will be generated. 6575 */ 6576 static int 6577 get_anchored_re(char *link, char *anchored_re, char *pattern) 6578 { 6579 if (*link == '/' || *link == '\0') { 6580 err_print(INVALID_DEVLINK_SPEC, pattern); 6581 return (DEVFSADM_FAILURE); 6582 } 6583 6584 *anchored_re++ = '^'; 6585 for (; *link != '\0'; ) { 6586 if (*link == '/') { 6587 while (*link == '/') 6588 link++; 6589 *anchored_re++ = '$'; 6590 *anchored_re++ = '/'; 6591 if (*link != '\0') { 6592 *anchored_re++ = '^'; 6593 } 6594 } else { 6595 *anchored_re++ = *link++; 6596 if (*link == '\0') { 6597 *anchored_re++ = '$'; 6598 } 6599 } 6600 } 6601 *anchored_re = '\0'; 6602 6603 return (DEVFSADM_SUCCESS); 6604 } 6605 6606 static int 6607 construct_devlink(char *link, link_list_t *link_build, char *contents, 6608 di_minor_t minor, di_node_t node, char *pattern) 6609 { 6610 int counter_offset = -1; 6611 devfsadm_enumerate_t rules[1] = {NULL}; 6612 char templink[PATH_MAX + 1]; 6613 char *buff; 6614 char start[10]; 6615 char *node_path; 6616 char anchored_re[PATH_MAX + 1]; 6617 6618 link[0] = '\0'; 6619 6620 for (; link_build != NULL; link_build = link_build->next) { 6621 switch (link_build->type) { 6622 case NAME: 6623 (void) strcat(link, di_node_name(node)); 6624 break; 6625 case CONSTANT: 6626 (void) strcat(link, link_build->constant); 6627 break; 6628 case ADDR: 6629 if (component_cat(link, di_bus_addr(node), 6630 link_build->arg) == DEVFSADM_FAILURE) { 6631 node_path = di_devfs_path(node); 6632 err_print(CANNOT_BE_USED, pattern, node_path, 6633 di_minor_name(minor)); 6634 di_devfs_path_free(node_path); 6635 return (DEVFSADM_FAILURE); 6636 } 6637 break; 6638 case MINOR: 6639 if (component_cat(link, di_minor_name(minor), 6640 link_build->arg) == DEVFSADM_FAILURE) { 6641 node_path = di_devfs_path(node); 6642 err_print(CANNOT_BE_USED, pattern, node_path, 6643 di_minor_name(minor)); 6644 di_devfs_path_free(node_path); 6645 return (DEVFSADM_FAILURE); 6646 } 6647 break; 6648 case COUNTER: 6649 counter_offset = strlen(link); 6650 (void) strcat(link, "([0-9]+)"); 6651 (void) sprintf(start, "%d", link_build->arg); 6652 break; 6653 default: 6654 return (DEVFSADM_FAILURE); 6655 } 6656 } 6657 6658 if (counter_offset != -1) { 6659 /* 6660 * copy anything appended after "([0-9]+)" into 6661 * templink 6662 */ 6663 6664 (void) strcpy(templink, 6665 &link[counter_offset + strlen("([0-9]+)")]); 6666 if (get_anchored_re(link, anchored_re, pattern) 6667 != DEVFSADM_SUCCESS) { 6668 return (DEVFSADM_FAILURE); 6669 } 6670 rules[0].re = anchored_re; 6671 rules[0].subexp = 1; 6672 rules[0].flags = MATCH_ALL; 6673 if (devfsadm_enumerate_int_start(contents, 0, &buff, 6674 rules, 1, start) == DEVFSADM_FAILURE) { 6675 return (DEVFSADM_FAILURE); 6676 } 6677 (void) strcpy(&link[counter_offset], buff); 6678 free(buff); 6679 (void) strcat(link, templink); 6680 vprint(DEVLINK_MID, "COUNTER is %s\n", link); 6681 } 6682 return (DEVFSADM_SUCCESS); 6683 } 6684 6685 /* 6686 * Compares "field" number of the comma separated list "full_name" with 6687 * field_item. Returns DEVFSADM_SUCCESS for match, 6688 * DEVFSADM_FAILURE for no match. 6689 */ 6690 static int 6691 compare_field(char *full_name, char *field_item, int field) 6692 { 6693 --field; 6694 while ((*full_name != '\0') && (field != 0)) { 6695 if (*(full_name++) == ',') { 6696 field--; 6697 } 6698 } 6699 6700 if (field != 0) { 6701 return (DEVFSADM_FAILURE); 6702 } 6703 6704 while ((*full_name != '\0') && (*field_item != '\0') && 6705 (*full_name != ',')) { 6706 if (*(full_name++) != *(field_item++)) { 6707 return (DEVFSADM_FAILURE); 6708 } 6709 } 6710 6711 if (*field_item != '\0') { 6712 return (DEVFSADM_FAILURE); 6713 } 6714 6715 if ((*full_name == '\0') || (*full_name == ',')) 6716 return (DEVFSADM_SUCCESS); 6717 6718 return (DEVFSADM_FAILURE); 6719 } 6720 6721 /* 6722 * strcat() field # "field" of comma separated list "name" to "link". 6723 * Field 0 is the entire name. 6724 * Return DEVFSADM_SUCCESS or DEVFSADM_FAILURE. 6725 */ 6726 static int 6727 component_cat(char *link, char *name, int field) 6728 { 6729 6730 if (name == NULL) { 6731 return (DEVFSADM_FAILURE); 6732 } 6733 6734 if (field == 0) { 6735 (void) strcat(link, name); 6736 return (DEVFSADM_SUCCESS); 6737 } 6738 6739 while (*link != '\0') { 6740 link++; 6741 } 6742 6743 --field; 6744 while ((*name != '\0') && (field != 0)) { 6745 if (*(name++) == ',') { 6746 --field; 6747 } 6748 } 6749 6750 if (field != 0) { 6751 return (DEVFSADM_FAILURE); 6752 } 6753 6754 while ((*name != '\0') && (*name != ',')) { 6755 *(link++) = *(name++); 6756 } 6757 6758 *link = '\0'; 6759 return (DEVFSADM_SUCCESS); 6760 } 6761 6762 static void 6763 free_selector_list(selector_list_t *head) 6764 { 6765 selector_list_t *temp; 6766 6767 while (head != NULL) { 6768 temp = head; 6769 head = head->next; 6770 free(temp->val); 6771 free(temp); 6772 } 6773 } 6774 6775 static void 6776 free_link_list(link_list_t *head) 6777 { 6778 link_list_t *temp; 6779 6780 while (head != NULL) { 6781 temp = head; 6782 head = head->next; 6783 if (temp->type == CONSTANT) { 6784 free(temp->constant); 6785 } 6786 free(temp); 6787 } 6788 } 6789 6790 /* 6791 * Prints only if level matches one of the debug levels 6792 * given on command line. INFO_MID is always printed. 6793 * 6794 * See devfsadm.h for a listing of globally defined levels and 6795 * meanings. Modules should prefix the level with their 6796 * module name to prevent collisions. 6797 */ 6798 /*PRINTFLIKE2*/ 6799 void 6800 devfsadm_print(char *msgid, char *message, ...) 6801 { 6802 va_list ap; 6803 static int newline = TRUE; 6804 int x; 6805 6806 if (msgid != NULL) { 6807 for (x = 0; x < num_verbose; x++) { 6808 if (strcmp(verbose[x], msgid) == 0) { 6809 break; 6810 } 6811 if (strcmp(verbose[x], ALL_MID) == 0) { 6812 break; 6813 } 6814 } 6815 if (x == num_verbose) { 6816 return; 6817 } 6818 } 6819 6820 va_start(ap, message); 6821 6822 if (msgid == NULL) { 6823 if (logflag == TRUE) { 6824 (void) vsyslog(LOG_NOTICE, message, ap); 6825 } else { 6826 (void) vfprintf(stdout, message, ap); 6827 } 6828 6829 } else { 6830 if (logflag == TRUE) { 6831 (void) syslog(LOG_DEBUG, "%s[%ld]: %s: ", 6832 prog, getpid(), msgid); 6833 (void) vsyslog(LOG_DEBUG, message, ap); 6834 } else { 6835 if (newline == TRUE) { 6836 (void) fprintf(stdout, "%s[%ld]: %s: ", 6837 prog, getpid(), msgid); 6838 } 6839 (void) vfprintf(stdout, message, ap); 6840 } 6841 } 6842 6843 if (message[strlen(message) - 1] == '\n') { 6844 newline = TRUE; 6845 } else { 6846 newline = FALSE; 6847 } 6848 va_end(ap); 6849 } 6850 6851 /* 6852 * print error messages to the terminal or to syslog 6853 */ 6854 /*PRINTFLIKE1*/ 6855 void 6856 devfsadm_errprint(char *message, ...) 6857 { 6858 va_list ap; 6859 6860 va_start(ap, message); 6861 6862 if (logflag == TRUE) { 6863 (void) vsyslog(LOG_ERR, message, ap); 6864 } else { 6865 (void) fprintf(stderr, "%s: ", prog); 6866 (void) vfprintf(stderr, message, ap); 6867 } 6868 va_end(ap); 6869 } 6870 6871 /* 6872 * return noupdate state (-s) 6873 */ 6874 int 6875 devfsadm_noupdate(void) 6876 { 6877 return (file_mods == TRUE ? DEVFSADM_TRUE : DEVFSADM_FALSE); 6878 } 6879 6880 /* 6881 * return current root update path (-r) 6882 */ 6883 const char * 6884 devfsadm_root_path(void) 6885 { 6886 if (root_dir[0] == '\0') { 6887 return ("/"); 6888 } else { 6889 return ((const char *)root_dir); 6890 } 6891 } 6892 6893 void 6894 devfsadm_free_dev_names(char **dev_names, int len) 6895 { 6896 int i; 6897 6898 for (i = 0; i < len; i++) 6899 free(dev_names[i]); 6900 free(dev_names); 6901 } 6902 6903 /* 6904 * Return all devlinks corresponding to phys_path as an array of strings. 6905 * The number of entries in the array is returned through lenp. 6906 * devfsadm_free_dev_names() is used to free the returned array. 6907 * NULL is returned on failure or when there are no matching devlinks. 6908 * 6909 * re is an extended regular expression in regex(5) format used to further 6910 * match devlinks pointing to phys_path; it may be NULL to match all 6911 */ 6912 char ** 6913 devfsadm_lookup_dev_names(char *phys_path, char *re, int *lenp) 6914 { 6915 struct devlink_cb_arg cb_arg; 6916 char **dev_names = NULL; 6917 int i; 6918 6919 *lenp = 0; 6920 cb_arg.count = 0; 6921 cb_arg.rv = 0; 6922 (void) di_devlink_cache_walk(devlink_cache, re, phys_path, 6923 DI_PRIMARY_LINK, &cb_arg, devlink_cb); 6924 6925 if (cb_arg.rv == -1 || cb_arg.count <= 0) 6926 return (NULL); 6927 6928 dev_names = s_malloc(cb_arg.count * sizeof (char *)); 6929 if (dev_names == NULL) 6930 goto out; 6931 6932 for (i = 0; i < cb_arg.count; i++) { 6933 dev_names[i] = s_strdup(cb_arg.dev_names[i]); 6934 if (dev_names[i] == NULL) { 6935 devfsadm_free_dev_names(dev_names, i); 6936 dev_names = NULL; 6937 goto out; 6938 } 6939 } 6940 *lenp = cb_arg.count; 6941 6942 out: 6943 free_dev_names(&cb_arg); 6944 return (dev_names); 6945 } 6946 6947 /* common exit function which ensures releasing locks */ 6948 static void 6949 devfsadm_exit(int status) 6950 { 6951 if (DEVFSADM_DEBUG_ON) { 6952 vprint(INFO_MID, "exit status = %d\n", status); 6953 } 6954 6955 if (rcm_hdl) { 6956 if (thr_self() != process_rcm_events_tid) { 6957 (void) mutex_lock(&rcm_eventq_lock); 6958 need_to_exit_rcm_event_thread = 1; 6959 (void) cond_broadcast(&rcm_eventq_cv); 6960 (void) mutex_unlock(&rcm_eventq_lock); 6961 6962 /* wait until process_rcm_events() thread exits */ 6963 (void) thr_join(process_rcm_events_tid, NULL, NULL); 6964 } 6965 librcm_free_handle(rcm_hdl); 6966 (void) dlclose(librcm_hdl); 6967 } 6968 6969 exit_dev_lock(); 6970 exit_daemon_lock(); 6971 6972 if (logflag == TRUE) { 6973 closelog(); 6974 } 6975 6976 exit(status); 6977 } 6978 6979 /* 6980 * set root_dir, devices_dir, dev_dir using optarg. 6981 */ 6982 static void 6983 set_root_devices_dev_dir(char *dir) 6984 { 6985 size_t len; 6986 6987 root_dir = s_strdup(dir); 6988 len = strlen(dir) + strlen(DEVICES) + 1; 6989 devices_dir = s_malloc(len); 6990 (void) snprintf(devices_dir, len, "%s%s", root_dir, DEVICES); 6991 len = strlen(root_dir) + strlen(DEV) + 1; 6992 dev_dir = s_malloc(len); 6993 (void) snprintf(dev_dir, len, "%s%s", root_dir, DEV); 6994 } 6995 6996 /* 6997 * Removes quotes. 6998 */ 6999 static char * 7000 dequote(char *src) 7001 { 7002 char *dst; 7003 int len; 7004 7005 len = strlen(src); 7006 dst = s_malloc(len + 1); 7007 if (src[0] == '\"' && src[len - 1] == '\"') { 7008 len -= 2; 7009 (void) strncpy(dst, &src[1], len); 7010 dst[len] = '\0'; 7011 } else { 7012 (void) strcpy(dst, src); 7013 } 7014 return (dst); 7015 } 7016 7017 /* 7018 * For a given physical device pathname and spectype, return the 7019 * ownership and permissions attributes by looking in data from 7020 * /etc/minor_perm. If currently in installation mode, check for 7021 * possible major number translations from the miniroot to the installed 7022 * root's name_to_major table. Note that there can be multiple matches, 7023 * but the last match takes effect. pts seems to rely on this 7024 * implementation behavior. 7025 */ 7026 static void 7027 getattr(char *phy_path, char *aminor, int spectype, dev_t dev, mode_t *mode, 7028 uid_t *uid, gid_t *gid) 7029 { 7030 char devname[PATH_MAX + 1]; 7031 char *node_name; 7032 char *minor_name; 7033 int match = FALSE; 7034 int is_clone; 7035 int mp_drvname_matches_node_name; 7036 int mp_drvname_matches_minor_name; 7037 int mp_drvname_is_clone; 7038 int mp_drvname_matches_drvname; 7039 struct mperm *mp; 7040 major_t major_no; 7041 char driver[PATH_MAX + 1]; 7042 7043 /* 7044 * Get the driver name based on the major number since the name 7045 * in /devices may be generic. Could be running with more major 7046 * numbers than are in /etc/name_to_major, so get it from the kernel 7047 */ 7048 major_no = major(dev); 7049 7050 if (modctl(MODGETNAME, driver, sizeof (driver), &major_no) != 0) { 7051 /* return default values */ 7052 goto use_defaults; 7053 } 7054 7055 (void) strcpy(devname, phy_path); 7056 7057 node_name = strrchr(devname, '/'); /* node name is the last */ 7058 /* component */ 7059 if (node_name == NULL) { 7060 err_print(NO_NODE, devname); 7061 goto use_defaults; 7062 } 7063 7064 minor_name = strchr(++node_name, '@'); /* see if it has address part */ 7065 7066 if (minor_name != NULL) { 7067 *minor_name++ = '\0'; 7068 } else { 7069 minor_name = node_name; 7070 } 7071 7072 minor_name = strchr(minor_name, ':'); /* look for minor name */ 7073 7074 if (minor_name == NULL) { 7075 err_print(NO_MINOR, devname); 7076 goto use_defaults; 7077 } 7078 *minor_name++ = '\0'; 7079 7080 /* 7081 * mp->mp_drvname = device name from minor_perm 7082 * mp->mp_minorname = minor part of device name from 7083 * minor_perm 7084 * drvname = name of driver for this device 7085 */ 7086 7087 is_clone = (strcmp(node_name, "clone") == 0 ? TRUE : FALSE); 7088 for (mp = minor_perms; mp != NULL; mp = mp->mp_next) { 7089 mp_drvname_matches_node_name = 7090 (strcmp(mp->mp_drvname, node_name) == 0 ? TRUE : FALSE); 7091 mp_drvname_matches_minor_name = 7092 (strcmp(mp->mp_drvname, minor_name) == 0 ? TRUE:FALSE); 7093 mp_drvname_is_clone = 7094 (strcmp(mp->mp_drvname, "clone") == 0 ? TRUE : FALSE); 7095 mp_drvname_matches_drvname = 7096 (strcmp(mp->mp_drvname, driver) == 0 ? TRUE : FALSE); 7097 7098 /* 7099 * If one of the following cases is true, then we try to change 7100 * the permissions if a "shell global pattern match" of 7101 * mp_>mp_minorname matches minor_name. 7102 * 7103 * 1. mp->mp_drvname matches driver. 7104 * 7105 * OR 7106 * 7107 * 2. mp->mp_drvname matches node_name and this 7108 * name is an alias of the driver name 7109 * 7110 * OR 7111 * 7112 * 3. /devices entry is the clone device and either 7113 * minor_perm entry is the clone device or matches 7114 * the minor part of the clone device. 7115 */ 7116 7117 if ((mp_drvname_matches_drvname == TRUE)|| 7118 ((mp_drvname_matches_node_name == TRUE) && 7119 (alias(driver, node_name) == TRUE)) || 7120 ((is_clone == TRUE) && 7121 ((mp_drvname_is_clone == TRUE) || 7122 (mp_drvname_matches_minor_name == TRUE)))) { 7123 /* 7124 * Check that the minor part of the 7125 * device name from the minor_perm 7126 * entry matches and if so, set the 7127 * permissions. 7128 * 7129 * Under real devfs, clone minor name is changed 7130 * to match the driver name, but minor_perm may 7131 * not match. We reconcile it here. 7132 */ 7133 if (aminor != NULL) 7134 minor_name = aminor; 7135 7136 if (gmatch(minor_name, mp->mp_minorname) != 0) { 7137 *uid = mp->mp_uid; 7138 *gid = mp->mp_gid; 7139 *mode = spectype | mp->mp_mode; 7140 match = TRUE; 7141 } 7142 } 7143 } 7144 7145 if (match == TRUE) { 7146 return; 7147 } 7148 7149 use_defaults: 7150 /* not found in minor_perm, so just use default values */ 7151 *uid = root_uid; 7152 *gid = sys_gid; 7153 *mode = (spectype | 0600); 7154 } 7155 7156 /* 7157 * Called by devfs_read_minor_perm() to report errors 7158 * key is: 7159 * line number: ignoring line number error 7160 * errno: open/close errors 7161 * size: alloc errors 7162 */ 7163 static void 7164 minorperm_err_cb(minorperm_err_t mp_err, int key) 7165 { 7166 switch (mp_err) { 7167 case MP_FOPEN_ERR: 7168 err_print(FOPEN_FAILED, MINOR_PERM_FILE, strerror(key)); 7169 break; 7170 case MP_FCLOSE_ERR: 7171 err_print(FCLOSE_FAILED, MINOR_PERM_FILE, strerror(key)); 7172 break; 7173 case MP_IGNORING_LINE_ERR: 7174 err_print(IGNORING_LINE_IN, key, MINOR_PERM_FILE); 7175 break; 7176 case MP_ALLOC_ERR: 7177 err_print(MALLOC_FAILED, key); 7178 break; 7179 case MP_NVLIST_ERR: 7180 err_print(NVLIST_ERROR, MINOR_PERM_FILE, strerror(key)); 7181 break; 7182 case MP_CANT_FIND_USER_ERR: 7183 err_print(CANT_FIND_USER, DEFAULT_DEV_USER); 7184 break; 7185 case MP_CANT_FIND_GROUP_ERR: 7186 err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP); 7187 break; 7188 } 7189 } 7190 7191 static void 7192 read_minor_perm_file(void) 7193 { 7194 static int cached = FALSE; 7195 static struct stat cached_sb; 7196 struct stat current_sb; 7197 7198 (void) stat(MINOR_PERM_FILE, ¤t_sb); 7199 7200 /* If already cached, check to see if it is still valid */ 7201 if (cached == TRUE) { 7202 7203 if (current_sb.st_mtime == cached_sb.st_mtime) { 7204 vprint(FILES_MID, "%s cache valid\n", MINOR_PERM_FILE); 7205 return; 7206 } 7207 devfs_free_minor_perm(minor_perms); 7208 minor_perms = NULL; 7209 } else { 7210 cached = TRUE; 7211 } 7212 7213 (void) stat(MINOR_PERM_FILE, &cached_sb); 7214 7215 vprint(FILES_MID, "loading binding file: %s\n", MINOR_PERM_FILE); 7216 7217 minor_perms = devfs_read_minor_perm(minorperm_err_cb); 7218 } 7219 7220 static void 7221 load_minor_perm_file(void) 7222 { 7223 read_minor_perm_file(); 7224 if (devfs_load_minor_perm(minor_perms, minorperm_err_cb) != 0) 7225 err_print(gettext("minor_perm load failed\n")); 7226 } 7227 7228 static char * 7229 convert_to_re(char *dev) 7230 { 7231 char *p, *l, *out; 7232 int i; 7233 7234 out = s_malloc(PATH_MAX); 7235 7236 for (l = p = dev, i = 0; (*p != '\0') && (i < (PATH_MAX - 1)); 7237 ++p, i++) { 7238 if ((*p == '*') && ((l != p) && (*l == '/'))) { 7239 out[i++] = '.'; 7240 out[i] = '+'; 7241 } else { 7242 out[i] = *p; 7243 } 7244 l = p; 7245 } 7246 out[i] = '\0'; 7247 p = (char *)s_malloc(strlen(out) + 1); 7248 (void) strlcpy(p, out, strlen(out) + 1); 7249 free(out); 7250 7251 vprint(FILES_MID, "converted %s -> %s\n", dev, p); 7252 7253 return (p); 7254 } 7255 7256 static void 7257 read_logindevperm_file(void) 7258 { 7259 static int cached = FALSE; 7260 static struct stat cached_sb; 7261 struct stat current_sb; 7262 struct login_dev *ldev; 7263 FILE *fp; 7264 char line[MAX_LDEV_LINE]; 7265 int ln, perm, rv; 7266 char *cp, *console, *dlist, *dev; 7267 char *lasts, *devlasts, *permstr, *drv; 7268 struct driver_list *list, *next; 7269 7270 /* Read logindevperm only when enabled */ 7271 if (login_dev_enable != TRUE) 7272 return; 7273 7274 if (cached == TRUE) { 7275 if (stat(LDEV_FILE, ¤t_sb) == 0 && 7276 current_sb.st_mtime == cached_sb.st_mtime) { 7277 vprint(FILES_MID, "%s cache valid\n", LDEV_FILE); 7278 return; 7279 } 7280 vprint(FILES_MID, "invalidating %s cache\n", LDEV_FILE); 7281 while (login_dev_cache != NULL) { 7282 7283 ldev = login_dev_cache; 7284 login_dev_cache = ldev->ldev_next; 7285 free(ldev->ldev_console); 7286 free(ldev->ldev_device); 7287 regfree(&ldev->ldev_device_regex); 7288 list = ldev->ldev_driver_list; 7289 while (list) { 7290 next = list->next; 7291 free(list); 7292 list = next; 7293 } 7294 free(ldev); 7295 } 7296 } else { 7297 cached = TRUE; 7298 } 7299 7300 assert(login_dev_cache == NULL); 7301 7302 if (stat(LDEV_FILE, &cached_sb) != 0) { 7303 cached = FALSE; 7304 return; 7305 } 7306 7307 vprint(FILES_MID, "loading file: %s\n", LDEV_FILE); 7308 7309 if ((fp = fopen(LDEV_FILE, "r")) == NULL) { 7310 /* Not fatal to devfsadm */ 7311 cached = FALSE; 7312 err_print(FOPEN_FAILED, LDEV_FILE, strerror(errno)); 7313 return; 7314 } 7315 7316 ln = 0; 7317 while (fgets(line, MAX_LDEV_LINE, fp) != NULL) { 7318 ln++; 7319 7320 /* Remove comments */ 7321 if ((cp = strchr(line, '#')) != NULL) 7322 *cp = '\0'; 7323 7324 if ((console = strtok_r(line, LDEV_DELIMS, &lasts)) == NULL) 7325 continue; /* Blank line */ 7326 7327 if ((permstr = strtok_r(NULL, LDEV_DELIMS, &lasts)) == NULL) { 7328 err_print(IGNORING_LINE_IN, ln, LDEV_FILE); 7329 continue; /* Malformed line */ 7330 } 7331 7332 /* 7333 * permstr is string in octal format. Convert to int 7334 */ 7335 cp = NULL; 7336 errno = 0; 7337 perm = strtol(permstr, &cp, 8); 7338 if (errno || perm < 0 || perm > 0777 || *cp != '\0') { 7339 err_print(IGNORING_LINE_IN, ln, LDEV_FILE); 7340 continue; 7341 } 7342 7343 if ((dlist = strtok_r(NULL, LDEV_DELIMS, &lasts)) == NULL) { 7344 err_print(IGNORING_LINE_IN, ln, LDEV_FILE); 7345 continue; 7346 } 7347 7348 dev = strtok_r(dlist, LDEV_DEV_DELIM, &devlasts); 7349 while (dev) { 7350 7351 ldev = (struct login_dev *)s_zalloc( 7352 sizeof (struct login_dev)); 7353 ldev->ldev_console = s_strdup(console); 7354 ldev->ldev_perms = perm; 7355 7356 /* 7357 * the logical device name may contain '*' which 7358 * we convert to a regular expression 7359 */ 7360 ldev->ldev_device = convert_to_re(dev); 7361 if (ldev->ldev_device && 7362 (rv = regcomp(&ldev->ldev_device_regex, 7363 ldev->ldev_device, REG_EXTENDED))) { 7364 bzero(&ldev->ldev_device_regex, 7365 sizeof (ldev->ldev_device_regex)); 7366 err_print(REGCOMP_FAILED, 7367 ldev->ldev_device, rv); 7368 } 7369 ldev->ldev_next = login_dev_cache; 7370 login_dev_cache = ldev; 7371 dev = strtok_r(NULL, LDEV_DEV_DELIM, &devlasts); 7372 } 7373 7374 drv = strtok_r(NULL, LDEV_DRVLIST_DELIMS, &lasts); 7375 if (drv) { 7376 if (strcmp(drv, LDEV_DRVLIST_NAME) == 0) { 7377 7378 drv = strtok_r(NULL, LDEV_DRV_DELIMS, 7379 &lasts); 7380 7381 while (drv) { 7382 vprint(FILES_MID, 7383 "logindevperm driver=%s\n", 7384 drv); 7385 7386 /* 7387 * create a linked list of driver 7388 * names 7389 */ 7390 list = (struct driver_list *) 7391 s_zalloc( 7392 sizeof (struct driver_list)); 7393 (void) strlcpy(list->driver_name, drv, 7394 sizeof (list->driver_name)); 7395 list->next = ldev->ldev_driver_list; 7396 ldev->ldev_driver_list = list; 7397 drv = strtok_r(NULL, LDEV_DRV_DELIMS, 7398 &lasts); 7399 } 7400 } 7401 } 7402 } 7403 (void) fclose(fp); 7404 } 7405 7406 /* 7407 * Tokens are separated by ' ', '\t', ':', '=', '&', '|', ';', '\n', or '\0' 7408 * 7409 * Returns DEVFSADM_SUCCESS if token found, DEVFSADM_FAILURE otherwise. 7410 */ 7411 static int 7412 getnexttoken(char *next, char **nextp, char **tokenpp, char *tchar) 7413 { 7414 char *cp; 7415 char *cp1; 7416 char *tokenp; 7417 7418 cp = next; 7419 while (*cp == ' ' || *cp == '\t') { 7420 cp++; /* skip leading spaces */ 7421 } 7422 tokenp = cp; /* start of token */ 7423 while (*cp != '\0' && *cp != '\n' && *cp != ' ' && *cp != '\t' && 7424 *cp != ':' && *cp != '=' && *cp != '&' && 7425 *cp != '|' && *cp != ';') { 7426 cp++; /* point to next character */ 7427 } 7428 /* 7429 * If terminating character is a space or tab, look ahead to see if 7430 * there's another terminator that's not a space or a tab. 7431 * (This code handles trailing spaces.) 7432 */ 7433 if (*cp == ' ' || *cp == '\t') { 7434 cp1 = cp; 7435 while (*++cp1 == ' ' || *cp1 == '\t') 7436 ; 7437 if (*cp1 == '=' || *cp1 == ':' || *cp1 == '&' || *cp1 == '|' || 7438 *cp1 == ';' || *cp1 == '\n' || *cp1 == '\0') { 7439 *cp = NULL; /* terminate token */ 7440 cp = cp1; 7441 } 7442 } 7443 if (tchar != NULL) { 7444 *tchar = *cp; /* save terminating character */ 7445 if (*tchar == '\0') { 7446 *tchar = '\n'; 7447 } 7448 } 7449 *cp++ = '\0'; /* terminate token, point to next */ 7450 *nextp = cp; /* set pointer to next character */ 7451 if (cp - tokenp - 1 == 0) { 7452 return (DEVFSADM_FAILURE); 7453 } 7454 *tokenpp = tokenp; 7455 return (DEVFSADM_SUCCESS); 7456 } 7457 7458 /* 7459 * read or reread the driver aliases file 7460 */ 7461 static void 7462 read_driver_aliases_file(void) 7463 { 7464 7465 driver_alias_t *save; 7466 driver_alias_t *lst_tail; 7467 driver_alias_t *ap; 7468 static int cached = FALSE; 7469 FILE *afd; 7470 char line[256]; 7471 char *cp; 7472 char *p; 7473 char t; 7474 int ln = 0; 7475 static struct stat cached_sb; 7476 struct stat current_sb; 7477 7478 (void) stat(ALIASFILE, ¤t_sb); 7479 7480 /* If already cached, check to see if it is still valid */ 7481 if (cached == TRUE) { 7482 7483 if (current_sb.st_mtime == cached_sb.st_mtime) { 7484 vprint(FILES_MID, "%s cache valid\n", ALIASFILE); 7485 return; 7486 } 7487 7488 vprint(FILES_MID, "invalidating %s cache\n", ALIASFILE); 7489 while (driver_aliases != NULL) { 7490 free(driver_aliases->alias_name); 7491 free(driver_aliases->driver_name); 7492 save = driver_aliases; 7493 driver_aliases = driver_aliases->next; 7494 free(save); 7495 } 7496 } else { 7497 cached = TRUE; 7498 } 7499 7500 (void) stat(ALIASFILE, &cached_sb); 7501 7502 vprint(FILES_MID, "loading binding file: %s\n", ALIASFILE); 7503 7504 if ((afd = fopen(ALIASFILE, "r")) == NULL) { 7505 err_print(FOPEN_FAILED, ALIASFILE, strerror(errno)); 7506 devfsadm_exit(1); 7507 } 7508 7509 while (fgets(line, sizeof (line), afd) != NULL) { 7510 ln++; 7511 /* cut off comments starting with '#' */ 7512 if ((cp = strchr(line, '#')) != NULL) 7513 *cp = '\0'; 7514 /* ignore comment or blank lines */ 7515 if (is_blank(line)) 7516 continue; 7517 cp = line; 7518 if (getnexttoken(cp, &cp, &p, &t) == DEVFSADM_FAILURE) { 7519 err_print(IGNORING_LINE_IN, ln, ALIASFILE); 7520 continue; 7521 } 7522 if (t == '\n' || t == '\0') { 7523 err_print(DRV_BUT_NO_ALIAS, ln, ALIASFILE); 7524 continue; 7525 } 7526 ap = (struct driver_alias *) 7527 s_zalloc(sizeof (struct driver_alias)); 7528 ap->driver_name = s_strdup(p); 7529 if (getnexttoken(cp, &cp, &p, &t) == DEVFSADM_FAILURE) { 7530 err_print(DRV_BUT_NO_ALIAS, ln, ALIASFILE); 7531 free(ap->driver_name); 7532 free(ap); 7533 continue; 7534 } 7535 if (*p == '"') { 7536 if (p[strlen(p) - 1] == '"') { 7537 p[strlen(p) - 1] = '\0'; 7538 p++; 7539 } 7540 } 7541 ap->alias_name = s_strdup(p); 7542 if (driver_aliases == NULL) { 7543 driver_aliases = ap; 7544 lst_tail = ap; 7545 } else { 7546 lst_tail->next = ap; 7547 lst_tail = ap; 7548 } 7549 } 7550 if (fclose(afd) == EOF) { 7551 err_print(FCLOSE_FAILED, ALIASFILE, strerror(errno)); 7552 } 7553 } 7554 7555 /* 7556 * return TRUE if alias_name is an alias for driver_name, otherwise 7557 * return FALSE. 7558 */ 7559 static int 7560 alias(char *driver_name, char *alias_name) 7561 { 7562 driver_alias_t *alias; 7563 7564 /* 7565 * check for a match 7566 */ 7567 for (alias = driver_aliases; alias != NULL; alias = alias->next) { 7568 if ((strcmp(alias->driver_name, driver_name) == 0) && 7569 (strcmp(alias->alias_name, alias_name) == 0)) { 7570 return (TRUE); 7571 } 7572 } 7573 return (FALSE); 7574 } 7575 7576 /* 7577 * convenience functions 7578 */ 7579 static int 7580 s_stat(const char *path, struct stat *sbufp) 7581 { 7582 int rv; 7583 retry: 7584 if ((rv = stat(path, sbufp)) == -1) { 7585 if (errno == EINTR) 7586 goto retry; 7587 } 7588 return (rv); 7589 } 7590 7591 static void * 7592 s_malloc(const size_t size) 7593 { 7594 void *rp; 7595 7596 rp = malloc(size); 7597 if (rp == NULL) { 7598 err_print(MALLOC_FAILED, size); 7599 devfsadm_exit(1); 7600 } 7601 return (rp); 7602 } 7603 7604 /* 7605 * convenience functions 7606 */ 7607 static void * 7608 s_realloc(void *ptr, const size_t size) 7609 { 7610 ptr = realloc(ptr, size); 7611 if (ptr == NULL) { 7612 err_print(REALLOC_FAILED, size); 7613 devfsadm_exit(1); 7614 } 7615 return (ptr); 7616 } 7617 7618 static void * 7619 s_zalloc(const size_t size) 7620 { 7621 void *rp; 7622 7623 rp = calloc(1, size); 7624 if (rp == NULL) { 7625 err_print(CALLOC_FAILED, size); 7626 devfsadm_exit(1); 7627 } 7628 return (rp); 7629 } 7630 7631 char * 7632 s_strdup(const char *ptr) 7633 { 7634 void *rp; 7635 7636 rp = strdup(ptr); 7637 if (rp == NULL) { 7638 err_print(STRDUP_FAILED, ptr); 7639 devfsadm_exit(1); 7640 } 7641 return (rp); 7642 } 7643 7644 static void 7645 s_closedir(DIR *dirp) 7646 { 7647 retry: 7648 if (closedir(dirp) != 0) { 7649 if (errno == EINTR) 7650 goto retry; 7651 err_print(CLOSEDIR_FAILED, strerror(errno)); 7652 } 7653 } 7654 7655 static void 7656 s_mkdirp(const char *path, const mode_t mode) 7657 { 7658 vprint(CHATTY_MID, "mkdirp(%s, 0x%lx)\n", path, mode); 7659 if (mkdirp(path, mode) == -1) { 7660 if (errno != EEXIST) { 7661 err_print(MKDIR_FAILED, path, mode, strerror(errno)); 7662 } 7663 } 7664 } 7665 7666 static void 7667 s_unlink(const char *file) 7668 { 7669 retry: 7670 if (unlink(file) == -1) { 7671 if (errno == EINTR || errno == EAGAIN) 7672 goto retry; 7673 if (errno != ENOENT) { 7674 err_print(UNLINK_FAILED, file, strerror(errno)); 7675 } 7676 } 7677 } 7678 7679 static void 7680 add_verbose_id(char *mid) 7681 { 7682 num_verbose++; 7683 verbose = s_realloc(verbose, num_verbose * sizeof (char *)); 7684 verbose[num_verbose - 1] = mid; 7685 } 7686 7687 /* 7688 * returns DEVFSADM_TRUE if contents is a minor node in /devices. 7689 * If mn_root is not NULL, mn_root is set to: 7690 * if contents is a /dev node, mn_root = contents 7691 * OR 7692 * if contents is a /devices node, mn_root set to the '/' 7693 * following /devices. 7694 */ 7695 static int 7696 is_minor_node(char *contents, char **mn_root) 7697 { 7698 char *ptr; 7699 char device_prefix[100]; 7700 7701 (void) snprintf(device_prefix, sizeof (device_prefix), "../devices/"); 7702 7703 if ((ptr = strstr(contents, device_prefix)) != NULL) { 7704 if (mn_root != NULL) { 7705 /* mn_root should point to the / following /devices */ 7706 *mn_root = ptr += strlen(device_prefix) - 1; 7707 } 7708 return (DEVFSADM_TRUE); 7709 } 7710 7711 (void) snprintf(device_prefix, sizeof (device_prefix), "/devices/"); 7712 7713 if (strncmp(contents, device_prefix, strlen(device_prefix)) == 0) { 7714 if (mn_root != NULL) { 7715 /* mn_root should point to the / following /devices */ 7716 *mn_root = contents + strlen(device_prefix) - 1; 7717 } 7718 return (DEVFSADM_TRUE); 7719 } 7720 7721 if (mn_root != NULL) { 7722 *mn_root = contents; 7723 } 7724 return (DEVFSADM_FALSE); 7725 } 7726 7727 /* 7728 * Lookup nvpair corresponding to the given name and type: 7729 * 7730 * The standard nvlist_lookup functions in libnvpair don't work as our 7731 * nvlist is not allocated with NV_UNIQUE_NAME or NV_UNIQUE_NAME_TYPE. 7732 */ 7733 static nvpair_t * 7734 lookup_nvpair(nvlist_t *nvl, char *name, data_type_t type) 7735 { 7736 nvpair_t *nvp; 7737 7738 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL; 7739 nvp = nvlist_next_nvpair(nvl, nvp)) { 7740 if (strcmp(name, nvpair_name(nvp)) == 0 && 7741 nvpair_type(nvp) == type) 7742 return (nvp); 7743 } 7744 7745 return (NULL); 7746 } 7747 7748 /*ARGSUSED*/ 7749 static void 7750 process_rcm_events(void *arg) 7751 { 7752 struct rcm_eventq *ev, *ev_next; 7753 nvpair_t *nvp; 7754 char *path, *driver; 7755 int instance; 7756 int err; 7757 int need_to_exit; 7758 7759 for (;;) { 7760 (void) mutex_lock(&rcm_eventq_lock); 7761 while (rcm_eventq_head == NULL && 7762 need_to_exit_rcm_event_thread == 0) 7763 (void) cond_wait(&rcm_eventq_cv, &rcm_eventq_lock); 7764 7765 need_to_exit = need_to_exit_rcm_event_thread; 7766 ev = rcm_eventq_head; 7767 rcm_eventq_head = rcm_eventq_tail = NULL; 7768 (void) mutex_unlock(&rcm_eventq_lock); 7769 7770 for (; ev != NULL; ev = ev_next) { 7771 /* 7772 * Private notification interface to RCM: 7773 * Do not retry the RCM notification on an error since 7774 * we do not know whether the failure occurred in 7775 * librcm, rcm_daemon or rcm modules or scripts. 7776 */ 7777 if (librcm_notify_event(rcm_hdl, 7778 RCM_RESOURCE_NETWORK_NEW, 0, ev->nvl, NULL) 7779 != RCM_SUCCESS) { 7780 7781 err = errno; 7782 7783 if (((nvp = lookup_nvpair(ev->nvl, 7784 RCM_NV_DEVFS_PATH, DATA_TYPE_STRING)) 7785 == NULL) || 7786 (nvpair_value_string(nvp, &path) != 0)) 7787 path = "unknown"; 7788 7789 if (((nvp = lookup_nvpair(ev->nvl, 7790 RCM_NV_DRIVER_NAME, DATA_TYPE_STRING)) 7791 == NULL) || 7792 (nvpair_value_string(nvp, &driver) != 0)) 7793 driver = "unknown"; 7794 if (((nvp = lookup_nvpair(ev->nvl, 7795 RCM_NV_INSTANCE, DATA_TYPE_INT32)) 7796 == NULL) || 7797 (nvpair_value_int32(nvp, &instance) != 0)) 7798 instance = -1; 7799 7800 err_print(RCM_NOTIFY_FAILED, path, driver, 7801 instance, strerror(err)); 7802 } 7803 7804 ev_next = ev->next; 7805 nvlist_free(ev->nvl); 7806 free(ev); 7807 } 7808 7809 if (need_to_exit) 7810 return; 7811 } 7812 } 7813 7814 /* 7815 * Initialize rcm related handles and function pointers. 7816 * Since RCM need not present in miniroot, we dlopen librcm. 7817 */ 7818 static int 7819 rcm_init(void) 7820 { 7821 #define LIBRCM_PATH "/lib/librcm.so" 7822 rcm_handle_t *hdl = NULL; 7823 int err; 7824 7825 if ((librcm_hdl = dlopen(LIBRCM_PATH, RTLD_LAZY)) == NULL) { 7826 /* 7827 * don't log an error here, since librcm may not be present 7828 * in miniroot. 7829 */ 7830 return (-1); 7831 } 7832 7833 librcm_alloc_handle = (int (*)())dlsym(librcm_hdl, "rcm_alloc_handle"); 7834 librcm_free_handle = (void (*)())dlsym(librcm_hdl, "rcm_free_handle"); 7835 librcm_notify_event = (int (*)())dlsym(librcm_hdl, "rcm_notify_event"); 7836 7837 if (librcm_alloc_handle == NULL || librcm_notify_event == NULL || 7838 librcm_free_handle == NULL) { 7839 err_print(MISSING_SYMBOLS, LIBRCM_PATH); 7840 goto out; 7841 } 7842 7843 /* Initialize the rcm handle */ 7844 if (librcm_alloc_handle(NULL, 0, NULL, &hdl) != RCM_SUCCESS) { 7845 err_print(RCM_ALLOC_HANDLE_ERROR); 7846 goto out; 7847 } 7848 7849 (void) cond_init(&rcm_eventq_cv, USYNC_THREAD, 0); 7850 (void) mutex_init(&rcm_eventq_lock, USYNC_THREAD, 0); 7851 7852 /* create a thread to notify RCM of events */ 7853 if ((err = thr_create(NULL, 0, (void *(*)(void *))process_rcm_events, 7854 NULL, 0, &process_rcm_events_tid)) != 0) { 7855 err_print(CANT_CREATE_THREAD, "process_rcm_events", 7856 strerror(err)); 7857 goto out; 7858 } 7859 7860 rcm_hdl = hdl; 7861 return (0); 7862 7863 out: 7864 if (hdl) 7865 librcm_free_handle(hdl); 7866 (void) dlclose(librcm_hdl); 7867 return (-1); 7868 } 7869 7870 /* 7871 * Build an nvlist using the minor data. Pack it and add the packed nvlist 7872 * as a byte array to nv_list parameter. 7873 * Return 0 on success, errno on failure. 7874 */ 7875 static int 7876 add_minor_data_to_nvl(nvlist_t *nv_list, di_minor_t minor) 7877 { 7878 nvlist_t *nvl = NULL; 7879 int32_t minor_type; 7880 char *minor_name, *minor_node_type; 7881 int err; 7882 char *buf = NULL; 7883 size_t buflen = 0; 7884 7885 if ((err = nvlist_alloc(&nvl, 0, 0)) != 0) 7886 return (err); 7887 7888 minor_type = (int32_t)di_minor_type(minor); 7889 if ((err = nvlist_add_int32(nvl, RCM_NV_MINOR_TYPE, minor_type)) != 0) 7890 goto error; 7891 7892 minor_name = di_minor_name(minor); 7893 if ((err = nvlist_add_string(nvl, RCM_NV_MINOR_NAME, minor_name)) != 0) 7894 goto error; 7895 7896 if ((minor_node_type = di_minor_nodetype(minor)) == NULL) 7897 minor_node_type = ""; 7898 if ((err = nvlist_add_string(nvl, RCM_NV_MINOR_NODE_TYPE, 7899 minor_node_type)) != 0) 7900 goto error; 7901 7902 if ((err = nvlist_pack(nvl, &buf, &buflen, NV_ENCODE_NATIVE, 0)) != 0) 7903 goto error; 7904 7905 err = nvlist_add_byte_array(nv_list, RCM_NV_MINOR_DATA, 7906 (uchar_t *)(buf), (uint_t)(buflen)); 7907 7908 error: 7909 nvlist_free(nvl); 7910 if (buf) 7911 free(buf); 7912 return (err); 7913 } 7914 7915 static void 7916 enqueue_rcm_event(nvlist_t *nvl) 7917 { 7918 struct rcm_eventq *ev; 7919 7920 ev = (struct rcm_eventq *)s_zalloc(sizeof (struct rcm_eventq)); 7921 ev->nvl = nvl; 7922 7923 (void) mutex_lock(&rcm_eventq_lock); 7924 if (rcm_eventq_head == NULL) 7925 rcm_eventq_head = ev; 7926 else 7927 rcm_eventq_tail->next = ev; 7928 rcm_eventq_tail = ev; 7929 (void) cond_broadcast(&rcm_eventq_cv); 7930 (void) mutex_unlock(&rcm_eventq_lock); 7931 } 7932 7933 /* 7934 * Generate an nvlist using the information given in node and minor_name. 7935 * If minor_name is NULL the nvlist will contain information on 7936 * all minor nodes. Otherwise the nvlist will contain information 7937 * only on the given minor_name. Notify RCM passing the nvlist. 7938 * 7939 * Return 0 upon successfully notifying RCM, errno on failure. 7940 */ 7941 static int 7942 notify_rcm(di_node_t node, char *minor_name) 7943 { 7944 nvlist_t *nvl = NULL; 7945 char *path, *driver_name; 7946 char *node_name; 7947 int err; 7948 int32_t instance; 7949 di_minor_t minor; 7950 7951 if ((driver_name = di_driver_name(node)) == NULL) 7952 driver_name = ""; 7953 7954 instance = (int32_t)di_instance(node); 7955 7956 if ((path = di_devfs_path(node)) == NULL) { 7957 err = errno; 7958 goto error; 7959 } 7960 7961 if ((err = nvlist_alloc(&nvl, 0, 0)) != 0) 7962 goto error; 7963 7964 if ((err = nvlist_add_string(nvl, RCM_NV_DRIVER_NAME, driver_name)) 7965 != 0) 7966 goto error; 7967 7968 if ((err = nvlist_add_int32(nvl, RCM_NV_INSTANCE, instance)) != 0) 7969 goto error; 7970 7971 if ((node_name = di_node_name(node)) == NULL) 7972 node_name = ""; 7973 if ((err = nvlist_add_string(nvl, RCM_NV_NODE_NAME, node_name)) != 0) 7974 goto error; 7975 7976 if ((err = nvlist_add_string(nvl, RCM_NV_DEVFS_PATH, path)) != 0) 7977 goto error; 7978 7979 minor = di_minor_next(node, DI_MINOR_NIL); 7980 while (minor != DI_MINOR_NIL) { 7981 if ((minor_name == NULL) || 7982 (strcmp(minor_name, di_minor_name(minor)) == 0)) { 7983 if ((err = add_minor_data_to_nvl(nvl, minor)) != 0) 7984 goto error; 7985 } 7986 minor = di_minor_next(node, minor); 7987 } 7988 7989 enqueue_rcm_event(nvl); 7990 di_devfs_path_free(path); 7991 return (0); 7992 7993 error: 7994 err_print(RCM_NVLIST_BUILD_ERROR, ((path != NULL) ? path : "unknown"), 7995 driver_name, instance, strerror(err)); 7996 7997 if (path) 7998 di_devfs_path_free(path); 7999 if (nvl) 8000 nvlist_free(nvl); 8001 return (err); 8002 } 8003 8004 /* 8005 * Add the specified property to nvl. 8006 * Returns: 8007 * 0 successfully added 8008 * -1 an error occurred 8009 * 1 could not add the property for reasons not due to errors. 8010 */ 8011 static int 8012 add_property(nvlist_t *nvl, di_prop_t prop) 8013 { 8014 char *name; 8015 char *attr_name; 8016 int n, len; 8017 int32_t *int32p; 8018 int64_t *int64p; 8019 char *str; 8020 char **strarray; 8021 uchar_t *bytep; 8022 int rv = 0; 8023 int i; 8024 8025 if ((name = di_prop_name(prop)) == NULL) 8026 return (-1); 8027 8028 len = sizeof (DEV_PROP_PREFIX) + strlen(name); 8029 if ((attr_name = malloc(len)) == NULL) 8030 return (-1); 8031 8032 (void) strlcpy(attr_name, DEV_PROP_PREFIX, len); 8033 (void) strlcat(attr_name, name, len); 8034 8035 switch (di_prop_type(prop)) { 8036 case DI_PROP_TYPE_BOOLEAN: 8037 if (nvlist_add_boolean(nvl, attr_name) != 0) 8038 goto out; 8039 break; 8040 8041 case DI_PROP_TYPE_INT: 8042 if ((n = di_prop_ints(prop, &int32p)) < 1) 8043 goto out; 8044 8045 if (n <= (PROP_LEN_LIMIT / sizeof (int32_t))) { 8046 if (nvlist_add_int32_array(nvl, attr_name, int32p, 8047 n) != 0) 8048 goto out; 8049 } else 8050 rv = 1; 8051 break; 8052 8053 case DI_PROP_TYPE_INT64: 8054 if ((n = di_prop_int64(prop, &int64p)) < 1) 8055 goto out; 8056 8057 if (n <= (PROP_LEN_LIMIT / sizeof (int64_t))) { 8058 if (nvlist_add_int64_array(nvl, attr_name, int64p, 8059 n) != 0) 8060 goto out; 8061 } else 8062 rv = 1; 8063 break; 8064 8065 case DI_PROP_TYPE_BYTE: 8066 case DI_PROP_TYPE_UNKNOWN: 8067 if ((n = di_prop_bytes(prop, &bytep)) < 1) 8068 goto out; 8069 8070 if (n <= PROP_LEN_LIMIT) { 8071 if (nvlist_add_byte_array(nvl, attr_name, bytep, n) 8072 != 0) 8073 goto out; 8074 } else 8075 rv = 1; 8076 break; 8077 8078 case DI_PROP_TYPE_STRING: 8079 if ((n = di_prop_strings(prop, &str)) < 1) 8080 goto out; 8081 8082 if ((strarray = malloc(n * sizeof (char *))) == NULL) 8083 goto out; 8084 8085 len = 0; 8086 for (i = 0; i < n; i++) { 8087 strarray[i] = str + len; 8088 len += strlen(strarray[i]) + 1; 8089 } 8090 8091 if (len <= PROP_LEN_LIMIT) { 8092 if (nvlist_add_string_array(nvl, attr_name, strarray, 8093 n) != 0) { 8094 free(strarray); 8095 goto out; 8096 } 8097 } else 8098 rv = 1; 8099 free(strarray); 8100 break; 8101 8102 default: 8103 rv = 1; 8104 break; 8105 } 8106 8107 free(attr_name); 8108 return (rv); 8109 8110 out: 8111 free(attr_name); 8112 return (-1); 8113 } 8114 8115 static void 8116 free_dev_names(struct devlink_cb_arg *x) 8117 { 8118 int i; 8119 8120 for (i = 0; i < x->count; i++) { 8121 free(x->dev_names[i]); 8122 free(x->link_contents[i]); 8123 } 8124 } 8125 8126 /* callback function for di_devlink_cache_walk */ 8127 static int 8128 devlink_cb(di_devlink_t dl, void *arg) 8129 { 8130 struct devlink_cb_arg *x = (struct devlink_cb_arg *)arg; 8131 const char *path; 8132 const char *content; 8133 8134 if ((path = di_devlink_path(dl)) == NULL || 8135 (content = di_devlink_content(dl)) == NULL || 8136 (x->dev_names[x->count] = s_strdup(path)) == NULL) 8137 goto out; 8138 8139 if ((x->link_contents[x->count] = s_strdup(content)) == NULL) { 8140 free(x->dev_names[x->count]); 8141 goto out; 8142 } 8143 8144 x->count++; 8145 if (x->count >= MAX_DEV_NAME_COUNT) 8146 return (DI_WALK_TERMINATE); 8147 8148 return (DI_WALK_CONTINUE); 8149 8150 out: 8151 x->rv = -1; 8152 free_dev_names(x); 8153 return (DI_WALK_TERMINATE); 8154 } 8155 8156 /* 8157 * Lookup dev name corresponding to the phys_path. 8158 * phys_path is path to a node or minor node. 8159 * Returns: 8160 * 0 with *dev_name set to the dev name 8161 * Lookup succeeded and dev_name found 8162 * 0 with *dev_name set to NULL 8163 * Lookup encountered no errors but dev name not found 8164 * -1 8165 * Lookup failed 8166 */ 8167 static int 8168 lookup_dev_name(char *phys_path, char **dev_name) 8169 { 8170 struct devlink_cb_arg cb_arg; 8171 8172 *dev_name = NULL; 8173 8174 cb_arg.count = 0; 8175 cb_arg.rv = 0; 8176 (void) di_devlink_cache_walk(devlink_cache, NULL, phys_path, 8177 DI_PRIMARY_LINK, &cb_arg, devlink_cb); 8178 8179 if (cb_arg.rv == -1) 8180 return (-1); 8181 8182 if (cb_arg.count > 0) { 8183 *dev_name = s_strdup(cb_arg.dev_names[0]); 8184 free_dev_names(&cb_arg); 8185 if (*dev_name == NULL) 8186 return (-1); 8187 } 8188 8189 return (0); 8190 } 8191 8192 static char * 8193 lookup_disk_dev_name(char *node_path) 8194 { 8195 struct devlink_cb_arg cb_arg; 8196 char *dev_name = NULL; 8197 int i; 8198 char *p; 8199 int len1, len2; 8200 8201 #define DEV_RDSK "/dev/rdsk/" 8202 #define DISK_RAW_MINOR ",raw" 8203 8204 cb_arg.count = 0; 8205 cb_arg.rv = 0; 8206 (void) di_devlink_cache_walk(devlink_cache, NULL, node_path, 8207 DI_PRIMARY_LINK, &cb_arg, devlink_cb); 8208 8209 if (cb_arg.rv == -1 || cb_arg.count == 0) 8210 return (NULL); 8211 8212 /* first try lookup based on /dev/rdsk name */ 8213 for (i = 0; i < cb_arg.count; i++) { 8214 if (strncmp(cb_arg.dev_names[i], DEV_RDSK, 8215 sizeof (DEV_RDSK) - 1) == 0) { 8216 dev_name = s_strdup(cb_arg.dev_names[i]); 8217 break; 8218 } 8219 } 8220 8221 if (dev_name == NULL) { 8222 /* now try lookup based on a minor name ending with ",raw" */ 8223 len1 = sizeof (DISK_RAW_MINOR) - 1; 8224 for (i = 0; i < cb_arg.count; i++) { 8225 len2 = strlen(cb_arg.link_contents[i]); 8226 if (len2 >= len1 && 8227 strcmp(cb_arg.link_contents[i] + len2 - len1, 8228 DISK_RAW_MINOR) == 0) { 8229 dev_name = s_strdup(cb_arg.dev_names[i]); 8230 break; 8231 } 8232 } 8233 } 8234 8235 free_dev_names(&cb_arg); 8236 8237 if (dev_name == NULL) 8238 return (NULL); 8239 if (strlen(dev_name) == 0) { 8240 free(dev_name); 8241 return (NULL); 8242 } 8243 8244 /* if the name contains slice or partition number strip it */ 8245 p = dev_name + strlen(dev_name) - 1; 8246 if (isdigit(*p)) { 8247 while (p != dev_name && isdigit(*p)) 8248 p--; 8249 if (*p == 's' || *p == 'p') 8250 *p = '\0'; 8251 } 8252 8253 return (dev_name); 8254 } 8255 8256 static char * 8257 lookup_lofi_dev_name(char *node_path, char *minor) 8258 { 8259 struct devlink_cb_arg cb_arg; 8260 char *dev_name = NULL; 8261 int i; 8262 int len1, len2; 8263 8264 cb_arg.count = 0; 8265 cb_arg.rv = 0; 8266 (void) di_devlink_cache_walk(devlink_cache, NULL, node_path, 8267 DI_PRIMARY_LINK, &cb_arg, devlink_cb); 8268 8269 if (cb_arg.rv == -1 || cb_arg.count == 0) 8270 return (NULL); 8271 8272 /* lookup based on a minor name ending with ",raw" */ 8273 len1 = strlen(minor); 8274 for (i = 0; i < cb_arg.count; i++) { 8275 len2 = strlen(cb_arg.link_contents[i]); 8276 if (len2 >= len1 && 8277 strcmp(cb_arg.link_contents[i] + len2 - len1, 8278 minor) == 0) { 8279 dev_name = s_strdup(cb_arg.dev_names[i]); 8280 break; 8281 } 8282 } 8283 8284 free_dev_names(&cb_arg); 8285 8286 if (dev_name == NULL) 8287 return (NULL); 8288 if (strlen(dev_name) == 0) { 8289 free(dev_name); 8290 return (NULL); 8291 } 8292 8293 return (dev_name); 8294 } 8295 8296 static char * 8297 lookup_network_dev_name(char *node_path, char *driver_name) 8298 { 8299 char *dev_name = NULL; 8300 char phys_path[MAXPATHLEN]; 8301 8302 if (lookup_dev_name(node_path, &dev_name) == -1) 8303 return (NULL); 8304 8305 if (dev_name == NULL) { 8306 /* dlpi style-2 only interface */ 8307 (void) snprintf(phys_path, sizeof (phys_path), 8308 "/pseudo/clone@0:%s", driver_name); 8309 if (lookup_dev_name(phys_path, &dev_name) == -1 || 8310 dev_name == NULL) 8311 return (NULL); 8312 } 8313 8314 return (dev_name); 8315 } 8316 8317 static char * 8318 lookup_printer_dev_name(char *node_path) 8319 { 8320 struct devlink_cb_arg cb_arg; 8321 char *dev_name = NULL; 8322 int i; 8323 8324 #define DEV_PRINTERS "/dev/printers/" 8325 8326 cb_arg.count = 0; 8327 cb_arg.rv = 0; 8328 (void) di_devlink_cache_walk(devlink_cache, NULL, node_path, 8329 DI_PRIMARY_LINK, &cb_arg, devlink_cb); 8330 8331 if (cb_arg.rv == -1 || cb_arg.count == 0) 8332 return (NULL); 8333 8334 /* first try lookup based on /dev/printers name */ 8335 for (i = 0; i < cb_arg.count; i++) { 8336 if (strncmp(cb_arg.dev_names[i], DEV_PRINTERS, 8337 sizeof (DEV_PRINTERS) - 1) == 0) { 8338 dev_name = s_strdup(cb_arg.dev_names[i]); 8339 break; 8340 } 8341 } 8342 8343 /* fallback to the first name */ 8344 if ((dev_name == NULL) && (cb_arg.count > 0)) 8345 dev_name = s_strdup(cb_arg.dev_names[0]); 8346 8347 free_dev_names(&cb_arg); 8348 8349 return (dev_name); 8350 } 8351 8352 /* 8353 * Build an nvlist containing all attributes for devfs events. 8354 * Returns nvlist pointer on success, NULL on failure. 8355 */ 8356 static nvlist_t * 8357 build_event_attributes(char *class, char *subclass, char *node_path, 8358 di_node_t node, char *driver_name, int instance, char *minor) 8359 { 8360 nvlist_t *nvl; 8361 int err = 0; 8362 di_prop_t prop; 8363 int count; 8364 char *prop_name; 8365 int x; 8366 char *dev_name = NULL; 8367 int dev_name_lookup_err = 0; 8368 8369 if ((err = nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0)) != 0) { 8370 nvl = NULL; 8371 goto out; 8372 } 8373 8374 if ((err = nvlist_add_int32(nvl, EV_VERSION, EV_V1)) != 0) 8375 goto out; 8376 8377 if ((err = nvlist_add_string(nvl, DEV_PHYS_PATH, node_path)) != 0) 8378 goto out; 8379 8380 if (strcmp(class, EC_DEV_ADD) != 0 && 8381 strcmp(class, EC_DEV_REMOVE) != 0) 8382 return (nvl); 8383 8384 if (driver_name == NULL || instance == -1) 8385 goto out; 8386 8387 if (strcmp(subclass, ESC_DISK) == 0) { 8388 if ((dev_name = lookup_disk_dev_name(node_path)) == NULL) { 8389 dev_name_lookup_err = 1; 8390 goto out; 8391 } 8392 } else if (strcmp(subclass, ESC_NETWORK) == 0) { 8393 if ((dev_name = lookup_network_dev_name(node_path, driver_name)) 8394 == NULL) { 8395 dev_name_lookup_err = 1; 8396 goto out; 8397 } 8398 } else if (strcmp(subclass, ESC_PRINTER) == 0) { 8399 if ((dev_name = lookup_printer_dev_name(node_path)) == NULL) { 8400 dev_name_lookup_err = 1; 8401 goto out; 8402 } 8403 } else if (strcmp(subclass, ESC_LOFI) == 0) { 8404 /* 8405 * The raw minor node is created or removed after the block 8406 * node. Lofi devfs events are dependent on this behavior. 8407 * Generate the sysevent only for the raw minor node. 8408 */ 8409 if (strstr(minor, "raw") == NULL) { 8410 if (nvl) { 8411 nvlist_free(nvl); 8412 } 8413 return (NULL); 8414 } 8415 if ((dev_name = lookup_lofi_dev_name(node_path, minor)) == 8416 NULL) { 8417 dev_name_lookup_err = 1; 8418 goto out; 8419 } 8420 } 8421 8422 if (dev_name) { 8423 if ((err = nvlist_add_string(nvl, DEV_NAME, dev_name)) != 0) 8424 goto out; 8425 free(dev_name); 8426 dev_name = NULL; 8427 } 8428 8429 if ((err = nvlist_add_string(nvl, DEV_DRIVER_NAME, driver_name)) != 0) 8430 goto out; 8431 8432 if ((err = nvlist_add_int32(nvl, DEV_INSTANCE, instance)) != 0) 8433 goto out; 8434 8435 if (strcmp(class, EC_DEV_ADD) == 0) { 8436 /* add properties */ 8437 count = 0; 8438 for (prop = di_prop_next(node, DI_PROP_NIL); 8439 prop != DI_PROP_NIL && count < MAX_PROP_COUNT; 8440 prop = di_prop_next(node, prop)) { 8441 8442 if (di_prop_devt(prop) != DDI_DEV_T_NONE) 8443 continue; 8444 8445 if ((x = add_property(nvl, prop)) == 0) 8446 count++; 8447 else if (x == -1) { 8448 if ((prop_name = di_prop_name(prop)) == NULL) 8449 prop_name = ""; 8450 err_print(PROP_ADD_FAILED, prop_name); 8451 goto out; 8452 } 8453 } 8454 } 8455 8456 return (nvl); 8457 8458 out: 8459 if (nvl) 8460 nvlist_free(nvl); 8461 8462 if (dev_name) 8463 free(dev_name); 8464 8465 if (dev_name_lookup_err) 8466 err_print(DEV_NAME_LOOKUP_FAILED, node_path); 8467 else 8468 err_print(BUILD_EVENT_ATTR_FAILED, (err) ? strerror(err) : ""); 8469 return (NULL); 8470 } 8471 8472 static void 8473 log_event(char *class, char *subclass, nvlist_t *nvl) 8474 { 8475 sysevent_id_t eid; 8476 8477 if (sysevent_post_event(class, subclass, "SUNW", DEVFSADMD, 8478 nvl, &eid) != 0) { 8479 err_print(LOG_EVENT_FAILED, strerror(errno)); 8480 } 8481 } 8482 8483 /* 8484 * When devfsadmd needs to generate sysevents, they are queued for later 8485 * delivery this allows them to be delivered after the devlinks db cache has 8486 * been flushed guaranteeing that applications consuming these events have 8487 * access to an accurate devlinks db. The queue is a FIFO, sysevents to be 8488 * inserted in the front of the queue and consumed off the back. 8489 */ 8490 static void 8491 enqueue_sysevent(char *class, char *subclass, nvlist_t *nvl) 8492 { 8493 syseventq_t *tmp; 8494 8495 if ((tmp = s_zalloc(sizeof (*tmp))) == NULL) 8496 return; 8497 8498 tmp->class = s_strdup(class); 8499 tmp->subclass = s_strdup(subclass); 8500 tmp->nvl = nvl; 8501 8502 (void) mutex_lock(&syseventq_mutex); 8503 if (syseventq_front != NULL) 8504 syseventq_front->next = tmp; 8505 else 8506 syseventq_back = tmp; 8507 syseventq_front = tmp; 8508 (void) mutex_unlock(&syseventq_mutex); 8509 } 8510 8511 static void 8512 process_syseventq() 8513 { 8514 (void) mutex_lock(&syseventq_mutex); 8515 while (syseventq_back != NULL) { 8516 syseventq_t *tmp = syseventq_back; 8517 8518 vprint(CHATTY_MID, "sending queued event: %s, %s\n", 8519 tmp->class, tmp->subclass); 8520 8521 log_event(tmp->class, tmp->subclass, tmp->nvl); 8522 8523 if (tmp->class != NULL) 8524 free(tmp->class); 8525 if (tmp->subclass != NULL) 8526 free(tmp->subclass); 8527 if (tmp->nvl != NULL) 8528 nvlist_free(tmp->nvl); 8529 syseventq_back = syseventq_back->next; 8530 if (syseventq_back == NULL) 8531 syseventq_front = NULL; 8532 free(tmp); 8533 } 8534 (void) mutex_unlock(&syseventq_mutex); 8535 } 8536 8537 static void 8538 build_and_enq_event(char *class, char *subclass, char *node_path, 8539 di_node_t node, char *minor) 8540 { 8541 nvlist_t *nvl; 8542 8543 vprint(CHATTY_MID, "build_and_enq_event(%s, %s, %s, 0x%8.8x)\n", 8544 class, subclass, node_path, (int)node); 8545 8546 if (node != DI_NODE_NIL) 8547 nvl = build_event_attributes(class, subclass, node_path, node, 8548 di_driver_name(node), di_instance(node), minor); 8549 else 8550 nvl = build_event_attributes(class, subclass, node_path, node, 8551 NULL, -1, minor); 8552 8553 if (nvl) { 8554 enqueue_sysevent(class, subclass, nvl); 8555 } 8556 } 8557 8558 /* 8559 * is_blank() returns 1 (true) if a line specified is composed of 8560 * whitespace characters only. otherwise, it returns 0 (false). 8561 * 8562 * Note. the argument (line) must be null-terminated. 8563 */ 8564 static int 8565 is_blank(char *line) 8566 { 8567 for (/* nothing */; *line != '\0'; line++) 8568 if (!isspace(*line)) 8569 return (0); 8570 return (1); 8571 } 8572 8573 /* 8574 * Functions to deal with the no-further-processing hash 8575 */ 8576 8577 static void 8578 nfphash_create(void) 8579 { 8580 assert(nfp_hash == NULL); 8581 nfp_hash = s_zalloc(NFP_HASH_SZ * sizeof (item_t *)); 8582 } 8583 8584 static int 8585 nfphash_fcn(char *key) 8586 { 8587 int i; 8588 uint64_t sum = 0; 8589 8590 for (i = 0; key[i] != '\0'; i++) { 8591 sum += (uchar_t)key[i]; 8592 } 8593 8594 return (sum % NFP_HASH_SZ); 8595 } 8596 8597 static item_t * 8598 nfphash_lookup(char *key) 8599 { 8600 int index; 8601 item_t *ip; 8602 8603 index = nfphash_fcn(key); 8604 8605 assert(index >= 0); 8606 8607 for (ip = nfp_hash[index]; ip; ip = ip->i_next) { 8608 if (strcmp(ip->i_key, key) == 0) 8609 return (ip); 8610 } 8611 8612 return (NULL); 8613 } 8614 8615 static void 8616 nfphash_insert(char *key) 8617 { 8618 item_t *ip; 8619 int index; 8620 8621 index = nfphash_fcn(key); 8622 8623 assert(index >= 0); 8624 8625 ip = s_zalloc(sizeof (item_t)); 8626 ip->i_key = s_strdup(key); 8627 8628 ip->i_next = nfp_hash[index]; 8629 nfp_hash[index] = ip; 8630 } 8631 8632 static void 8633 nfphash_destroy(void) 8634 { 8635 int i; 8636 item_t *ip; 8637 8638 for (i = 0; i < NFP_HASH_SZ; i++) { 8639 /*LINTED*/ 8640 while (ip = nfp_hash[i]) { 8641 nfp_hash[i] = ip->i_next; 8642 free(ip->i_key); 8643 free(ip); 8644 } 8645 } 8646 8647 free(nfp_hash); 8648 nfp_hash = NULL; 8649 } 8650 8651 static int 8652 devname_kcall(int subcmd, void *args) 8653 { 8654 int error = 0; 8655 char *nvlbuf = NULL; 8656 size_t nvlsize; 8657 8658 switch (subcmd) { 8659 case MODDEVNAME_NSMAPS: 8660 error = nvlist_pack((nvlist_t *)args, &nvlbuf, &nvlsize, 0, 0); 8661 if (error) { 8662 err_print("packing MODDEVNAME_NSMAPS failed\n"); 8663 break; 8664 } 8665 error = modctl(MODDEVNAME, subcmd, nvlbuf, nvlsize); 8666 if (error) { 8667 vprint(INFO_MID, "modctl(MODDEVNAME, " 8668 "MODDEVNAME_NSMAPS) failed - %s\n", 8669 strerror(errno)); 8670 } 8671 free(nvlbuf); 8672 nvlist_free(args); 8673 break; 8674 case MODDEVNAME_LOOKUPDOOR: 8675 error = modctl(MODDEVNAME, subcmd, (uintptr_t)args); 8676 if (error) { 8677 vprint(INFO_MID, "modctl(MODDEVNAME, " 8678 "MODDEVNAME_LOOKUPDOOR) failed - %s\n", 8679 strerror(errno)); 8680 } 8681 break; 8682 default: 8683 error = EINVAL; 8684 break; 8685 } 8686 return (error); 8687 } 8688 8689 static void 8690 devname_setup_nsmaps(void) 8691 { 8692 int error = 0; 8693 8694 if (devname_first_call) { 8695 devname_first_call = 0; 8696 } 8697 8698 error = di_devname_get_mapinfo(DEVNAME_MASTER_MAP, &devname_maps); 8699 8700 if (error) { 8701 vprint(DEVNAME_MID, "devname_setup_nsmaps: non-existing/empty" 8702 "%s\n", DEVNAME_MASTER_MAP); 8703 } else { 8704 di_devname_print_mapinfo(devname_maps); 8705 8706 /* pass down the existing map names to kernel */ 8707 (void) devname_kcall(MODDEVNAME_NSMAPS, (void *)devname_maps); 8708 } 8709 } 8710 8711 static void 8712 devname_ns_services(uint8_t cmd, char *key, char *map) 8713 { 8714 nvlist_t *nvl = NULL; 8715 int32_t error = 0; 8716 sdev_door_res_t res; 8717 8718 vprint(DEVNAME_MID, "devname_ns_services: cmd %d key %s map %s\n", 8719 cmd, key, map); 8720 8721 switch (cmd) { 8722 case DEVFSADMD_NS_LOOKUP: 8723 vprint(DEVNAME_MID, "calling di_devname_get_mapent\n"); 8724 error = di_devname_get_mapent(key, map, &nvl); 8725 if (nvl == NULL) { 8726 error = DEVFSADM_NS_FAILED; 8727 goto done; 8728 } 8729 8730 if (error) { 8731 nvlist_free(nvl); 8732 goto done; 8733 } 8734 8735 if (devname_debug_msg) 8736 di_devname_print_mapinfo(nvl); 8737 8738 vprint(DEVNAME_MID, "calling di_devname_action_on_key for %d\n", 8739 cmd); 8740 error = di_devname_action_on_key(nvl, cmd, key, (void *)&res); 8741 nvlist_free(nvl); 8742 break; 8743 case DEVFSADMD_NS_READDIR: 8744 vprint(DEVNAME_MID, "calling di_devname_get_mapinfo for cmd %d" 8745 "\n", cmd); 8746 error = di_devname_get_mapinfo(map, &nvl); 8747 if (nvl == NULL) { 8748 error = DEVFSADM_NS_FAILED; 8749 goto done; 8750 } 8751 8752 if (error) { 8753 nvlist_free(nvl); 8754 goto done; 8755 } 8756 8757 if (devname_debug_msg) 8758 di_devname_print_mapinfo(nvl); 8759 8760 vprint(DEVNAME_MID, "calling di_devname_action_on_key\n"); 8761 error = di_devname_action_on_key(nvl, cmd, key, (void *)&res); 8762 nvlist_free(nvl); 8763 break; 8764 default: 8765 error = DEVFSADM_RUN_NOTSUP; 8766 break; 8767 } 8768 8769 done: 8770 vprint(DEVNAME_MID, "error %d\n", error); 8771 res.devfsadm_error = error; 8772 (void) door_return((char *)&res, sizeof (struct sdev_door_res), 8773 NULL, 0); 8774 } 8775 8776 /* ARGSUSED */ 8777 static void 8778 devname_lookup_handler(void *cookie, char *argp, size_t arg_size, 8779 door_desc_t *dp, uint_t n_desc) 8780 { 8781 int32_t error = 0; 8782 door_cred_t dcred; 8783 struct dca_impl dci; 8784 uint8_t cmd; 8785 char *ns_map, *ns_name; 8786 sdev_door_res_t res; 8787 sdev_door_arg_t *args; 8788 8789 if (argp == NULL || arg_size == 0) { 8790 vprint(DEVNAME_MID, "devname_lookup_handler: argp wrong\n"); 8791 error = DEVFSADM_RUN_INVALID; 8792 goto done; 8793 } 8794 vprint(DEVNAME_MID, "devname_lookup_handler\n"); 8795 8796 if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) { 8797 vprint(DEVNAME_MID, "devname_lookup_handler: cred wrong\n"); 8798 error = DEVFSADM_RUN_EPERM; 8799 goto done; 8800 } 8801 8802 args = (sdev_door_arg_t *)argp; 8803 cmd = args->devfsadm_cmd; 8804 8805 vprint(DEVNAME_MID, "devname_lookup_handler: cmd %d\n", cmd); 8806 switch (cmd) { 8807 case DEVFSADMD_NS_LOOKUP: 8808 case DEVFSADMD_NS_READDIR: 8809 ns_name = s_strdup(args->ns_hdl.ns_name); 8810 ns_map = s_strdup(args->ns_hdl.ns_map); 8811 8812 vprint(DEVNAME_MID, " ns_name %s ns_map %s\n", ns_name, ns_map); 8813 if (ns_name == NULL || ns_map == NULL) { 8814 error = DEVFSADM_RUN_INVALID; 8815 goto done; 8816 } 8817 8818 devname_ns_services(cmd, ns_name, ns_map); 8819 return; 8820 case DEVFSADMD_RUN_ALL: 8821 /* 8822 * run "devfsadm" 8823 */ 8824 dci.dci_root = "/"; 8825 dci.dci_minor = NULL; 8826 dci.dci_driver = NULL; 8827 dci.dci_error = 0; 8828 dci.dci_flags = 0; 8829 dci.dci_arg = NULL; 8830 8831 lock_dev(); 8832 update_drvconf((major_t)-1); 8833 dci.dci_flags |= DCA_FLUSH_PATHINST; 8834 8835 pre_and_post_cleanup(RM_PRE); 8836 devi_tree_walk(&dci, DINFOFORCE|DI_CACHE_SNAPSHOT_FLAGS, NULL); 8837 error = (int32_t)dci.dci_error; 8838 if (!error) { 8839 pre_and_post_cleanup(RM_POST); 8840 update_database = TRUE; 8841 unlock_dev(SYNC_STATE); 8842 update_database = FALSE; 8843 } else { 8844 if (DEVFSADM_DEBUG_ON) { 8845 vprint(INFO_MID, "devname_lookup_handler: " 8846 "DEVFSADMD_RUN_ALL failed\n"); 8847 } 8848 8849 unlock_dev(SYNC_STATE); 8850 } 8851 break; 8852 default: 8853 /* log an error here? */ 8854 error = DEVFSADM_RUN_NOTSUP; 8855 break; 8856 } 8857 8858 done: 8859 vprint(DEVNAME_MID, "devname_lookup_handler: error %d\n", error); 8860 res.devfsadm_error = error; 8861 (void) door_return((char *)&res, sizeof (struct sdev_door_res), 8862 NULL, 0); 8863 } 8864 8865 8866 di_devlink_handle_t 8867 devfsadm_devlink_cache(void) 8868 { 8869 return (devlink_cache); 8870 } 8871 8872 int 8873 devfsadm_reserve_id_cache(devlink_re_t re_array[], enumerate_file_t *head) 8874 { 8875 enumerate_file_t *entry; 8876 int nelem; 8877 int i; 8878 int subex; 8879 char *re; 8880 size_t size; 8881 regmatch_t *pmch; 8882 8883 /* 8884 * Check the <RE, subexp> array passed in and compile it. 8885 */ 8886 for (i = 0; re_array[i].d_re; i++) { 8887 if (re_array[i].d_subexp == 0) { 8888 err_print("bad subexp value in RE: %s\n", 8889 re_array[i].d_re); 8890 goto bad_re; 8891 } 8892 8893 re = re_array[i].d_re; 8894 if (regcomp(&re_array[i].d_rcomp, re, REG_EXTENDED) != 0) { 8895 err_print("reg. exp. failed to compile: %s\n", re); 8896 goto bad_re; 8897 } 8898 subex = re_array[i].d_subexp; 8899 nelem = subex + 1; 8900 re_array[i].d_pmatch = s_malloc(sizeof (regmatch_t) * nelem); 8901 } 8902 8903 entry = head ? head : enumerate_reserved; 8904 for (; entry; entry = entry->er_next) { 8905 if (entry->er_id) { 8906 vprint(RSBY_MID, "entry %s already has ID %s\n", 8907 entry->er_file, entry->er_id); 8908 continue; 8909 } 8910 for (i = 0; re_array[i].d_re; i++) { 8911 subex = re_array[i].d_subexp; 8912 pmch = re_array[i].d_pmatch; 8913 if (regexec(&re_array[i].d_rcomp, entry->er_file, 8914 subex + 1, pmch, 0) != 0) { 8915 /* No match */ 8916 continue; 8917 } 8918 size = pmch[subex].rm_eo - pmch[subex].rm_so; 8919 entry->er_id = s_malloc(size + 1); 8920 (void) strncpy(entry->er_id, 8921 &entry->er_file[pmch[subex].rm_so], size); 8922 entry->er_id[size] = '\0'; 8923 if (head) { 8924 vprint(RSBY_MID, "devlink(%s) matches RE(%s). " 8925 "ID is %s\n", entry->er_file, 8926 re_array[i].d_re, entry->er_id); 8927 } else { 8928 vprint(RSBY_MID, "rsrv entry(%s) matches " 8929 "RE(%s) ID is %s\n", entry->er_file, 8930 re_array[i].d_re, entry->er_id); 8931 } 8932 break; 8933 } 8934 } 8935 8936 for (i = 0; re_array[i].d_re; i++) { 8937 regfree(&re_array[i].d_rcomp); 8938 assert(re_array[i].d_pmatch); 8939 free(re_array[i].d_pmatch); 8940 } 8941 8942 entry = head ? head : enumerate_reserved; 8943 for (; entry; entry = entry->er_next) { 8944 if (entry->er_id == NULL) 8945 continue; 8946 if (head) { 8947 vprint(RSBY_MID, "devlink: %s\n", entry->er_file); 8948 vprint(RSBY_MID, "ID: %s\n", entry->er_id); 8949 } else { 8950 vprint(RSBY_MID, "reserve file entry: %s\n", 8951 entry->er_file); 8952 vprint(RSBY_MID, "reserve file id: %s\n", 8953 entry->er_id); 8954 } 8955 } 8956 8957 return (DEVFSADM_SUCCESS); 8958 8959 bad_re: 8960 for (i = i-1; i >= 0; i--) { 8961 regfree(&re_array[i].d_rcomp); 8962 assert(re_array[i].d_pmatch); 8963 free(re_array[i].d_pmatch); 8964 } 8965 return (DEVFSADM_FAILURE); 8966 } 8967 8968 /* 8969 * Return 1 if we have reserved links. 8970 */ 8971 int 8972 devfsadm_have_reserved() 8973 { 8974 return (enumerate_reserved ? 1 : 0); 8975 } 8976 8977 /* 8978 * This functions errs on the side of caution. If there is any error 8979 * we assume that the devlink is *not* reserved 8980 */ 8981 int 8982 devfsadm_is_reserved(devlink_re_t re_array[], char *devlink) 8983 { 8984 int match; 8985 enumerate_file_t estruct = {NULL}; 8986 enumerate_file_t *entry; 8987 8988 match = 0; 8989 estruct.er_file = devlink; 8990 estruct.er_id = NULL; 8991 estruct.er_next = NULL; 8992 8993 if (devfsadm_reserve_id_cache(re_array, &estruct) != DEVFSADM_SUCCESS) { 8994 err_print("devfsadm_is_reserved: devlink (%s) does not " 8995 "match RE\n", devlink); 8996 return (0); 8997 } 8998 if (estruct.er_id == NULL) { 8999 err_print("devfsadm_is_reserved: ID derived from devlink %s " 9000 "is NULL\n", devlink); 9001 return (0); 9002 } 9003 9004 entry = enumerate_reserved; 9005 for (; entry; entry = entry->er_next) { 9006 if (entry->er_id == NULL) 9007 continue; 9008 if (strcmp(entry->er_id, estruct.er_id) != 0) 9009 continue; 9010 match = 1; 9011 vprint(RSBY_MID, "reserve file entry (%s) and devlink (%s) " 9012 "match\n", entry->er_file, devlink); 9013 break; 9014 } 9015 9016 free(estruct.er_id); 9017 return (match); 9018 } 9019