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