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