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