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