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