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