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