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