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