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