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