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