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