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