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