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