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