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