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