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