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