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