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