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