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