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