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