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