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 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #pragma ident   "@(#)devfsadm.c 1.98    08/05/07 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 <deflt.h>
  41 #include <tsol/label.h>
  42 #include <bsm/devices.h>
  43 #include <bsm/devalloc.h>
  44 #include <utime.h>
  45 #include <sys/param.h>
  46 #include <bsm/libbsm.h>
  47 #include "devfsadm_impl.h"
  48 
  49 /* externs from devalloc.c */
  50 extern void  _reset_devalloc(int);
  51 extern void _update_devalloc_db(devlist_t *, int, int, char *, char *);
  52 extern int _da_check_for_usb(char *, char *);
  53 
  54 /* create or remove nodes or links. unset with -n */
  55 static int file_mods = TRUE;
  56 
  57 /* cleanup mode.  Set with -C */
  58 static int cleanup = FALSE;
  59 
  60 /* devlinks -d compatibility */
  61 static int devlinks_debug = FALSE;
  62 
  63 /* flag to check if system is labeled */
  64 int system_labeled = FALSE;
  65 
  66 /* flag to enable/disable device allocation with -e/-d */
  67 static int devalloc_flag = 0;
  68 
  69 /* flag that indicates if device allocation is on or not */
  70 static int devalloc_is_on = 0;
  71 
  72 /* flag to update device allocation database for this device type */
  73 static int update_devdb = 0;
  74 
  75 /*
  76  * devices to be deallocated with -d :
  77  *      audio, floppy, cd, floppy, tape, rmdisk.
  78  */
  79 static char *devalloc_list[10] = {DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_CD_CHAN,
  80                                     DDI_NT_FD, DDI_NT_TAPE, DDI_NT_BLOCK_CHAN,
  81                                     DDI_NT_UGEN, DDI_NT_USB_ATTACHMENT_POINT,
  82                                     DDI_NT_SCSI_NEXUS, NULL};
  83 
  84 /* list of allocatable devices */
  85 static devlist_t devlist;
  86 
  87 /* load a single driver only.  set with -i */
  88 static int single_drv = FALSE;
  89 static char *driver = NULL;
  90 
  91 /* attempt to load drivers or defer attach nodes */
  92 static int load_attach_drv = TRUE;
  93 
  94 /* set if invoked via /usr/lib/devfsadm/devfsadmd */
  95 static int daemon_mode = FALSE;
  96 
  97 /* output directed to syslog during daemon mode if set */
  98 static int logflag = FALSE;
  99 
 100 /* build links in /dev.  -x to turn off */
 101 static int build_dev = TRUE;
 102 
 103 /* build nodes in /devices.  -y to turn off */
 104 static int build_devices = TRUE;
 105 
 106 /* -z to turn off */
 107 static int flush_path_to_inst_enable = TRUE;
 108 
 109 /* variables used for path_to_inst flushing */
 110 static int inst_count = 0;
 111 static mutex_t count_lock;
 112 static cond_t cv;
 113 
 114 /* variables for minor_fini thread */
 115 static mutex_t minor_fini_mutex;
 116 static int minor_fini_canceled = TRUE;
 117 static int minor_fini_delayed = FALSE;
 118 static cond_t minor_fini_cv;
 119 static int minor_fini_timeout = MINOR_FINI_TIMEOUT_DEFAULT;
 120 
 121 /* single-threads /dev modification */
 122 static sema_t dev_sema;
 123 
 124 /* the program we were invoked as; ie argv[0] */
 125 static char *prog;
 126 
 127 /* pointers to create/remove link lists */
 128 static create_list_t *create_head = NULL;
 129 static remove_list_t *remove_head = NULL;
 130 
 131 /*  supports the class -c option */
 132 static char **classes = NULL;
 133 static int num_classes = 0;
 134 
 135 /* used with verbose option -v or -V */
 136 static int num_verbose = 0;
 137 static char **verbose = NULL;
 138 
 139 static struct mperm *minor_perms = NULL;
 140 static driver_alias_t *driver_aliases = NULL;
 141 
 142 /* set if -r alternate root given */
 143 static char *root_dir = "";
 144 
 145 /* /devices or <rootdir>/devices */
 146 static char *devices_dir  = DEVICES;
 147 
 148 /* /dev or <rootdir>/dev */
 149 static char *dev_dir = DEV;
 150 
 151 /* /etc/dev or <rootdir>/etc/dev */
 152 static char *etc_dev_dir = ETCDEV;
 153 
 154 /*
 155  * writable root (for lock files and doors during install).
 156  * This is also root dir for /dev attr dir during install.
 157  */
 158 static char *attr_root = NULL;
 159 
 160 /* /etc/path_to_inst unless -p used */
 161 static char *inst_file = INSTANCE_FILE;
 162 
 163 /* /usr/lib/devfsadm/linkmods unless -l used */
 164 static char *module_dirs = MODULE_DIRS;
 165 
 166 /* default uid/gid used if /etc/minor_perm entry not found */
 167 static uid_t root_uid;
 168 static gid_t sys_gid;
 169 
 170 /* /etc/devlink.tab unless devlinks -t used */
 171 static char *devlinktab_file = NULL;
 172 
 173 /* File and data structure to reserve enumerate IDs */
 174 static char *enumerate_file = ENUMERATE_RESERVED;
 175 static enumerate_file_t *enumerate_reserved = NULL;
 176 
 177 /* set if /dev link is new. speeds up rm_stale_links */
 178 static int linknew = TRUE;
 179 
 180 /* variables for devlink.tab compat processing */
 181 static devlinktab_list_t *devlinktab_list = NULL;
 182 static unsigned int devlinktab_line = 0;
 183 
 184 /* cache head for devfsadm_enumerate*() functions */
 185 static numeral_set_t *head_numeral_set = NULL;
 186 
 187 /* list list of devfsadm modules */
 188 static module_t *module_head = NULL;
 189 
 190 /* name_to_major list used in utility function */
 191 static n2m_t *n2m_list = NULL;
 192 
 193 /* cache of some links used for performance */
 194 static linkhead_t *headlinkhead = NULL;
 195 
 196 /* locking variables to prevent multiples writes to /dev */
 197 static int hold_dev_lock = FALSE;
 198 static int hold_daemon_lock = FALSE;
 199 static int dev_lock_fd;
 200 static int daemon_lock_fd;
 201 static char dev_lockfile[PATH_MAX + 1];
 202 static char daemon_lockfile[PATH_MAX + 1];
 203 
 204 /* last devinfo node/minor processed. used for performance */
 205 static di_node_t lnode;
 206 static di_minor_t lminor;
 207 static char lphy_path[PATH_MAX + 1] = {""};
 208 
 209 /* Globals used by the link database */
 210 static di_devlink_handle_t devlink_cache;
 211 static int update_database = FALSE;
 212 
 213 /* Globals used to set logindev perms */
 214 static struct login_dev *login_dev_cache = NULL;
 215 static int login_dev_enable = FALSE;
 216 
 217 /* Global to use devinfo snapshot cache */
 218 static int use_snapshot_cache = FALSE;
 219 
 220 /* Global for no-further-processing hash */
 221 static item_t **nfp_hash;
 222 static mutex_t  nfp_mutex = DEFAULTMUTEX;
 223 
 224 /*
 225  * Packaged directories - not removed even when empty.
 226  * The dirs must be listed in canonical form
 227  * i.e. without leading "/dev/"
 228  */
 229 static char *packaged_dirs[] =
 230         {"dsk", "rdsk", "term", NULL};
 231 
 232 /* RCM related globals */
 233 static void *librcm_hdl;
 234 static rcm_handle_t *rcm_hdl = NULL;
 235 static thread_t process_rcm_events_tid;
 236 static struct rcm_eventq *volatile rcm_eventq_head = NULL;
 237 static struct rcm_eventq *rcm_eventq_tail = NULL;
 238 static mutex_t rcm_eventq_lock;
 239 static cond_t rcm_eventq_cv;
 240 static volatile int need_to_exit_rcm_event_thread = 0;
 241 
 242 /* Devname globals */
 243 static int devname_debug_msg = 1;
 244 static nvlist_t *devname_maps = NULL;
 245 static int devname_first_call = 1;
 246 static int load_devname_nsmaps = FALSE;
 247 static int lookup_door_fd = -1;
 248 static char *lookup_door_path;
 249 
 250 static void load_dev_acl(void);
 251 static void update_drvconf(major_t);
 252 static void check_reconfig_state(void);
 253 static void devname_setup_nsmaps(void);
 254 static int s_stat(const char *, struct stat *);
 255 
 256 static int is_blank(char *);
 257 
 258 /* sysevent queue related globals */
 259 static mutex_t  syseventq_mutex = DEFAULTMUTEX;
 260 static syseventq_t *syseventq_front;
 261 static syseventq_t *syseventq_back;
 262 static void process_syseventq();
 263 
 264 int
 265 main(int argc, char *argv[])
 266 {
 267         struct passwd *pw;
 268         struct group *gp;
 269         pid_t pid;
 270         int cond = 0;
 271 
 272         (void) setlocale(LC_ALL, "");
 273         (void) textdomain(TEXT_DOMAIN);
 274 
 275         if ((prog = strrchr(argv[0], '/')) == NULL) {
 276                 prog = argv[0];
 277         } else {
 278                 prog++;
 279         }
 280 
 281         if (getuid() != 0) {
 282                 err_print(MUST_BE_ROOT);
 283                 devfsadm_exit(1);
 284         }
 285 
 286         /*
 287          * Close all files except stdin/stdout/stderr
 288          */
 289         closefrom(3);
 290 
 291         if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) {
 292                 root_uid = pw->pw_uid;
 293         } else {
 294                 err_print(CANT_FIND_USER, DEFAULT_DEV_USER);
 295                 root_uid = (uid_t)0;    /* assume 0 is root */
 296         }
 297 
 298         /* the default group is sys */
 299 
 300         if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) {
 301                 sys_gid = gp->gr_gid;
 302         } else {
 303                 err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP);
 304                 sys_gid = (gid_t)3;     /* assume 3 is sys */
 305         }
 306 
 307         (void) umask(0);
 308 
 309         system_labeled = is_system_labeled();
 310         if (system_labeled == FALSE) {
 311                 /*
 312                  * is_system_labeled() will return false in case we are
 313                  * starting before the first reboot after Trusted Extensions
 314                  * is enabled.  Check the setting in /etc/system to see if
 315                  * TX is enabled (even if not yet booted).
 316                  */
 317                 if (defopen("/etc/system") == 0) {
 318                         if (defread("set sys_labeling=1") != NULL)
 319                                 system_labeled = TRUE;
 320 
 321                         /* close defaults file */
 322                         (void) defopen(NULL);
 323                 }
 324         }
 325         /*
 326          * Check if device allocation is enabled.
 327          */
 328         if (system_labeled) {
 329                 /*
 330                  * In TX, the first line in /etc/security/device_allocate has
 331                  * DEVICE_ALLOCATION=ON if the feature is enabled.
 332                  */
 333                 devalloc_is_on = da_is_on();
 334         } else if (auditon(A_GETCOND, (caddr_t)&cond, sizeof (cond)) == 0) {
 335                 /*
 336                  * Device allocation (and auditing) is enabled if BSM is
 337                  * enabled. auditon returns -1 and sets errno to EINVAL if BSM
 338                  * is not enabled.
 339                  */
 340                 devalloc_is_on = 1;
 341         }
 342 
 343 #ifdef DEBUG
 344         if (system_labeled == FALSE) {
 345                 struct stat tx_stat;
 346 
 347                 /* test hook: see also mkdevalloc.c and allocate.c */
 348                 system_labeled = is_system_labeled_debug(&tx_stat);
 349         }
 350 #endif
 351 
 352         parse_args(argc, argv);
 353 
 354         (void) sema_init(&dev_sema, 1, USYNC_THREAD, NULL);
 355 
 356         /* Initialize device allocation list */
 357         devlist.audio = devlist.cd = devlist.floppy = devlist.tape =
 358             devlist.rmdisk = NULL;
 359 
 360         if (daemon_mode == TRUE) {
 361                 /*
 362                  * Build /dev and /devices before daemonizing if
 363                  * reconfig booting and daemon invoked with alternate
 364                  * root. This is to support install.
 365                  */
 366                 if (getenv(RECONFIG_BOOT) != NULL && root_dir[0] != '\0') {
 367                         vprint(INFO_MID, CONFIGURING);
 368                         load_dev_acl();
 369                         update_drvconf((major_t)-1);
 370                         process_devinfo_tree();
 371                         (void) modctl(MODSETMINIROOT);
 372                 }
 373 
 374                 /*
 375                  * fork before detaching from tty in order to print error
 376                  * message if unable to acquire file lock.  locks not preserved
 377                  * across forks.  Even under debug we want to fork so that
 378                  * when executed at boot we don't hang.
 379                  */
 380                 if (fork() != 0) {
 381                         devfsadm_exit(0);
 382                 }
 383 
 384                 /* set directory to / so it coredumps there */
 385                 if (chdir("/") == -1) {
 386                         err_print(CHROOT_FAILED, strerror(errno));
 387                 }
 388 
 389                 /* only one daemon can run at a time */
 390                 if ((pid = enter_daemon_lock()) == getpid()) {
 391                         detachfromtty();
 392                         (void) cond_init(&cv, USYNC_THREAD, 0);
 393                         (void) mutex_init(&count_lock, USYNC_THREAD, 0);
 394                         if (thr_create(NULL, NULL,
 395                             (void *(*)(void *))instance_flush_thread,
 396                             NULL, THR_DETACHED, NULL) != 0) {
 397                                 err_print(CANT_CREATE_THREAD, "daemon",
 398                                     strerror(errno));
 399                                 devfsadm_exit(1);
 400                         }
 401 
 402                         /* start the minor_fini_thread */
 403                         (void) mutex_init(&minor_fini_mutex, USYNC_THREAD, 0);
 404                         (void) cond_init(&minor_fini_cv, USYNC_THREAD, 0);
 405                         if (thr_create(NULL, NULL,
 406                             (void *(*)(void *))minor_fini_thread,
 407                             NULL, THR_DETACHED, NULL)) {
 408                                 err_print(CANT_CREATE_THREAD, "minor_fini",
 409                                     strerror(errno));
 410                                 devfsadm_exit(1);
 411                         }
 412 
 413 
 414                         /*
 415                          * No need for rcm notifications when running
 416                          * with an alternate root. So initialize rcm only
 417                          * when devfsadm is running with root dir "/".
 418                          * Similarly, logindevperms need only be set
 419                          * in daemon mode and when root dir is "/".
 420                          */
 421                         if (root_dir[0] == '\0') {
 422                                 (void) rcm_init();
 423                                 login_dev_enable = TRUE;
 424                         }
 425                         daemon_update();
 426                 } else {
 427                         err_print(DAEMON_RUNNING, pid);
 428                         devfsadm_exit(1);
 429                 }
 430                 exit_daemon_lock();
 431 
 432         } else {
 433                 /* not a daemon, so just build /dev and /devices */
 434                 process_devinfo_tree();
 435                 if (devalloc_flag != 0)
 436                         /* Enable/disable device allocation */
 437                         _reset_devalloc(devalloc_flag);
 438         }
 439         return (0);
 440 }
 441 
 442 static void
 443 update_drvconf(major_t major)
 444 {
 445         if (modctl(MODLOADDRVCONF, major) != 0)
 446                 err_print(gettext("update_drvconf failed for major %d\n"),
 447                     major);
 448 }
 449 
 450 
 451 static void
 452 load_dev_acl()
 453 {
 454         if (load_devpolicy() != 0)
 455                 err_print(gettext("device policy load failed\n"));
 456         load_minor_perm_file();
 457 }
 458 
 459 /*
 460  * As devfsadm is run early in boot to provide the kernel with
 461  * minor_perm info, we might as well check for reconfig at the
 462  * same time to avoid running devfsadm twice.  This gets invoked
 463  * earlier than the env variable RECONFIG_BOOT is set up.
 464  */
 465 static void
 466 check_reconfig_state()
 467 {
 468         struct stat sb;
 469 
 470         if (s_stat("/reconfigure", &sb) == 0) {
 471                 (void) modctl(MODDEVNAME, MODDEVNAME_RECONFIG, 0);
 472         }
 473 }
 474 
 475 static void
 476 modctl_sysavail()
 477 {
 478         /*
 479          * Inform /dev that system is available, that
 480          * implicit reconfig can now be performed.
 481          */
 482         (void) modctl(MODDEVNAME, MODDEVNAME_SYSAVAIL, 0);
 483 }
 484 
 485 static void
 486 set_lock_root(void)
 487 {
 488         struct stat sb;
 489         char *lock_root;
 490         size_t len;
 491 
 492         lock_root = attr_root ? attr_root : root_dir;
 493 
 494         len = strlen(lock_root) + strlen(ETCDEV) + 1;
 495         etc_dev_dir = s_malloc(len);
 496         (void) snprintf(etc_dev_dir, len, "%s%s", lock_root, ETCDEV);
 497 
 498         if (s_stat(etc_dev_dir, &sb) != 0) {
 499                 s_mkdirp(etc_dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
 500         } else if (!S_ISDIR(sb.st_mode)) {
 501                 err_print(NOT_DIR, etc_dev_dir);
 502                 devfsadm_exit(1);
 503         }
 504 }
 505 
 506 
 507 /*
 508  * Parse arguments for all 6 programs handled from devfsadm.
 509  */
 510 static void
 511 parse_args(int argc, char *argv[])
 512 {
 513         char opt;
 514         char get_linkcompat_opts = FALSE;
 515         char *compat_class;
 516         int num_aliases = 0;
 517         int len;
 518         int retval;
 519         int add_bind = FALSE;
 520         struct aliases *ap = NULL;
 521         struct aliases *a_head = NULL;
 522         struct aliases *a_tail = NULL;
 523         struct modconfig mc;
 524 
 525         if (strcmp(prog, DISKS) == 0) {
 526                 compat_class = "disk";
 527                 get_linkcompat_opts = TRUE;
 528 
 529         } else if (strcmp(prog, TAPES) == 0) {
 530                 compat_class = "tape";
 531                 get_linkcompat_opts = TRUE;
 532 
 533         } else if (strcmp(prog, PORTS) == 0) {
 534                 compat_class = "port";
 535                 get_linkcompat_opts = TRUE;
 536 
 537         } else if (strcmp(prog, AUDLINKS) == 0) {
 538                 compat_class = "audio";
 539                 get_linkcompat_opts = TRUE;
 540 
 541         } else if (strcmp(prog, DEVLINKS) == 0) {
 542                 devlinktab_file = DEVLINKTAB_FILE;
 543 
 544                 build_devices = FALSE;
 545                 load_attach_drv = FALSE;
 546 
 547                 while ((opt = getopt(argc, argv, "dnr:st:vV:")) != EOF) {
 548                         switch (opt) {
 549                         case 'd':
 550                                 file_mods = FALSE;
 551                                 flush_path_to_inst_enable = FALSE;
 552                                 devlinks_debug = TRUE;
 553                                 break;
 554                         case 'n':
 555                                 /* prevent driver loading and deferred attach */
 556                                 load_attach_drv = FALSE;
 557                                 break;
 558                         case 'r':
 559                                 set_root_devices_dev_dir(optarg);
 560                                 if (zone_pathcheck(root_dir) !=
 561                                     DEVFSADM_SUCCESS)
 562                                         devfsadm_exit(1);
 563                                 break;
 564                         case 's':
 565                                 /*
 566                                  * suppress.  don't create/remove links/nodes
 567                                  * useful with -v or -V
 568                                  */
 569                                 file_mods = FALSE;
 570                                 flush_path_to_inst_enable = FALSE;
 571                                 break;
 572                         case 't':
 573                                 /* supply a non-default table file */
 574                                 devlinktab_file = optarg;
 575                                 break;
 576                         case 'v':
 577                                 /* documented verbose flag */
 578                                 add_verbose_id(VERBOSE_MID);
 579                                 break;
 580                         case 'V':
 581                                 /* undocumented for extra verbose levels */
 582                                 add_verbose_id(optarg);
 583                                 break;
 584                         default:
 585                                 usage();
 586                                 break;
 587                         }
 588                 }
 589 
 590                 if (optind < argc) {
 591                         usage();
 592                 }
 593 
 594         } else if (strcmp(prog, DRVCONFIG) == 0) {
 595                 build_dev = FALSE;
 596 
 597                 while ((opt =
 598                     getopt(argc, argv, "a:bdc:i:m:np:R:r:svV:")) != EOF) {
 599                         switch (opt) {
 600                         case 'a':
 601                                 ap = calloc(sizeof (struct aliases), 1);
 602                                 ap->a_name = dequote(optarg);
 603                                 len = strlen(ap->a_name) + 1;
 604                                 if (len > MAXMODCONFNAME) {
 605                                         err_print(ALIAS_TOO_LONG,
 606                                             MAXMODCONFNAME, ap->a_name);
 607                                         devfsadm_exit(1);
 608                                 }
 609                                 ap->a_len = len;
 610                                 if (a_tail == NULL) {
 611                                         a_head = ap;
 612                                 } else {
 613                                         a_tail->a_next = ap;
 614                                 }
 615                                 a_tail = ap;
 616                                 num_aliases++;
 617                                 add_bind = TRUE;
 618                                 break;
 619                         case 'b':
 620                                 add_bind = TRUE;
 621                                 break;
 622                         case 'c':
 623                                 (void) strcpy(mc.drvclass, optarg);
 624                                 break;
 625                         case 'd':
 626                                 /*
 627                                  * need to keep for compatibility, but
 628                                  * do nothing.
 629                                  */
 630                                 break;
 631                         case 'i':
 632                                 single_drv = TRUE;
 633                                 (void) strcpy(mc.drvname, optarg);
 634                                 driver = s_strdup(optarg);
 635                                 break;
 636                         case 'm':
 637                                 mc.major = atoi(optarg);
 638                                 break;
 639                         case 'n':
 640                                 /* prevent driver loading and deferred attach */
 641                                 load_attach_drv = FALSE;
 642                                 break;
 643                         case 'p':
 644                                 /* specify alternate path_to_inst file */
 645                                 inst_file = s_strdup(optarg);
 646                                 break;
 647                         case 'R':
 648                                 /*
 649                                  * Private flag for suninstall to populate
 650                                  * device information on the installed root.
 651                                  */
 652                                 root_dir = s_strdup(optarg);
 653                                 if (zone_pathcheck(root_dir) !=
 654                                     DEVFSADM_SUCCESS)
 655                                 devfsadm_exit(devfsadm_copy());
 656                                 break;
 657                         case 'r':
 658                                 devices_dir = s_strdup(optarg);
 659                                 if (zone_pathcheck(devices_dir) !=
 660                                     DEVFSADM_SUCCESS)
 661                                         devfsadm_exit(1);
 662                                 break;
 663                         case 's':
 664                                 /*
 665                                  * suppress.  don't create nodes
 666                                  * useful with -v or -V
 667                                  */
 668                                 file_mods = FALSE;
 669                                 flush_path_to_inst_enable = FALSE;
 670                                 break;
 671                         case 'v':
 672                                 /* documented verbose flag */
 673                                 add_verbose_id(VERBOSE_MID);
 674                                 break;
 675                         case 'V':
 676                                 /* undocumented for extra verbose levels */
 677                                 add_verbose_id(optarg);
 678                                 break;
 679                         default:
 680                                 usage();
 681                         }
 682                 }
 683 
 684                 if (optind < argc) {
 685                         usage();
 686                 }
 687 
 688                 if ((add_bind == TRUE) && (mc.major == -1 ||
 689                     mc.drvname[0] == NULL)) {
 690                         err_print(MAJOR_AND_B_FLAG);
 691                         devfsadm_exit(1);
 692                 }
 693                 if (add_bind == TRUE) {
 694                         mc.num_aliases = num_aliases;
 695                         mc.ap = a_head;
 696                         retval =  modctl(MODADDMAJBIND, NULL, (caddr_t)&mc);
 697                         if (retval < 0) {
 698                                 err_print(MODCTL_ADDMAJBIND);
 699                         }
 700                         devfsadm_exit(retval);
 701                 }
 702 
 703         } else if ((strcmp(prog, DEVFSADM) == 0) ||
 704             (strcmp(prog, DEVFSADMD) == 0)) {
 705                 char *zonename = NULL;
 706                 int init_drvconf = 0;
 707                 int init_perm = 0;
 708                 int public_mode = 0;
 709                 int init_sysavail = 0;
 710 
 711                 if (strcmp(prog, DEVFSADMD) == 0) {
 712                         daemon_mode = TRUE;
 713                 }
 714 
 715                 devlinktab_file = DEVLINKTAB_FILE;
 716 
 717                 while ((opt = getopt(argc, argv,
 718                     "a:Cc:deIi:l:mnp:PR:r:sSt:vV:x:")) != EOF) {
 719                         if (opt == 'I' || opt == 'P' || opt == 'S') {
 720                                 if (public_mode)
 721                                         usage();
 722                         } else {
 723                                 if (init_perm || init_drvconf || init_sysavail)
 724                                         usage();
 725                                 public_mode = 1;
 726                         }
 727                         switch (opt) {
 728                         case 'a':
 729                                 attr_root = s_strdup(optarg);
 730                                 break;
 731                         case 'C':
 732                                 cleanup = TRUE;
 733                                 break;
 734                         case 'c':
 735                                 num_classes++;
 736                                 classes = s_realloc(classes,
 737                                     num_classes * sizeof (char *));
 738                                 classes[num_classes - 1] = optarg;
 739                                 break;
 740                         case 'd':
 741                                 if (daemon_mode == FALSE) {
 742                                         /*
 743                                          * Device allocation to be disabled.
 744                                          */
 745                                         devalloc_flag = DA_OFF;
 746                                         build_dev = FALSE;
 747                                 }
 748                                 break;
 749                         case 'e':
 750                                 if (daemon_mode == FALSE) {
 751                                         /*
 752                                          * Device allocation to be enabled.
 753                                          */
 754                                         devalloc_flag = DA_ON;
 755                                         build_dev = FALSE;
 756                                 }
 757                                 break;
 758                         case 'I':       /* update kernel driver.conf cache */
 759                                 if (daemon_mode == TRUE)
 760                                         usage();
 761                                 init_drvconf = 1;
 762                                 break;
 763                         case 'i':
 764                                 single_drv = TRUE;
 765                                 driver = s_strdup(optarg);
 766                                 break;
 767                         case 'l':
 768                                 /* specify an alternate module load path */
 769                                 module_dirs = s_strdup(optarg);
 770                                 break;
 771                         case 'm':
 772                                 load_devname_nsmaps = TRUE;
 773                                 break;
 774                         case 'n':
 775                                 /* prevent driver loading and deferred attach */
 776                                 load_attach_drv = FALSE;
 777                                 break;
 778                         case 'p':
 779                                 /* specify alternate path_to_inst file */
 780                                 inst_file = s_strdup(optarg);
 781                                 break;
 782                         case 'P':
 783                                 if (daemon_mode == TRUE)
 784                                         usage();
 785                                 /* load minor_perm and device_policy */
 786                                 init_perm = 1;
 787                                 break;
 788                         case 'R':
 789                                 /*
 790                                  * Private flag for suninstall to populate
 791                                  * device information on the installed root.
 792                                  */
 793                                 root_dir = s_strdup(optarg);
 794                                 devfsadm_exit(devfsadm_copy());
 795                                 break;
 796                         case 'r':
 797                                 set_root_devices_dev_dir(optarg);
 798                                 break;
 799                         case 's':
 800                                 /*
 801                                  * suppress. don't create/remove links/nodes
 802                                  * useful with -v or -V
 803                                  */
 804                                 file_mods = FALSE;
 805                                 flush_path_to_inst_enable = FALSE;
 806                                 break;
 807                         case 'S':
 808                                 if (daemon_mode == TRUE)
 809                                         usage();
 810                                 init_sysavail = 1;
 811                                 break;
 812                         case 't':
 813                                 devlinktab_file = optarg;
 814                                 break;
 815                         case 'v':
 816                                 /* documented verbose flag */
 817                                 add_verbose_id(VERBOSE_MID);
 818                                 break;
 819                         case 'V':
 820                                 /* undocumented: specify verbose lvl */
 821                                 add_verbose_id(optarg);
 822                                 break;
 823                         case 'x':
 824                                 /*
 825                                  * x is the "private switch" option.  The
 826                                  * goal is to not suck up all the other
 827                                  * option letters.
 828                                  */
 829                                 if (strcmp(optarg, "update_devlinksdb") == 0) {
 830                                         update_database = TRUE;
 831                                 } else if (strcmp(optarg, "no_dev") == 0) {
 832                                         /* don't build /dev */
 833                                         build_dev = FALSE;
 834                                 } else if (strcmp(optarg, "no_devices") == 0) {
 835                                         /* don't build /devices */
 836                                         build_devices = FALSE;
 837                                 } else if (strcmp(optarg, "no_p2i") == 0) {
 838                                         /* don't flush path_to_inst */
 839                                         flush_path_to_inst_enable = FALSE;
 840                                 } else if (strcmp(optarg, "use_dicache") == 0) {
 841                                         use_snapshot_cache = TRUE;
 842                                 } else {
 843                                         usage();
 844                                 }
 845                                 break;
 846                         default:
 847                                 usage();
 848                                 break;
 849                         }
 850                 }
 851                 if (optind < argc) {
 852                         usage();
 853                 }
 854 
 855                 /*
 856                  * We're not in zone mode; Check to see if the rootpath
 857                  * collides with any zonepaths.
 858                  */
 859                 if (zonename == NULL) {
 860                         if (zone_pathcheck(root_dir) != DEVFSADM_SUCCESS)
 861                                 devfsadm_exit(1);
 862                 }
 863 
 864                 if (init_drvconf || init_perm || init_sysavail) {
 865                         /*
 866                          * Load minor perm before force-loading drivers
 867                          * so the correct permissions are picked up.
 868                          */
 869                         if (init_perm) {
 870                                 check_reconfig_state();
 871                                 load_dev_acl();
 872                         }
 873                         if (init_drvconf)
 874                                 update_drvconf((major_t)-1);
 875                         if (init_sysavail)
 876                                 modctl_sysavail();
 877                         devfsadm_exit(0);
 878                         /* NOTREACHED */
 879                 }
 880 
 881                 if (load_devname_nsmaps == TRUE) {
 882                         devname_setup_nsmaps();
 883                         devfsadm_exit(0);
 884                 }
 885         }
 886 
 887 
 888         if (get_linkcompat_opts == TRUE) {
 889 
 890                 build_devices = FALSE;
 891                 load_attach_drv = FALSE;
 892                 num_classes++;
 893                 classes = s_realloc(classes, num_classes *
 894                     sizeof (char *));
 895                 classes[num_classes - 1] = compat_class;
 896 
 897                 while ((opt = getopt(argc, argv, "Cnr:svV:")) != EOF) {
 898                         switch (opt) {
 899                         case 'C':
 900                                 cleanup = TRUE;
 901                                 break;
 902                         case 'n':
 903                                 /* prevent driver loading or deferred attach */
 904                                 load_attach_drv = FALSE;
 905                                 break;
 906                         case 'r':
 907                                 set_root_devices_dev_dir(optarg);
 908                                 if (zone_pathcheck(root_dir) !=
 909                                     DEVFSADM_SUCCESS)
 910                                         devfsadm_exit(1);
 911                                 break;
 912                         case 's':
 913                                 /* suppress.  don't create/remove links/nodes */
 914                                 /* useful with -v or -V */
 915                                 file_mods = FALSE;
 916                                 flush_path_to_inst_enable = FALSE;
 917                                 break;
 918                         case 'v':
 919                                 /* documented verbose flag */
 920                                 add_verbose_id(VERBOSE_MID);
 921                                 break;
 922                         case 'V':
 923                                 /* undocumented for extra verbose levels */
 924                                 add_verbose_id(optarg);
 925                                 break;
 926                         default:
 927                                 usage();
 928                         }
 929                 }
 930                 if (optind < argc) {
 931                         usage();
 932                 }
 933         }
 934         set_lock_root();
 935 }
 936 
 937 void
 938 usage(void)
 939 {
 940         if (strcmp(prog, DEVLINKS) == 0) {
 941                 err_print(DEVLINKS_USAGE);
 942         } else if (strcmp(prog, DRVCONFIG) == 0) {
 943                 err_print(DRVCONFIG_USAGE);
 944         } else if ((strcmp(prog, DEVFSADM) == 0) ||
 945             (strcmp(prog, DEVFSADMD) == 0)) {
 946                 err_print(DEVFSADM_USAGE);
 947         } else {
 948                 err_print(COMPAT_LINK_USAGE);
 949         }
 950 
 951         devfsadm_exit(1);
 952 }
 953 
 954 static void
 955 devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass)
 956 {
 957         char *msg, *name;
 958         struct mlist    mlist = {0};
 959         di_node_t       node;
 960 
 961         vprint(CHATTY_MID, "devi_tree_walk: root=%s, minor=%s, driver=%s,"
 962             " error=%d, flags=%u\n", dcip->dci_root,
 963             dcip->dci_minor ? dcip->dci_minor : "<NULL>",
 964             dcip->dci_driver ? dcip->dci_driver : "<NULL>", dcip->dci_error,
 965             dcip->dci_flags);
 966 
 967         assert(dcip->dci_root);
 968 
 969         if (dcip->dci_flags & DCA_LOAD_DRV) {
 970                 node = di_init_driver(dcip->dci_driver, flags);
 971                 msg = DRIVER_FAILURE;
 972                 name = dcip->dci_driver;
 973         } else {
 974                 node = di_init(dcip->dci_root, flags);
 975                 msg = DI_INIT_FAILED;
 976                 name = dcip->dci_root;
 977         }
 978 
 979         if (node == DI_NODE_NIL) {
 980                 dcip->dci_error = errno;
 981                 /*
 982                  * Rapid hotplugging (commonly seen during USB testing),
 983                  * may remove a device before the create event for it
 984                  * has been processed. To prevent alarming users with
 985                  * a superfluous message, we suppress error messages
 986                  * for ENXIO and hotplug.
 987                  */
 988                 if (!(errno == ENXIO && (dcip->dci_flags & DCA_HOT_PLUG)))
 989                         err_print(msg, name, strerror(dcip->dci_error));
 990                 return;
 991         }
 992 
 993         if (dcip->dci_flags & DCA_FLUSH_PATHINST)
 994                 flush_path_to_inst();
 995 
 996         dcip->dci_arg = &mlist;
 997 
 998         vprint(CHATTY_MID, "walking device tree\n");
 999 
1000         (void) di_walk_minor(node, NULL, DI_CHECK_ALIAS, dcip,
1001             check_minor_type);
1002 
1003         process_deferred_links(dcip, DCA_CREATE_LINK);
1004 
1005         dcip->dci_arg = NULL;
1006 
1007         /*
1008          * Finished creating devfs files and dev links.
1009          * Log sysevent and notify RCM.
1010          */
1011         if (ev_subclass)
1012                 build_and_enq_event(EC_DEV_ADD, ev_subclass, dcip->dci_root,
1013                     node, dcip->dci_minor);
1014 
1015         if ((dcip->dci_flags & DCA_NOTIFY_RCM) && rcm_hdl)
1016                 (void) notify_rcm(node, dcip->dci_minor);
1017 
1018         /* Add new device to device allocation database */
1019         if (system_labeled && update_devdb) {
1020                 _update_devalloc_db(&devlist, 0, DA_ADD, NULL, root_dir);
1021                 update_devdb = 0;
1022         }
1023 
1024         di_fini(node);
1025 }
1026 
1027 static void
1028 process_deferred_links(struct dca_impl *dcip, int flags)
1029 {
1030         struct mlist    *dep;
1031         struct minor    *mp, *smp;
1032 
1033         vprint(CHATTY_MID, "processing deferred links\n");
1034 
1035         dep = dcip->dci_arg;
1036 
1037         /*
1038          * The list head is not used during the deferred create phase
1039          */
1040         dcip->dci_arg = NULL;
1041 
1042         assert(dep);
1043         assert((dep->head == NULL) ^ (dep->tail != NULL));
1044         assert(flags == DCA_FREE_LIST || flags == DCA_CREATE_LINK);
1045 
1046         for (smp = NULL, mp = dep->head; mp; mp = mp->next) {
1047                 if (flags == DCA_CREATE_LINK)
1048                         (void) check_minor_type(mp->node, mp->minor, dcip);
1049                 free(smp);
1050                 smp = mp;
1051         }
1052 
1053         free(smp);
1054 }
1055 
1056 /*
1057  * Called in non-daemon mode to take a snap shot of the devinfo tree.
1058  * Then it calls the appropriate functions to build /devices and /dev.
1059  * It also flushes path_to_inst.
1060  * Except in the devfsadm -i (single driver case), the flags used by devfsadm
1061  * needs to match DI_CACHE_SNAPSHOT_FLAGS. That will make DINFOCACHE snapshot
1062  * updated.
1063  */
1064 void
1065 process_devinfo_tree()
1066 {
1067         uint_t          flags;
1068         struct dca_impl dci;
1069         char            name[MAXNAMELEN];
1070         char            *fcn = "process_devinfo_tree: ";
1071 
1072         vprint(CHATTY_MID, "%senter\n", fcn);
1073 
1074         dca_impl_init("/", NULL, &dci);
1075 
1076         lock_dev();
1077 
1078         /*
1079          * Update kernel driver.conf cache when devfsadm/drvconfig
1080          * is invoked to build /devices and /dev.
1081          */
1082         if (load_attach_drv == TRUE)
1083                 update_drvconf((major_t)-1);
1084 
1085         if (single_drv == TRUE) {
1086                 /*
1087                  * load a single driver, but walk the entire devinfo tree
1088                  */
1089                 if (load_attach_drv == FALSE)
1090                         err_print(DRV_LOAD_REQD);
1091 
1092                 vprint(CHATTY_MID, "%sattaching driver (%s)\n", fcn, driver);
1093 
1094                 dci.dci_flags |= DCA_LOAD_DRV;
1095                 (void) snprintf(name, sizeof (name), "%s", driver);
1096                 dci.dci_driver = name;
1097                 flags = DINFOCPYALL | DINFOPATH;
1098 
1099         } else if (load_attach_drv == TRUE) {
1100                 /*
1101                  * Load and attach all drivers, then walk the entire tree.
1102                  * If the cache flag is set, use DINFOCACHE to get cached
1103                  * data.
1104                  */
1105                 if (use_snapshot_cache == TRUE) {
1106                         flags = DINFOCACHE;
1107                         vprint(CHATTY_MID, "%susing snapshot cache\n", fcn);
1108                 } else {
1109                         vprint(CHATTY_MID, "%sattaching all drivers\n", fcn);
1110                         flags = DI_CACHE_SNAPSHOT_FLAGS;
1111                         if (cleanup) {
1112                                 /*
1113                                  * remove dangling entries from /etc/devices
1114                                  * files.
1115                                  */
1116                                 flags |= DINFOCLEANUP;
1117                         }
1118                 }
1119         } else {
1120                 /*
1121                  * For devlinks, disks, ports, tapes and devfsadm -n,
1122                  * just need to take a snapshot with active devices.
1123                  */
1124                 vprint(CHATTY_MID, "%staking snapshot of active devices\n",
1125                     fcn);
1126                 flags = DINFOCPYALL;
1127         }
1128 
1129         if (((load_attach_drv == TRUE) || (single_drv == TRUE)) &&
1130             (build_devices == TRUE)) {
1131                 dci.dci_flags |= DCA_FLUSH_PATHINST;
1132         }
1133 
1134         /* handle pre-cleanup operations desired by the modules. */
1135         pre_and_post_cleanup(RM_PRE);
1136 
1137         devi_tree_walk(&dci, flags, NULL);
1138 
1139         if (dci.dci_error) {
1140                 devfsadm_exit(1);
1141         }
1142 
1143         /* handle post-cleanup operations desired by the modules. */
1144         pre_and_post_cleanup(RM_POST);
1145 
1146         unlock_dev(SYNC_STATE);
1147 }
1148 
1149 /*ARGSUSED*/
1150 static void
1151 print_cache_signal(int signo)
1152 {
1153         if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) {
1154                 err_print("signal SIGUSR1 failed: %s\n", strerror(errno));
1155                 devfsadm_exit(1);
1156         }
1157 }
1158 
1159 static void
1160 revoke_lookup_door(void)
1161 {
1162         if (lookup_door_fd != -1) {
1163                 if (door_revoke(lookup_door_fd) == -1) {
1164                         err_print("door_revoke of %s failed - %s\n",
1165                             lookup_door_path, strerror(errno));
1166                 }
1167         }
1168 }
1169 
1170 /*ARGSUSED*/
1171 static void
1172 catch_exit(int signo)
1173 {
1174         revoke_lookup_door();
1175 }
1176 
1177 /*
1178  * Register with eventd for messages. Create doors for synchronous
1179  * link creation.
1180  */
1181 static void
1182 daemon_update(void)
1183 {
1184         int fd;
1185         char *fcn = "daemon_update: ";
1186         char door_file[MAXPATHLEN];
1187         const char *subclass_list;
1188         sysevent_handle_t *sysevent_hp;
1189         vprint(CHATTY_MID, "%senter\n", fcn);
1190 
1191         if (signal(SIGUSR1, print_cache_signal) == SIG_ERR) {
1192                 err_print("signal SIGUSR1 failed: %s\n", strerror(errno));
1193                 devfsadm_exit(1);
1194         }
1195         if (signal(SIGTERM, catch_exit) == SIG_ERR) {
1196                 err_print("signal SIGTERM failed: %s\n", strerror(errno));
1197                 devfsadm_exit(1);
1198         }
1199 
1200         if (snprintf(door_file, sizeof (door_file),
1201             "%s%s", attr_root ? attr_root : root_dir, DEVFSADM_SERVICE_DOOR)
1202             >= sizeof (door_file)) {
1203                 err_print("update_daemon failed to open sysevent service "
1204                     "door\n");
1205                 devfsadm_exit(1);
1206         }
1207         if ((sysevent_hp = sysevent_open_channel_alt(
1208             door_file)) == NULL) {
1209                 err_print(CANT_CREATE_DOOR,
1210                     door_file, strerror(errno));
1211                 devfsadm_exit(1);
1212         }
1213         if (sysevent_bind_subscriber(sysevent_hp, event_handler) != 0) {
1214                 err_print(CANT_CREATE_DOOR,
1215                     door_file, strerror(errno));
1216                 (void) sysevent_close_channel(sysevent_hp);
1217                 devfsadm_exit(1);
1218         }
1219         subclass_list = EC_SUB_ALL;
1220         if (sysevent_register_event(sysevent_hp, EC_ALL, &subclass_list, 1)
1221             != 0) {
1222                 err_print(CANT_CREATE_DOOR,
1223                     door_file, strerror(errno));
1224                 (void) sysevent_unbind_subscriber(sysevent_hp);
1225                 (void) sysevent_close_channel(sysevent_hp);
1226                 devfsadm_exit(1);
1227         }
1228         if (snprintf(door_file, sizeof (door_file), "%s/%s",
1229             etc_dev_dir, DEVFSADM_SYNCH_DOOR) >= sizeof (door_file)) {
1230                 err_print(CANT_CREATE_DOOR, DEVFSADM_SYNCH_DOOR,
1231                     strerror(ENAMETOOLONG));
1232                 devfsadm_exit(1);
1233         }
1234 
1235         (void) s_unlink(door_file);
1236         if ((fd = open(door_file, O_RDWR | O_CREAT, SYNCH_DOOR_PERMS)) == -1) {
1237                 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1238                 devfsadm_exit(1);
1239         }
1240         (void) close(fd);
1241 
1242         if ((fd = door_create(sync_handler, NULL,
1243             DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1244                 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1245                 (void) s_unlink(door_file);
1246                 devfsadm_exit(1);
1247         }
1248 
1249         if (fattach(fd, door_file) == -1) {
1250                 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1251                 (void) s_unlink(door_file);
1252                 devfsadm_exit(1);
1253         }
1254 
1255         /*
1256          * devname_lookup_door
1257          */
1258         if (snprintf(door_file, sizeof (door_file), "%s/%s",
1259             etc_dev_dir, DEVNAME_LOOKUP_DOOR) >= sizeof (door_file)) {
1260                 err_print(CANT_CREATE_DOOR, DEVNAME_LOOKUP_DOOR,
1261                     strerror(ENAMETOOLONG));
1262                 devfsadm_exit(1);
1263         }
1264 
1265         (void) s_unlink(door_file);
1266         if ((fd = open(door_file, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR)) == -1) {
1267                 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1268                 devfsadm_exit(1);
1269         }
1270         (void) close(fd);
1271 
1272         if ((fd = door_create(devname_lookup_handler, NULL,
1273             DOOR_REFUSE_DESC)) == -1) {
1274                 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1275                 (void) s_unlink(door_file);
1276                 devfsadm_exit(1);
1277         }
1278 
1279         (void) fdetach(door_file);
1280         lookup_door_path = s_strdup(door_file);
1281 retry:
1282         if (fattach(fd, door_file) == -1) {
1283                 if (errno == EBUSY)
1284                         goto retry;
1285                 err_print(CANT_CREATE_DOOR, door_file, strerror(errno));
1286                 (void) s_unlink(door_file);
1287                 devfsadm_exit(1);
1288         }
1289         lookup_door_fd = fd;
1290 
1291         /* pass down the door name to kernel for door_ki_open */
1292         if (devname_kcall(MODDEVNAME_LOOKUPDOOR, (void *)door_file) != 0)
1293                 err_print(DEVNAME_CONTACT_FAILED, strerror(errno));
1294         else
1295                 devname_setup_nsmaps();
1296 
1297         vprint(CHATTY_MID, "%spausing\n", fcn);
1298         for (;;) {
1299                 (void) pause();
1300         }
1301 }
1302 
1303 /*ARGSUSED*/
1304 static void
1305 sync_handler(void *cookie, char *ap, size_t asize,
1306     door_desc_t *dp, uint_t ndesc)
1307 {
1308         door_cred_t     dcred;
1309         struct dca_off  *dcp, rdca;
1310         struct dca_impl dci;
1311 
1312         /*
1313          * Must be root to make this call
1314          * If caller is not root, don't touch its data.
1315          */
1316         if (door_cred(&dcred) != 0 || dcred.dc_euid != 0) {
1317                 dcp = &rdca;
1318                 dcp->dca_error = EPERM;
1319                 goto out;
1320         }
1321 
1322         assert(ap);
1323         assert(asize == sizeof (*dcp));
1324 
1325         dcp = (void *)ap;
1326 
1327         /*
1328          * Root is always present and is the first component of "name" member
1329          */
1330         assert(dcp->dca_root == 0);
1331 
1332         /*
1333          * The structure passed in by the door_client uses offsets
1334          * instead of pointers to work across address space boundaries.
1335          * Now copy the data into a structure (dca_impl) which uses
1336          * pointers.
1337          */
1338         dci.dci_root = &dcp->dca_name[dcp->dca_root];
1339         dci.dci_minor = dcp->dca_minor ? &dcp->dca_name[dcp->dca_minor] : NULL;
1340         dci.dci_driver =
1341             dcp->dca_driver ? &dcp->dca_name[dcp->dca_driver] : NULL;
1342         dci.dci_error = 0;
1343         dci.dci_flags = dcp->dca_flags | (dci.dci_driver ? DCA_LOAD_DRV : 0);
1344         dci.dci_arg = NULL;
1345 
1346         lock_dev();
1347         devi_tree_walk(&dci, DINFOCPYALL, NULL);
1348         dcp->dca_error = dci.dci_error;
1349 
1350         if (dcp->dca_flags & DCA_DEVLINK_SYNC)
1351                 unlock_dev(SYNC_STATE);
1352         else
1353                 unlock_dev(CACHE_STATE);
1354 
1355 out:    (void) door_return((char *)dcp, sizeof (*dcp), NULL, 0);
1356 }
1357 
1358 static void
1359 lock_dev(void)
1360 {
1361         vprint(CHATTY_MID, "lock_dev(): entered\n");
1362 
1363         if (build_dev == FALSE)
1364                 return;
1365 
1366         /* lockout other threads from /dev */
1367         while (sema_wait(&dev_sema) != 0)
1368                 ;
1369 
1370         /*
1371          * Lock out other devfsadm processes from /dev.
1372          * If this wasn't the last process to run,
1373          * clear caches
1374          */
1375         if (enter_dev_lock() != getpid()) {
1376                 invalidate_enumerate_cache();
1377                 rm_all_links_from_cache();
1378                 (void) di_devlink_close(&devlink_cache, DI_LINK_ERROR);
1379 
1380                 /* send any sysevents that were queued up. */
1381                 process_syseventq();
1382         }
1383 
1384         /*
1385          * (re)load the  reverse links database if not
1386          * already cached.
1387          */
1388         if (devlink_cache == NULL)
1389                 devlink_cache = di_devlink_open(root_dir, 0);
1390 
1391         /*
1392          * If modules were unloaded, reload them.  Also use module status
1393          * as an indication that we should check to see if other binding
1394          * files need to be reloaded.
1395          */
1396         if (module_head == NULL) {
1397                 load_modules();
1398                 read_minor_perm_file();
1399                 read_driver_aliases_file();
1400                 read_devlinktab_file();
1401                 read_logindevperm_file();
1402                 read_enumerate_file();
1403         }
1404 
1405         if (module_head != NULL)
1406                 return;
1407 
1408         if (strcmp(prog, DEVLINKS) == 0) {
1409                 if (devlinktab_list == NULL) {
1410                         err_print(NO_LINKTAB, devlinktab_file);
1411                         err_print(NO_MODULES, module_dirs);
1412                         err_print(ABORTING);
1413                         devfsadm_exit(1);
1414                 }
1415         } else {
1416                 err_print(NO_MODULES, module_dirs);
1417                 if (strcmp(prog, DEVFSADM) == 0) {
1418                         err_print(MODIFY_PATH);
1419                 }
1420         }
1421 }
1422 
1423 /*
1424  * Unlock the device.  If we are processing a CACHE_STATE call, we signal a
1425  * minor_fini_thread delayed SYNC_STATE at the end of the call.  If we are
1426  * processing a SYNC_STATE call, we cancel any minor_fini_thread SYNC_STATE
1427  * at both the start and end of the call since we will be doing the SYNC_STATE.
1428  */
1429 static void
1430 unlock_dev(int flag)
1431 {
1432         assert(flag == SYNC_STATE || flag == CACHE_STATE);
1433 
1434         vprint(CHATTY_MID, "unlock_dev(): entered\n");
1435 
1436         /* If we are starting a SYNC_STATE, cancel minor_fini_thread SYNC */
1437         if (flag == SYNC_STATE) {
1438                 (void) mutex_lock(&minor_fini_mutex);
1439                 minor_fini_canceled = TRUE;
1440                 minor_fini_delayed = FALSE;
1441                 (void) mutex_unlock(&minor_fini_mutex);
1442         }
1443 
1444         if (build_dev == FALSE)
1445                 return;
1446 
1447         if (devlink_cache == NULL) {
1448                 err_print(NO_DEVLINK_CACHE);
1449         }
1450         assert(devlink_cache);
1451 
1452         if (flag == SYNC_STATE) {
1453                 unload_modules();
1454                 if (update_database)
1455                         (void) di_devlink_update(devlink_cache);
1456                 (void) di_devlink_close(&devlink_cache, 0);
1457 
1458                 /*
1459                  * now that the devlinks db cache has been flushed, it is safe
1460                  * to send any sysevents that were queued up.
1461                  */
1462                 process_syseventq();
1463         }
1464 
1465         exit_dev_lock();
1466 
1467         (void) mutex_lock(&minor_fini_mutex);
1468         if (flag == SYNC_STATE) {
1469                 /* We did a SYNC_STATE, cancel minor_fini_thread SYNC */
1470                 minor_fini_canceled = TRUE;
1471                 minor_fini_delayed = FALSE;
1472         } else {
1473                 /* We did a CACHE_STATE, start delayed minor_fini_thread SYNC */
1474                 minor_fini_canceled = FALSE;
1475                 minor_fini_delayed = TRUE;
1476                 (void) cond_signal(&minor_fini_cv);
1477         }
1478         (void) mutex_unlock(&minor_fini_mutex);
1479 
1480         (void) sema_post(&dev_sema);
1481 }
1482 
1483 /*
1484  * Check that if -r is set, it is not any part of a zone--- that is, that
1485  * the zonepath is not a substring of the root path.
1486  */
1487 static int
1488 zone_pathcheck(char *checkpath)
1489 {
1490         void            *dlhdl = NULL;
1491         char            *name;
1492         char            root[MAXPATHLEN]; /* resolved devfsadm root path */
1493         char            zroot[MAXPATHLEN]; /* zone root path */
1494         char            rzroot[MAXPATHLEN]; /* resolved zone root path */
1495         char            tmp[MAXPATHLEN];
1496         FILE            *cookie;
1497         int             err = DEVFSADM_SUCCESS;
1498 
1499         if (checkpath[0] == '\0')
1500                 return (DEVFSADM_SUCCESS);
1501 
1502         /*
1503          * Check if zones is available on this system.
1504          */
1505         if ((dlhdl = dlopen(LIBZONECFG_PATH, RTLD_LAZY)) == NULL) {
1506                 return (DEVFSADM_SUCCESS);
1507         }
1508 
1509         bzero(root, sizeof (root));
1510         if (resolvepath(checkpath, root, sizeof (root) - 1) == -1) {
1511                 /*
1512                  * In this case the user has done "devfsadm -r" on some path
1513                  * which does not yet exist, or we got some other misc. error.
1514                  * We punt and don't resolve the path in this case.
1515                  */
1516                 (void) strlcpy(root, checkpath, sizeof (root));
1517         }
1518 
1519         if (strlen(root) > 0 && (root[strlen(root) - 1] != '/')) {
1520                 (void) snprintf(tmp, sizeof (tmp), "%s/", root);
1521                 (void) strlcpy(root, tmp, sizeof (root));
1522         }
1523 
1524         cookie = setzoneent();
1525         while ((name = getzoneent(cookie)) != NULL) {
1526                 /* Skip the global zone */
1527                 if (strcmp(name, GLOBAL_ZONENAME) == 0) {
1528                         free(name);
1529                         continue;
1530                 }
1531 
1532                 if (zone_get_zonepath(name, zroot, sizeof (zroot)) != Z_OK) {
1533                         free(name);
1534                         continue;
1535                 }
1536 
1537                 bzero(rzroot, sizeof (rzroot));
1538                 if (resolvepath(zroot, rzroot, sizeof (rzroot) - 1) == -1) {
1539                         /*
1540                          * Zone path doesn't exist, or other misc error,
1541                          * so we try using the non-resolved pathname.
1542                          */
1543                         (void) strlcpy(rzroot, zroot, sizeof (rzroot));
1544                 }
1545                 if (strlen(rzroot) > 0 && (rzroot[strlen(rzroot) - 1] != '/')) {
1546                         (void) snprintf(tmp, sizeof (tmp), "%s/", rzroot);
1547                         (void) strlcpy(rzroot, tmp, sizeof (rzroot));
1548                 }
1549 
1550                 /*
1551                  * Finally, the comparison.  If the zone root path is a
1552                  * leading substring of the root path, fail.
1553                  */
1554                 if (strncmp(rzroot, root, strlen(rzroot)) == 0) {
1555                         err_print(ZONE_PATHCHECK, root, name);
1556                         err = DEVFSADM_FAILURE;
1557                         free(name);
1558                         break;
1559                 }
1560                 free(name);
1561         }
1562         endzoneent(cookie);
1563         (void) dlclose(dlhdl);
1564         return (err);
1565 }
1566 
1567 /*
1568  *  Called by the daemon when it receives an event from the devfsadm SLM
1569  *  to syseventd.
1570  *
1571  *  The devfsadm SLM uses a private event channel for communication to
1572  *  devfsadmd set-up via private libsysevent interfaces.  This handler is
1573  *  used to bind to the devfsadmd channel for event delivery.
1574  *  The devfsadmd SLM insures single calls to this routine as well as
1575  *  synchronized event delivery.
1576  *
1577  */
1578 static void
1579 event_handler(sysevent_t *ev)
1580 {
1581         char *path;
1582         char *minor;
1583         char *subclass;
1584         char *dev_ev_subclass;
1585         char *driver_name;
1586         nvlist_t *attr_list = NULL;
1587         int err = 0;
1588         int instance;
1589         int branch_event = 0;
1590 
1591         subclass = sysevent_get_subclass_name(ev);
1592         vprint(EVENT_MID, "event_handler: %s id:0X%llx\n",
1593             subclass, sysevent_get_seq(ev));
1594 
1595         if (strcmp(subclass, ESC_DEVFS_START) == 0) {
1596                 return;
1597         }
1598 
1599         /* Check if event is an instance modification */
1600         if (strcmp(subclass, ESC_DEVFS_INSTANCE_MOD) == 0) {
1601                 devfs_instance_mod();
1602                 return;
1603         }
1604         if (sysevent_get_attr_list(ev, &attr_list) != 0) {
1605                 vprint(EVENT_MID, "event_handler: can not get attr list\n");
1606                 return;
1607         }
1608 
1609         if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0 ||
1610             strcmp(subclass, ESC_DEVFS_DEVI_REMOVE) == 0 ||
1611             strcmp(subclass, ESC_DEVFS_MINOR_CREATE) == 0 ||
1612             strcmp(subclass, ESC_DEVFS_MINOR_REMOVE) == 0) {
1613                 if ((err = nvlist_lookup_string(attr_list, DEVFS_PATHNAME,
1614                     &path)) != 0)
1615                         goto out;
1616 
1617                 if (nvlist_lookup_string(attr_list, DEVFS_DEVI_CLASS,
1618                     &dev_ev_subclass) != 0)
1619                         dev_ev_subclass = NULL;
1620 
1621                 if (nvlist_lookup_string(attr_list, DEVFS_DRIVER_NAME,
1622                     &driver_name) != 0)
1623                         driver_name = NULL;
1624 
1625                 if (nvlist_lookup_int32(attr_list, DEVFS_INSTANCE,
1626                     &instance) != 0)
1627                         instance = -1;
1628 
1629                 if (nvlist_lookup_int32(attr_list, DEVFS_BRANCH_EVENT,
1630                     &branch_event) != 0)
1631                         branch_event = 0;
1632 
1633                 if (nvlist_lookup_string(attr_list, DEVFS_MINOR_NAME,
1634                     &minor) != 0)
1635                         minor = NULL;
1636 
1637                 lock_dev();
1638 
1639                 if (strcmp(ESC_DEVFS_DEVI_ADD, subclass) == 0) {
1640                         add_minor_pathname(path, NULL, dev_ev_subclass);
1641                         if (branch_event) {
1642                                 build_and_enq_event(EC_DEV_BRANCH,
1643                                     ESC_DEV_BRANCH_ADD, path, DI_NODE_NIL,
1644                                     NULL);
1645                         }
1646 
1647                 } else if (strcmp(ESC_DEVFS_MINOR_CREATE, subclass) == 0) {
1648                         add_minor_pathname(path, minor, dev_ev_subclass);
1649 
1650                 } else if (strcmp(ESC_DEVFS_MINOR_REMOVE, subclass) == 0) {
1651                         hot_cleanup(path, minor, dev_ev_subclass, driver_name,
1652                             instance);
1653 
1654                 } else { /* ESC_DEVFS_DEVI_REMOVE */
1655                         hot_cleanup(path, NULL, dev_ev_subclass,
1656                             driver_name, instance);
1657                         if (branch_event) {
1658                                 build_and_enq_event(EC_DEV_BRANCH,
1659                                     ESC_DEV_BRANCH_REMOVE, path, DI_NODE_NIL,
1660                                     NULL);
1661                         }
1662                 }
1663 
1664                 unlock_dev(CACHE_STATE);
1665 
1666         } else if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0 ||
1667             strcmp(subclass, ESC_DEVFS_BRANCH_REMOVE) == 0) {
1668                 if ((err = nvlist_lookup_string(attr_list,
1669                     DEVFS_PATHNAME, &path)) != 0)
1670                         goto out;
1671 
1672                 /* just log ESC_DEV_BRANCH... event */
1673                 if (strcmp(subclass, ESC_DEVFS_BRANCH_ADD) == 0)
1674                         dev_ev_subclass = ESC_DEV_BRANCH_ADD;
1675                 else
1676                         dev_ev_subclass = ESC_DEV_BRANCH_REMOVE;
1677 
1678                 lock_dev();
1679                 build_and_enq_event(EC_DEV_BRANCH, dev_ev_subclass, path,
1680                     DI_NODE_NIL, NULL);
1681                 unlock_dev(CACHE_STATE);
1682         } else
1683                 err_print(UNKNOWN_EVENT, subclass);
1684 
1685 out:
1686         if (err)
1687                 err_print(EVENT_ATTR_LOOKUP_FAILED, strerror(err));
1688         nvlist_free(attr_list);
1689 }
1690 
1691 static void
1692 dca_impl_init(char *root, char *minor, struct dca_impl *dcip)
1693 {
1694         assert(root);
1695 
1696         dcip->dci_root = root;
1697         dcip->dci_minor = minor;
1698         dcip->dci_driver = NULL;
1699         dcip->dci_error = 0;
1700         dcip->dci_flags = 0;
1701         dcip->dci_arg = NULL;
1702 }
1703 
1704 /*
1705  *  Kernel logs a message when a devinfo node is attached.  Try to create
1706  *  /dev and /devices for each minor node.  minorname can be NULL.
1707  */
1708 void
1709 add_minor_pathname(char *node, char *minor, char *ev_subclass)
1710 {
1711         struct dca_impl dci;
1712 
1713         vprint(CHATTY_MID, "add_minor_pathname: node_path=%s minor=%s\n",
1714             node, minor ? minor : "NULL");
1715 
1716         dca_impl_init(node, minor, &dci);
1717 
1718         /*
1719          * Restrict hotplug link creation if daemon
1720          * started  with -i option.
1721          */
1722         if (single_drv == TRUE) {
1723                 dci.dci_driver = driver;
1724         }
1725 
1726         /*
1727          * We are being invoked in response to a hotplug
1728          * event. Also, notify RCM if nodetype indicates
1729          * a network device has been hotplugged.
1730          */
1731         dci.dci_flags = DCA_HOT_PLUG | DCA_CHECK_TYPE;
1732 
1733         devi_tree_walk(&dci, DINFOPROP|DINFOMINOR, ev_subclass);
1734 }
1735 
1736 static di_node_t
1737 find_clone_node()
1738 {
1739         static di_node_t clone_node = DI_NODE_NIL;
1740 
1741         if (clone_node == DI_NODE_NIL)
1742                 clone_node = di_init("/pseudo/clone@0", DINFOPROP);
1743         return (clone_node);
1744 }
1745 
1746 static int
1747 is_descendent_of(di_node_t node, char *driver)
1748 {
1749         while (node != DI_NODE_NIL) {
1750                 char *drv = di_driver_name(node);
1751                 if (strcmp(drv, driver) == 0)
1752                         return (1);
1753                 node = di_parent_node(node);
1754         }
1755         return (0);
1756 }
1757 
1758 /*
1759  * Checks the minor type.  If it is an alias node, then lookup
1760  * the real node/minor first, then call minor_process() to
1761  * do the real work.
1762  */
1763 static int
1764 check_minor_type(di_node_t node, di_minor_t minor, void *arg)
1765 {
1766         ddi_minor_type  minor_type;
1767         di_node_t       clone_node;
1768         char            *mn;
1769         char            *nt;
1770         struct mlist    *dep;
1771         struct dca_impl *dcip = arg;
1772 
1773         assert(dcip);
1774 
1775         dep = dcip->dci_arg;
1776 
1777         mn = di_minor_name(minor);
1778 
1779         /*
1780          * We match driver here instead of in minor_process
1781          * as we want the actual driver name. This check is
1782          * unnecessary during deferred processing.
1783          */
1784         if (dep &&
1785             ((dcip->dci_driver && !is_descendent_of(node, dcip->dci_driver)) ||
1786             (dcip->dci_minor && strcmp(mn, dcip->dci_minor)))) {
1787                 return (DI_WALK_CONTINUE);
1788         }
1789 
1790         if ((dcip->dci_flags & DCA_CHECK_TYPE) &&
1791             (nt = di_minor_nodetype(minor)) &&
1792             (strcmp(nt, DDI_NT_NET) == 0)) {
1793                 dcip->dci_flags |= DCA_NOTIFY_RCM;
1794                 dcip->dci_flags &= ~DCA_CHECK_TYPE;
1795         }
1796 
1797         minor_type = di_minor_type(minor);
1798 
1799         if (minor_type == DDM_MINOR) {
1800                 minor_process(node, minor, dep);
1801 
1802         } else if (minor_type == DDM_ALIAS) {
1803                 struct mlist *cdep, clone_del = {0};
1804 
1805                 clone_node = find_clone_node();
1806                 if (clone_node == DI_NODE_NIL) {
1807                         err_print(DI_INIT_FAILED, "clone", strerror(errno));
1808                         return (DI_WALK_CONTINUE);
1809                 }
1810 
1811                 cdep = dep ? &clone_del : NULL;
1812 
1813                 minor_process(clone_node, minor, cdep);
1814 
1815                 /*
1816                  * cache "alias" minor node and free "clone" minor
1817                  */
1818                 if (cdep != NULL && cdep->head != NULL) {
1819                         assert(cdep->tail != NULL);
1820                         cache_deferred_minor(dep, node, minor);
1821                         dcip->dci_arg = cdep;
1822                         process_deferred_links(dcip, DCA_FREE_LIST);
1823                         dcip->dci_arg = dep;
1824                 }
1825         }
1826 
1827         return (DI_WALK_CONTINUE);
1828 }
1829 
1830 
1831 /*
1832  *  This is the entry point for each minor node, whether walking
1833  *  the entire tree via di_walk_minor() or processing a hotplug event
1834  *  for a single devinfo node (via hotplug ndi_devi_online()).
1835  */
1836 /*ARGSUSED*/
1837 static void
1838 minor_process(di_node_t node, di_minor_t minor, struct mlist *dep)
1839 {
1840         create_list_t   *create;
1841         int             defer;
1842 
1843         vprint(CHATTY_MID, "minor_process: node=%s, minor=%s\n",
1844             di_node_name(node), di_minor_name(minor));
1845 
1846         if (dep != NULL) {
1847 
1848                 /*
1849                  * Reset /devices node to minor_perm perm/ownership
1850                  * if we are here to deactivate device allocation
1851                  */
1852                 if (build_devices == TRUE) {
1853                         reset_node_permissions(node, minor);
1854                 }
1855 
1856                 if (build_dev == FALSE) {
1857                         return;
1858                 }
1859 
1860                 /*
1861                  * This function will create any nodes for /etc/devlink.tab.
1862                  * If devlink.tab handles link creation, we don't call any
1863                  * devfsadm modules since that could cause duplicate caching
1864                  * in the enumerate functions if different re strings are
1865                  * passed that are logically identical.  I'm still not
1866                  * convinced this would cause any harm, but better to be safe.
1867                  *
1868                  * Deferred processing is available only for devlinks
1869                  * created through devfsadm modules.
1870                  */
1871                 if (process_devlink_compat(minor, node) == TRUE) {
1872                         return;
1873                 }
1874         } else {
1875                 vprint(CHATTY_MID, "minor_process: deferred processing\n");
1876         }
1877 
1878         /*
1879          * look for relevant link create rules in the modules, and
1880          * invoke the link create callback function to build a link
1881          * if there is a match.
1882          */
1883         defer = 0;
1884         for (create = create_head; create != NULL; create = create->next) {
1885                 if ((minor_matches_rule(node, minor, create) == TRUE) &&
1886                     class_ok(create->create->device_class) ==
1887                     DEVFSADM_SUCCESS) {
1888                         if (call_minor_init(create->modptr) ==
1889                             DEVFSADM_FAILURE) {
1890                                 continue;
1891                         }
1892 
1893                         /*
1894                          * If NOT doing the deferred creates (i.e. 1st pass) and
1895                          * rule requests deferred processing cache the minor
1896                          * data.
1897                          *
1898                          * If deferred processing (2nd pass), create links
1899                          * ONLY if rule requests deferred processing.
1900                          */
1901                         if (dep && ((create->create->flags & CREATE_MASK) ==
1902                             CREATE_DEFER)) {
1903                                 defer = 1;
1904                                 continue;
1905                         } else if (dep == NULL &&
1906                             ((create->create->flags & CREATE_MASK) !=
1907                             CREATE_DEFER)) {
1908                                 continue;
1909                         }
1910 
1911                         if ((*(create->create->callback_fcn))
1912                             (minor, node) == DEVFSADM_TERMINATE) {
1913                                 break;
1914                         }
1915                 }
1916         }
1917 
1918         if (defer)
1919                 cache_deferred_minor(dep, node, minor);
1920 }
1921 
1922 
1923 /*
1924  * Cache node and minor in defer list.
1925  */
1926 static void
1927 cache_deferred_minor(
1928         struct mlist *dep,
1929         di_node_t node,
1930         di_minor_t minor)
1931 {
1932         struct minor    *mp;
1933         const char      *fcn = "cache_deferred_minor";
1934 
1935         vprint(CHATTY_MID, "%s node=%s, minor=%s\n", fcn,
1936             di_node_name(node), di_minor_name(minor));
1937 
1938         if (dep == NULL) {
1939                 vprint(CHATTY_MID, "%s: cannot cache during "
1940                     "deferred processing. Ignoring minor\n", fcn);
1941                 return;
1942         }
1943 
1944         mp = (struct minor *)s_zalloc(sizeof (struct minor));
1945         mp->node = node;
1946         mp->minor = minor;
1947         mp->next = NULL;
1948 
1949         assert(dep->head == NULL || dep->tail != NULL);
1950         if (dep->head == NULL) {
1951                 dep->head = mp;
1952         } else {
1953                 dep->tail->next = mp;
1954         }
1955         dep->tail = mp;
1956 }
1957 
1958 /*
1959  *  Check to see if "create" link creation rule matches this node/minor.
1960  *  If it does, return TRUE.
1961  */
1962 static int
1963 minor_matches_rule(di_node_t node, di_minor_t minor, create_list_t *create)
1964 {
1965         char *m_nodetype, *m_drvname;
1966 
1967         if (create->create->node_type != NULL) {
1968 
1969                 m_nodetype = di_minor_nodetype(minor);
1970                 assert(m_nodetype != NULL);
1971 
1972                 switch (create->create->flags & TYPE_MASK) {
1973                 case TYPE_EXACT:
1974                         if (strcmp(create->create->node_type, m_nodetype) !=
1975                             0) {
1976                                 return (FALSE);
1977                         }
1978                         break;
1979                 case TYPE_PARTIAL:
1980                         if (strncmp(create->create->node_type, m_nodetype,
1981                             strlen(create->create->node_type)) != 0) {
1982                                 return (FALSE);
1983                         }
1984                         break;
1985                 case TYPE_RE:
1986                         if (regexec(&(create->node_type_comp), m_nodetype,
1987                             0, NULL, 0) != 0) {
1988                                 return (FALSE);
1989                         }
1990                         break;
1991                 }
1992         }
1993 
1994         if (create->create->drv_name != NULL) {
1995                 m_drvname = di_driver_name(node);
1996                 switch (create->create->flags & DRV_MASK) {
1997                 case DRV_EXACT:
1998                         if (strcmp(create->create->drv_name, m_drvname) != 0) {
1999                                 return (FALSE);
2000                         }
2001                         break;
2002                 case DRV_RE:
2003                         if (regexec(&(create->drv_name_comp), m_drvname,
2004                             0, NULL, 0) != 0) {
2005                                 return (FALSE);
2006                         }
2007                         break;
2008                 }
2009         }
2010 
2011         return (TRUE);
2012 }
2013 
2014 /*
2015  * If no classes were given on the command line, then return DEVFSADM_SUCCESS.
2016  * Otherwise, return DEVFSADM_SUCCESS if the device "class" from the module
2017  * matches one of the device classes given on the command line,
2018  * otherwise, return DEVFSADM_FAILURE.
2019  */
2020 static int
2021 class_ok(char *class)
2022 {
2023         int i;
2024 
2025         if (num_classes == 0) {
2026                 return (DEVFSADM_SUCCESS);
2027         }
2028 
2029         for (i = 0; i < num_classes; i++) {
2030                 if (strcmp(class, classes[i]) == 0) {
2031                         return (DEVFSADM_SUCCESS);
2032                 }
2033         }
2034         return (DEVFSADM_FAILURE);
2035 }
2036 
2037 /*
2038  * call minor_fini on active modules, then unload ALL modules
2039  */
2040 static void
2041 unload_modules(void)
2042 {
2043         module_t *module_free;
2044         create_list_t *create_free;
2045         remove_list_t *remove_free;
2046 
2047         while (create_head != NULL) {
2048                 create_free = create_head;
2049                 create_head = create_head->next;
2050 
2051                 if ((create_free->create->flags & TYPE_RE) == TYPE_RE) {
2052                         regfree(&(create_free->node_type_comp));
2053                 }
2054                 if ((create_free->create->flags & DRV_RE) == DRV_RE) {
2055                         regfree(&(create_free->drv_name_comp));
2056                 }
2057                 free(create_free);
2058         }
2059 
2060         while (remove_head != NULL) {
2061                 remove_free = remove_head;
2062                 remove_head = remove_head->next;
2063                 free(remove_free);
2064         }
2065 
2066         while (module_head != NULL) {
2067 
2068                 if ((module_head->minor_fini != NULL) &&
2069                     ((module_head->flags & MODULE_ACTIVE) == MODULE_ACTIVE)) {
2070                         (void) (*(module_head->minor_fini))();
2071                 }
2072 
2073                 vprint(MODLOAD_MID, "unloading module %s\n", module_head->name);
2074                 free(module_head->name);
2075                 (void) dlclose(module_head->dlhandle);
2076 
2077                 module_free = module_head;
2078                 module_head = module_head->next;
2079                 free(module_free);
2080         }
2081 }
2082 
2083 /*
2084  * Load devfsadm logical link processing modules.
2085  */
2086 static void
2087 load_modules(void)
2088 {
2089         DIR *mod_dir;
2090         struct dirent *entp;
2091         char cdir[PATH_MAX + 1];
2092         char *last;
2093         char *mdir = module_dirs;
2094         char *fcn = "load_modules: ";
2095 
2096         while (*mdir != '\0') {
2097 
2098                 while (*mdir == ':') {
2099                         mdir++;
2100                 }
2101 
2102                 if (*mdir == '\0') {
2103                         continue;
2104                 }
2105 
2106                 last = strchr(mdir, ':');
2107 
2108                 if (last == NULL) {
2109                         last = mdir + strlen(mdir);
2110                 }
2111 
2112                 (void) strncpy(cdir, mdir, last - mdir);
2113                 cdir[last - mdir] = '\0';
2114                 mdir += strlen(cdir);
2115 
2116                 if ((mod_dir = opendir(cdir)) == NULL) {
2117                         vprint(MODLOAD_MID, "%sopendir(%s): %s\n",
2118                             fcn, cdir, strerror(errno));
2119                         continue;
2120                 }
2121 
2122                 while ((entp = readdir(mod_dir)) != NULL) {
2123 
2124                         if ((strcmp(entp->d_name, ".") == 0) ||
2125                             (strcmp(entp->d_name, "..") == 0)) {
2126                                 continue;
2127                         }
2128 
2129                         load_module(entp->d_name, cdir);
2130                 }
2131                 s_closedir(mod_dir);
2132         }
2133 }
2134 
2135 static void
2136 load_module(char *mname, char *cdir)
2137 {
2138         _devfsadm_create_reg_t *create_reg;
2139         _devfsadm_remove_reg_V1_t *remove_reg;
2140         create_list_t *create_list_element;
2141         create_list_t **create_list_next;
2142         remove_list_t *remove_list_element;
2143         remove_list_t **remove_list_next;
2144         char epath[PATH_MAX + 1], *end;
2145         char *fcn = "load_module: ";
2146         char *dlerrstr;
2147         void *dlhandle;
2148         module_t *module;
2149         int flags;
2150         int n;
2151         int i;
2152 
2153         /* ignore any file which does not end in '.so' */
2154         if ((end = strstr(mname, MODULE_SUFFIX)) != NULL) {
2155                 if (end[strlen(MODULE_SUFFIX)] != '\0') {
2156                         return;
2157                 }
2158         } else {
2159                 return;
2160         }
2161 
2162         (void) snprintf(epath, sizeof (epath), "%s/%s", cdir, mname);
2163 
2164         if ((dlhandle = dlopen(epath, RTLD_LAZY)) == NULL) {
2165                 dlerrstr = dlerror();
2166                 err_print(DLOPEN_FAILED, epath,
2167                     dlerrstr ? dlerrstr : "unknown error");
2168                 return;
2169         }
2170 
2171         /* dlsym the _devfsadm_create_reg structure */
2172         if (NULL == (create_reg = (_devfsadm_create_reg_t *)
2173             dlsym(dlhandle, _DEVFSADM_CREATE_REG))) {
2174                 vprint(MODLOAD_MID, "dlsym(%s, %s): symbol not found\n", epath,
2175                     _DEVFSADM_CREATE_REG);
2176         } else {
2177                 vprint(MODLOAD_MID, "%sdlsym(%s, %s) succeeded\n",
2178                     fcn, epath, _DEVFSADM_CREATE_REG);
2179         }
2180 
2181         /* dlsym the _devfsadm_remove_reg structure */
2182         if (NULL == (remove_reg = (_devfsadm_remove_reg_V1_t *)
2183             dlsym(dlhandle, _DEVFSADM_REMOVE_REG))) {
2184                 vprint(MODLOAD_MID, "dlsym(%s,\n\t%s): symbol not found\n",
2185                     epath, _DEVFSADM_REMOVE_REG);
2186         } else {
2187                 vprint(MODLOAD_MID, "dlsym(%s, %s): succeeded\n",
2188                     epath, _DEVFSADM_REMOVE_REG);
2189         }
2190 
2191         vprint(MODLOAD_MID, "module %s loaded\n", epath);
2192 
2193         module = (module_t *)s_malloc(sizeof (module_t));
2194         module->name = s_strdup(epath);
2195         module->dlhandle = dlhandle;
2196 
2197         /* dlsym other module functions, to be called later */
2198         module->minor_fini = (int (*)())dlsym(dlhandle, MINOR_FINI);
2199         module->minor_init = (int (*)())dlsym(dlhandle, MINOR_INIT);
2200         module->flags = 0;
2201 
2202         /*
2203          *  put a ptr to each struct devfsadm_create on "create_head"
2204          *  list sorted in interpose_lvl.
2205          */
2206         if (create_reg != NULL) {
2207                 for (i = 0; i < create_reg->count; i++) {
2208                         int flags = create_reg->tblp[i].flags;
2209 
2210                         create_list_element = (create_list_t *)
2211                             s_malloc(sizeof (create_list_t));
2212 
2213                         create_list_element->create = &(create_reg->tblp[i]);
2214                         create_list_element->modptr = module;
2215 
2216                         if (((flags & CREATE_MASK) != 0) &&
2217                             ((flags & CREATE_MASK) != CREATE_DEFER)) {
2218                                 free(create_list_element);
2219                                 err_print("illegal flag combination in "
2220                                     "module create\n");
2221                                 err_print(IGNORING_ENTRY, i, epath);
2222                                 continue;
2223                         }
2224 
2225                         if (((flags & TYPE_MASK) == 0) ^
2226                             (create_reg->tblp[i].node_type == NULL)) {
2227                                 free(create_list_element);
2228                                 err_print("flags value incompatible with "
2229                                     "node_type value in module create\n");
2230                                 err_print(IGNORING_ENTRY, i, epath);
2231                                 continue;
2232                         }
2233 
2234                         if (((flags & TYPE_MASK) != 0) &&
2235                             ((flags & TYPE_MASK) != TYPE_EXACT) &&
2236                             ((flags & TYPE_MASK) != TYPE_RE) &&
2237                             ((flags & TYPE_MASK) != TYPE_PARTIAL)) {
2238                                 free(create_list_element);
2239                                 err_print("illegal TYPE_* flag combination in "
2240                                     "module create\n");
2241                                 err_print(IGNORING_ENTRY, i, epath);
2242                                 continue;
2243                         }
2244 
2245                         /* precompile regular expression for efficiency */
2246                         if ((flags & TYPE_RE) == TYPE_RE) {
2247                                 if ((n = regcomp(&(create_list_element->
2248                                     node_type_comp),
2249                                     create_reg->tblp[i].node_type,
2250                                     REG_EXTENDED)) != 0) {
2251                                         free(create_list_element);
2252                                         err_print(REGCOMP_FAILED,
2253                                             create_reg->tblp[i].node_type, n);
2254                                         err_print(IGNORING_ENTRY, i, epath);
2255                                         continue;
2256                                 }
2257                         }
2258 
2259                         if (((flags & DRV_MASK) == 0) ^
2260                             (create_reg->tblp[i].drv_name == NULL)) {
2261                                 if ((flags & TYPE_RE) == TYPE_RE) {
2262                                         regfree(&(create_list_element->
2263                                             node_type_comp));
2264                                 }
2265                                 free(create_list_element);
2266                                 err_print("flags value incompatible with "
2267                                     "drv_name value in module create\n");
2268                                 err_print(IGNORING_ENTRY, i, epath);
2269                                 continue;
2270                         }
2271 
2272                         if (((flags & DRV_MASK) != 0) &&
2273                             ((flags & DRV_MASK) != DRV_EXACT) &&
2274                             ((flags & DRV_MASK) !=  DRV_RE)) {
2275                                 if ((flags & TYPE_RE) == TYPE_RE) {
2276                                         regfree(&(create_list_element->
2277                                             node_type_comp));
2278                                 }
2279                                 free(create_list_element);
2280                                 err_print("illegal DRV_* flag combination in "
2281                                     "module create\n");
2282                                 err_print(IGNORING_ENTRY, i, epath);
2283                                 continue;
2284                         }
2285 
2286                         /* precompile regular expression for efficiency */
2287                         if ((create_reg->tblp[i].flags & DRV_RE) == DRV_RE) {
2288                                 if ((n = regcomp(&(create_list_element->
2289                                     drv_name_comp),
2290                                     create_reg->tblp[i].drv_name,
2291                                     REG_EXTENDED)) != 0) {
2292                                         if ((flags & TYPE_RE) == TYPE_RE) {
2293                                                 regfree(&(create_list_element->
2294                                                     node_type_comp));
2295                                         }
2296                                         free(create_list_element);
2297                                         err_print(REGCOMP_FAILED,
2298                                             create_reg->tblp[i].drv_name, n);
2299                                         err_print(IGNORING_ENTRY, i, epath);
2300                                         continue;
2301                                 }
2302                         }
2303 
2304 
2305                         /* add to list sorted by interpose level */
2306                         for (create_list_next = &(create_head);
2307                             (*create_list_next != NULL) &&
2308                             (*create_list_next)->create->interpose_lvl >=
2309                             create_list_element->create->interpose_lvl;
2310                             create_list_next = &((*create_list_next)->next))
2311                                 ;
2312                         create_list_element->next = *create_list_next;
2313                         *create_list_next = create_list_element;
2314                 }
2315         }
2316 
2317         /*
2318          *  put a ptr to each struct devfsadm_remove on "remove_head"
2319          *  list sorted by interpose_lvl.
2320          */
2321         flags = 0;
2322         if (remove_reg != NULL) {
2323                 if (remove_reg->version < DEVFSADM_V1)
2324                         flags |= RM_NOINTERPOSE;
2325                 for (i = 0; i < remove_reg->count; i++) {
2326 
2327                         remove_list_element = (remove_list_t *)
2328                             s_malloc(sizeof (remove_list_t));
2329 
2330                         remove_list_element->remove = &(remove_reg->tblp[i]);
2331                         remove_list_element->remove->flags |= flags;
2332                         remove_list_element->modptr = module;
2333 
2334                         for (remove_list_next = &(remove_head);
2335                             (*remove_list_next != NULL) &&
2336                             (*remove_list_next)->remove->interpose_lvl >=
2337                             remove_list_element->remove->interpose_lvl;
2338                             remove_list_next = &((*remove_list_next)->next))
2339                                 ;
2340                         remove_list_element->next = *remove_list_next;
2341                         *remove_list_next = remove_list_element;
2342                 }
2343         }
2344 
2345         module->next = module_head;
2346         module_head = module;
2347 }
2348 
2349 /*
2350  * After we have completed a CACHE_STATE, if a SYNC_STATE does not occur
2351  * within 'timeout' secs the minor_fini_thread needs to do a SYNC_STATE
2352  * so that we still call the minor_fini routines.
2353  */
2354 /*ARGSUSED*/
2355 static void
2356 minor_fini_thread(void *arg)
2357 {
2358         timestruc_t     abstime;
2359 
2360         vprint(INITFINI_MID, "minor_fini_thread starting\n");
2361 
2362         (void) mutex_lock(&minor_fini_mutex);
2363         for (;;) {
2364                 /* wait the gather period, or until signaled */
2365                 abstime.tv_sec = time(NULL) + minor_fini_timeout;
2366                 abstime.tv_nsec = 0;
2367                 (void) cond_timedwait(&minor_fini_cv,
2368                     &minor_fini_mutex, &abstime);
2369 
2370                 /* if minor_fini was canceled, go wait again */
2371                 if (minor_fini_canceled == TRUE)
2372                         continue;
2373 
2374                 /* if minor_fini was delayed, go wait again */
2375                 if (minor_fini_delayed == TRUE) {
2376                         minor_fini_delayed = FALSE;
2377                         continue;
2378                 }
2379 
2380                 /* done with cancellations and delays, do the SYNC_STATE */
2381                 (void) mutex_unlock(&minor_fini_mutex);
2382 
2383                 lock_dev();
2384                 unlock_dev(SYNC_STATE);
2385                 vprint(INITFINI_MID, "minor_fini sync done\n");
2386 
2387                 (void) mutex_lock(&minor_fini_mutex);
2388         }
2389 }
2390 
2391 
2392 /*
2393  * Attempt to initialize module, if a minor_init routine exists.  Set
2394  * the active flag if the routine exists and succeeds.  If it doesn't
2395  * exist, just set the active flag.
2396  */
2397 static int
2398 call_minor_init(module_t *module)
2399 {
2400         char *fcn = "call_minor_init: ";
2401 
2402         if ((module->flags & MODULE_ACTIVE) == MODULE_ACTIVE) {
2403                 return (DEVFSADM_SUCCESS);
2404         }
2405 
2406         vprint(INITFINI_MID, "%smodule %s.  current state: inactive\n",
2407             fcn, module->name);
2408 
2409         if (module->minor_init == NULL) {
2410                 module->flags |= MODULE_ACTIVE;
2411                 vprint(INITFINI_MID, "minor_init not defined\n");
2412                 return (DEVFSADM_SUCCESS);
2413         }
2414 
2415         if ((*(module->minor_init))() == DEVFSADM_FAILURE) {
2416                 err_print(FAILED_FOR_MODULE, MINOR_INIT, module->name);
2417                 return (DEVFSADM_FAILURE);
2418         }
2419 
2420         vprint(INITFINI_MID, "minor_init() returns DEVFSADM_SUCCESS. "
2421             "new state: active\n");
2422 
2423         module->flags |= MODULE_ACTIVE;
2424         return (DEVFSADM_SUCCESS);
2425 }
2426 
2427 /*
2428  * Creates a symlink 'link' to the physical path of node:minor.
2429  * Construct link contents, then call create_link_common().
2430  */
2431 /*ARGSUSED*/
2432 int
2433 devfsadm_mklink(char *link, di_node_t node, di_minor_t minor, int flags)
2434 {
2435         char rcontents[PATH_MAX];
2436         char devlink[PATH_MAX];
2437         char phy_path[PATH_MAX];
2438         char *acontents;
2439         char *dev_path;
2440         int numslashes;
2441         int rv;
2442         int i, link_exists;
2443         int last_was_slash = FALSE;
2444 
2445         /*
2446          * try to use devices path
2447          */
2448         if ((node == lnode) && (minor == lminor)) {
2449                 acontents = lphy_path;
2450         } else if (di_minor_type(minor) == DDM_ALIAS) {
2451                 /* use /pseudo/clone@0:<driver> as the phys path */
2452                 (void) snprintf(phy_path, sizeof (phy_path),
2453                     "/pseudo/clone@0:%s",
2454                     di_driver_name(di_minor_devinfo(minor)));
2455                 acontents = phy_path;
2456         } else {
2457                 if ((dev_path = di_devfs_path(node)) == NULL) {
2458                         err_print(DI_DEVFS_PATH_FAILED, strerror(errno));
2459                         devfsadm_exit(1);
2460                 }
2461                 (void) snprintf(phy_path, sizeof (phy_path), "%s:%s",
2462                     dev_path, di_minor_name(minor));
2463                 di_devfs_path_free(dev_path);
2464                 acontents = phy_path;
2465         }
2466 
2467         /* prepend link with dev_dir contents */
2468         (void) strlcpy(devlink, dev_dir, sizeof (devlink));
2469         (void) strlcat(devlink, "/", sizeof (devlink));
2470         (void) strlcat(devlink, link, sizeof (devlink));
2471 
2472         /*
2473          * Calculate # of ../ to add.  Account for double '//' in path.
2474          * Ignore all leading slashes.
2475          */
2476         for (i = 0; link[i] == '/'; i++)
2477                 ;
2478         for (numslashes = 0; link[i] != '\0'; i++) {
2479                 if (link[i] == '/') {
2480                         if (last_was_slash == FALSE) {
2481                                 numslashes++;
2482                                 last_was_slash = TRUE;
2483                         }
2484                 } else {
2485                         last_was_slash = FALSE;
2486                 }
2487         }
2488         /* Don't count any trailing '/' */
2489         if (link[i-1] == '/') {
2490                 numslashes--;
2491         }
2492 
2493         rcontents[0] = '\0';
2494         do {
2495                 (void) strlcat(rcontents, "../", sizeof (rcontents));
2496         } while (numslashes-- != 0);
2497 
2498         (void) strlcat(rcontents, "devices", sizeof (rcontents));
2499         (void) strlcat(rcontents, acontents, sizeof (rcontents));
2500 
2501         if (devlinks_debug == TRUE) {
2502                 vprint(INFO_MID, "adding link %s ==> %s\n", devlink, rcontents);
2503         }
2504 
2505         if ((rv = create_link_common(devlink, rcontents, &link_exists))
2506             == DEVFSADM_SUCCESS) {
2507                 linknew = TRUE;
2508                 add_link_to_cache(link, acontents);
2509         } else {
2510                 linknew = FALSE;
2511         }
2512 
2513         if (link_exists == TRUE) {
2514                 /* Link exists or was just created */
2515                 (void) di_devlink_add_link(devlink_cache, link, rcontents,
2516                     DI_PRIMARY_LINK);
2517 
2518                 if (system_labeled && (flags & DA_ADD)) {
2519                         /*
2520                          * Add this to the list of allocatable devices. If this
2521                          * is a hotplugged, removable disk, add it as rmdisk.
2522                          */
2523                         int instance = di_instance(node);
2524 
2525                         if ((flags & DA_CD) &&
2526                             (_da_check_for_usb(devlink, root_dir) == 1)) {
2527                                 (void) da_add_list(&devlist, devlink, instance,
2528                                     DA_ADD|DA_RMDISK);
2529                                 update_devdb = DA_RMDISK;
2530                         } else if (linknew == TRUE) {
2531                                 (void) da_add_list(&devlist, devlink, instance,
2532                                     flags);
2533                                 update_devdb = flags;
2534                         }
2535                 }
2536         }
2537 
2538         return (rv);
2539 }
2540 
2541 /*
2542  * Creates a symlink link to primary_link.  Calculates relative
2543  * directory offsets, then calls link_common().
2544  */
2545 /*ARGSUSED*/
2546 int
2547 devfsadm_secondary_link(char *link, char *primary_link, int flags)
2548 {
2549         char contents[PATH_MAX + 1];
2550         char devlink[PATH_MAX + 1];
2551         int rv, link_exists;
2552         char *fpath;
2553         char *tpath;
2554         char *op;
2555 
2556         /* prepend link with dev_dir contents */
2557         (void) strcpy(devlink, dev_dir);
2558         (void) strcat(devlink, "/");
2559         (void) strcat(devlink, link);
2560         /*
2561          * building extra link, so use first link as link contents, but first
2562          * make it relative.
2563          */
2564         fpath = link;
2565         tpath = primary_link;
2566         op = contents;
2567 
2568         while (*fpath == *tpath && *fpath != '\0') {
2569                 fpath++, tpath++;
2570         }
2571 
2572         /* Count directories to go up, if any, and add "../" */
2573         while (*fpath != '\0') {
2574                 if (*fpath == '/') {
2575                         (void) strcpy(op, "../");
2576                         op += 3;
2577                 }
2578                 fpath++;
2579         }
2580 
2581         /*
2582          * Back up to the start of the current path component, in
2583          * case in the middle
2584          */
2585         while (tpath != primary_link && *(tpath-1) != '/') {
2586                 tpath--;
2587         }
2588         (void) strcpy(op, tpath);
2589 
2590         if (devlinks_debug == TRUE) {
2591                 vprint(INFO_MID, "adding extra link %s ==> %s\n",
2592                     devlink, contents);
2593         }
2594 
2595         if ((rv = create_link_common(devlink, contents, &link_exists))
2596             == DEVFSADM_SUCCESS) {
2597                 /*
2598                  * we need to save the ultimate /devices contents, and not the
2599                  * secondary link, since hotcleanup only looks at /devices path.
2600                  * Since we don't have devices path here, we can try to get it
2601                  * by readlink'ing the secondary link.  This assumes the primary
2602                  * link was created first.
2603                  */
2604                 add_link_to_cache(link, lphy_path);
2605                 linknew = TRUE;
2606                 if (system_labeled &&
2607                     ((flags & DA_AUDIO) && (flags & DA_ADD))) {
2608                         /*
2609                          * Add this device to the list of allocatable devices.
2610                          */
2611                         int     instance = 0;
2612 
2613                         op = strrchr(contents, '/');
2614                         op++;
2615                         (void) sscanf(op, "%d", &instance);
2616                         (void) da_add_list(&devlist, devlink, instance, flags);
2617                         update_devdb = flags;
2618                 }
2619         } else {
2620                 linknew = FALSE;
2621         }
2622 
2623         /*
2624          * If link exists or was just created, add it to the database
2625          */
2626         if (link_exists == TRUE) {
2627                 (void) di_devlink_add_link(devlink_cache, link, contents,
2628                     DI_SECONDARY_LINK);
2629         }
2630 
2631         return (rv);
2632 }
2633 
2634 /* returns pointer to the devices directory */
2635 char *
2636 devfsadm_get_devices_dir()
2637 {
2638         return (devices_dir);
2639 }
2640 
2641 /*
2642  * Does the actual link creation.  VERBOSE_MID only used if there is
2643  * a change.  CHATTY_MID used otherwise.
2644  */
2645 static int
2646 create_link_common(char *devlink, char *contents, int *exists)
2647 {
2648         int try;
2649         int linksize;
2650         int max_tries = 0;
2651         static int prev_link_existed = TRUE;
2652         char checkcontents[PATH_MAX + 1];
2653         char *hide;
2654 
2655         *exists = FALSE;
2656 
2657         /* Database is not updated when file_mods == FALSE */
2658         if (file_mods == FALSE) {
2659                 linksize = readlink(devlink, checkcontents, PATH_MAX);
2660                 if (linksize > 0) {
2661                         checkcontents[linksize] = '\0';
2662                         if (strcmp(checkcontents, contents) != 0) {
2663                                 vprint(CHATTY_MID, REMOVING_LINK,
2664                                     devlink, checkcontents);
2665                                 return (DEVFSADM_SUCCESS);
2666                         } else {
2667                                 vprint(CHATTY_MID, "link exists and is correct:"
2668                                     " %s -> %s\n", devlink, contents);
2669                                 /* failure only in that the link existed */
2670                                 return (DEVFSADM_FAILURE);
2671                         }
2672                 } else {
2673                         vprint(VERBOSE_MID, CREATING_LINK, devlink, contents);
2674                         return (DEVFSADM_SUCCESS);
2675                 }
2676         }
2677 
2678         /*
2679          * systems calls are expensive, so predict whether to readlink
2680          * or symlink first, based on previous attempt
2681          */
2682         if (prev_link_existed == FALSE) {
2683                 try = CREATE_LINK;
2684         } else {
2685                 try = READ_LINK;
2686         }
2687 
2688         while (++max_tries <= 3) {
2689 
2690                 switch (try) {
2691                 case CREATE_LINK:
2692 
2693                         if (symlink(contents, devlink) == 0) {
2694                                 vprint(VERBOSE_MID, CREATING_LINK, devlink,
2695                                     contents);
2696                                 prev_link_existed = FALSE;
2697                                 /* link successfully created */
2698                                 *exists = TRUE;
2699                                 set_logindev_perms(devlink);
2700                                 return (DEVFSADM_SUCCESS);
2701                         } else {
2702                                 switch (errno) {
2703 
2704                                 case ENOENT:
2705                                         /* dirpath to node doesn't exist */
2706                                         hide = strrchr(devlink, '/');
2707                                         *hide = '\0';
2708                                         s_mkdirp(devlink, S_IRWXU|S_IRGRP|
2709                                             S_IXGRP|S_IROTH|S_IXOTH);
2710                                         *hide = '/';
2711                                         break;
2712                                 case EEXIST:
2713                                         try = READ_LINK;
2714                                         break;
2715                                 default:
2716                                         err_print(SYMLINK_FAILED, devlink,
2717                                             contents, strerror(errno));
2718                                         return (DEVFSADM_FAILURE);
2719                                 }
2720                         }
2721                         break;
2722 
2723                 case READ_LINK:
2724 
2725                         linksize = readlink(devlink, checkcontents, PATH_MAX);
2726                         if (linksize >= 0) {
2727                                 checkcontents[linksize] = '\0';
2728                                 if (strcmp(checkcontents, contents) != 0) {
2729                                         s_unlink(devlink);
2730                                         vprint(VERBOSE_MID, REMOVING_LINK,
2731                                             devlink, checkcontents);
2732                                         try = CREATE_LINK;
2733                                 } else {
2734                                         prev_link_existed = TRUE;
2735                                         vprint(CHATTY_MID,
2736                                             "link exists and is correct:"
2737                                             " %s -> %s\n", devlink, contents);
2738                                         *exists = TRUE;
2739                                         /* failure in that the link existed */
2740                                         return (DEVFSADM_FAILURE);
2741                                 }
2742                         } else {
2743                                 switch (errno) {
2744                                 case EINVAL:
2745                                         /* not a symlink, remove and create */
2746                                         s_unlink(devlink);
2747                                 default:
2748                                         /* maybe it didn't exist at all */
2749                                         try = CREATE_LINK;
2750                                         break;
2751                                 }
2752                         }
2753                         break;
2754                 }
2755         }
2756         err_print(MAX_ATTEMPTS, devlink, contents);
2757         return (DEVFSADM_FAILURE);
2758 }
2759 
2760 static void
2761 set_logindev_perms(char *devlink)
2762 {
2763         struct login_dev *newdev;
2764         struct passwd pwd, *resp;
2765         char pwd_buf[PATH_MAX];
2766         int rv;
2767         struct stat sb;
2768         char *devfs_path = NULL;
2769 
2770         /*
2771          * We only want logindev perms to be set when a device is
2772          * hotplugged or an application requests synchronous creates.
2773          * So we enable this only in daemon mode. In addition,
2774          * login(1) only fixes the std. /dev dir. So we don't
2775          * change perms if alternate root is set.
2776          * login_dev_enable is TRUE only in these cases.
2777          */
2778         if (login_dev_enable != TRUE)
2779                 return;
2780 
2781         /*
2782          * Normally, /etc/logindevperm has few (8 - 10 entries) which
2783          * may be regular expressions (globs were converted to RE).
2784          * So just do a linear search through the list.
2785          */
2786         for (newdev = login_dev_cache; newdev; newdev = newdev->ldev_next) {
2787                 vprint(FILES_MID, "matching %s with %s\n", devlink,
2788                     newdev->ldev_device);
2789 
2790                 if (regexec(&newdev->ldev_device_regex, devlink, 0,
2791                     NULL, 0) == 0)  {
2792                         vprint(FILES_MID, "matched %s with %s\n", devlink,
2793                             newdev->ldev_device);
2794                         break;
2795                 }
2796         }
2797 
2798         if (newdev == NULL)
2799                 return;
2800 
2801         /*
2802          * we have a match, now find the driver associated with this
2803          * minor node using a snapshot on the physical path
2804          */
2805         (void) resolve_link(devlink, NULL, NULL, &devfs_path, 0);
2806         if (devfs_path) {
2807                 di_node_t node;
2808                 char *drv = NULL;
2809                 struct driver_list *list;
2810                 char *p;
2811 
2812                 /* truncate on : so we can take a snapshot */
2813                 (void) strcpy(pwd_buf, devfs_path);
2814                 p = strrchr(pwd_buf, ':');
2815                 if (p == NULL) {
2816                         free(devfs_path);
2817                         return;
2818                 }
2819                 *p = '\0';
2820 
2821                 vprint(FILES_MID, "link=%s->physpath=%s\n",
2822                     devlink, pwd_buf);
2823 
2824                 node = di_init(pwd_buf, DINFOMINOR);
2825 
2826                 if (node) {
2827                         drv = di_driver_name(node);
2828 
2829                         if (drv) {
2830                                 vprint(FILES_MID, "%s: driver is %s\n",
2831                                     devlink, drv);
2832                         }
2833                         di_fini(node);
2834                 }
2835                 /* search thru the driver list specified in logindevperm */
2836                 list = newdev->ldev_driver_list;
2837                 if ((drv != NULL) && (list != NULL)) {
2838                         while (list) {
2839                                 if (strcmp(list->driver_name,
2840                                     drv) == 0) {
2841                                         vprint(FILES_MID,
2842                                             "driver %s match!\n", drv);
2843                                         break;
2844                                 }
2845                                 list = list->next;
2846                         }
2847                         if (list == NULL) {
2848                                 vprint(FILES_MID, "no driver match!\n");
2849                                 free(devfs_path);
2850                                 return;
2851                         }
2852                 }
2853                 free(devfs_path);
2854         } else {
2855                 return;
2856         }
2857 
2858         vprint(FILES_MID, "changing permissions of %s\n", devlink);
2859 
2860         /*
2861          * We have a match. We now attempt to determine the
2862          * owner and group of the console user.
2863          *
2864          * stat() the console device newdev->ldev_console
2865          * which will always exist - it will have the right owner but
2866          * not the right group. Use getpwuid_r() to determine group for this
2867          * uid.
2868          * Note, it is safe to use name service here since if name services
2869          * are not available (during boot or in single-user mode), then
2870          * console owner will be root and its gid can be found in
2871          * local files.
2872          */
2873         if (stat(newdev->ldev_console, &sb) == -1) {
2874                 vprint(VERBOSE_MID, STAT_FAILED, newdev->ldev_console,
2875                     strerror(errno));
2876                 return;
2877         }
2878 
2879         resp = NULL;
2880         rv = getpwuid_r(sb.st_uid, &pwd, pwd_buf, sizeof (pwd_buf), &resp);
2881         if (rv || resp == NULL) {
2882                 rv = rv ? rv : EINVAL;
2883                 vprint(VERBOSE_MID, GID_FAILED, sb.st_uid,
2884                     strerror(rv));
2885                 return;
2886         }
2887 
2888         assert(&pwd == resp);
2889 
2890         sb.st_gid = resp->pw_gid;
2891 
2892         if (chmod(devlink, newdev->ldev_perms) == -1) {
2893                 vprint(VERBOSE_MID, CHMOD_FAILED, devlink,
2894                     strerror(errno));
2895                 return;
2896         }
2897 
2898         if (chown(devlink, sb.st_uid, sb.st_gid)  == -1) {
2899                 vprint(VERBOSE_MID, CHOWN_FAILED, devlink,
2900                     strerror(errno));
2901         }
2902 }
2903 
2904 /*
2905  * Reset /devices node with appropriate permissions and
2906  * ownership as specified in /etc/minor_perm.
2907  */
2908 static void
2909 reset_node_permissions(di_node_t node, di_minor_t minor)
2910 {
2911         int spectype;
2912         char phy_path[PATH_MAX + 1];
2913         mode_t mode;
2914         dev_t dev;
2915         uid_t uid;
2916         gid_t gid;
2917         struct stat sb;
2918         char *dev_path, *aminor = NULL;
2919 
2920         /* lphy_path starts with / */
2921         if ((dev_path = di_devfs_path(node)) == NULL) {
2922                 err_print(DI_DEVFS_PATH_FAILED, strerror(errno));
2923                 devfsadm_exit(1);
2924         }
2925         (void) strcpy(lphy_path, dev_path);
2926         di_devfs_path_free(dev_path);
2927 
2928         (void) strcat(lphy_path, ":");
2929         if (di_minor_type(minor) == DDM_ALIAS) {
2930                 char *driver;
2931                 aminor = di_minor_name(minor);
2932                 driver = di_driver_name(di_minor_devinfo(minor));
2933                 (void) strcat(lphy_path, driver);
2934         } else
2935                 (void) strcat(lphy_path, di_minor_name(minor));
2936 
2937         (void) strcpy(phy_path, devices_dir);
2938         (void) strcat(phy_path, lphy_path);
2939 
2940         lnode = node;
2941         lminor = minor;
2942 
2943         vprint(CHATTY_MID, "reset_node_permissions: phy_path=%s lphy_path=%s\n",
2944             phy_path, lphy_path);
2945 
2946         dev = di_minor_devt(minor);
2947         spectype = di_minor_spectype(minor); /* block or char */
2948 
2949         getattr(phy_path, aminor, spectype, dev, &mode, &uid, &gid);
2950 
2951         /*
2952          * compare and set permissions and ownership
2953          *
2954          * Under devfs, a quick insertion and removal of USB devices
2955          * would cause stat of physical path to fail. In this case,
2956          * we emit a verbose message, but don't print errors.
2957          */
2958         if ((stat(phy_path, &sb) == -1) || (sb.st_rdev != dev)) {
2959                 vprint(VERBOSE_MID, NO_DEVFS_NODE, phy_path);
2960                 return;
2961         }
2962 
2963         /*
2964          * If we are here for a new device
2965          *      If device allocation is on
2966          *      then
2967          *              set ownership to root:other and permissions to 0000
2968          *      else
2969          *              set ownership and permissions as specified in minor_perm
2970          * If we are here for an existing device
2971          *      If device allocation is to be turned on
2972          *      then
2973          *              reset ownership to root:other and permissions to 0000
2974          *      else if device allocation is to be turned off
2975          *              reset ownership and permissions to those specified in
2976          *              minor_perm
2977          *      else
2978          *              preserve existing/user-modified ownership and
2979          *              permissions
2980          *
2981          * devfs indicates a new device by faking access time to be zero.
2982          */
2983         if (sb.st_atime != 0) {
2984                 int  i;
2985                 char *nt;
2986 
2987                 if ((devalloc_flag == 0) && (devalloc_is_on != 1))
2988                         /*
2989                          * Leave existing devices as they are if we are not
2990                          * turning device allocation on/off.
2991                          */
2992                         return;
2993 
2994                 nt = di_minor_nodetype(minor);
2995 
2996                 if (nt == NULL)
2997                         return;
2998 
2999                 for (i = 0; devalloc_list[i]; i++) {
3000                         if (strcmp(nt, devalloc_list[i]) == 0)
3001                                 /*
3002                                  * One of the types recognized by devalloc,
3003                                  * reset attrs.
3004                                  */
3005                                 break;
3006                 }
3007                 if (devalloc_list[i] == NULL)
3008                         return;
3009         }
3010 
3011         if (file_mods == FALSE) {
3012                 /* Nothing more to do if simulating */
3013                 vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode);
3014                 return;
3015         }
3016 
3017         if ((devalloc_flag == DA_ON) || (devalloc_is_on == 1)) {
3018                 /*
3019                  * we are here either to turn device allocation on
3020                  * or to add a new device while device allocation in on
3021                  */
3022                 mode = DEALLOC_MODE;
3023                 uid = DA_UID;
3024                 gid = DA_GID;
3025         }
3026 
3027         if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) ||
3028             (sb.st_mode != mode)) {
3029                 if (chmod(phy_path, mode) == -1)
3030                         vprint(VERBOSE_MID, CHMOD_FAILED,
3031                             phy_path, strerror(errno));
3032         }
3033         if ((devalloc_is_on == 1) || (devalloc_flag == DA_ON) ||
3034             (sb.st_uid != uid || sb.st_gid != gid)) {
3035                 if (chown(phy_path, uid, gid) == -1)
3036                         vprint(VERBOSE_MID, CHOWN_FAILED,
3037                             phy_path, strerror(errno));
3038         }
3039 
3040         /* Report that we actually did something */
3041         vprint(VERBOSE_MID, PERM_MSG, phy_path, uid, gid, mode);
3042 }
3043 
3044 /*
3045  * Removes logical link and the minor node it refers to.  If file is a
3046  * link, we recurse and try to remove the minor node (or link if path is
3047  * a double link) that file's link contents refer to.
3048  */
3049 static void
3050 devfsadm_rm_work(char *file, int recurse, int file_type)
3051 {
3052         char *fcn = "devfsadm_rm_work: ";
3053         int linksize;
3054         char contents[PATH_MAX + 1];
3055         char nextfile[PATH_MAX + 1];
3056         char newfile[PATH_MAX + 1];
3057         char *ptr;
3058 
3059         vprint(REMOVE_MID, "%s%s\n", fcn, file);
3060 
3061         /* TYPE_LINK split into multiple if's due to excessive indentations */
3062         if (file_type == TYPE_LINK) {
3063                 (void) strcpy(newfile, dev_dir);
3064                 (void) strcat(newfile, "/");
3065                 (void) strcat(newfile, file);
3066         }
3067 
3068         if ((file_type == TYPE_LINK) && (recurse == TRUE) &&
3069             ((linksize = readlink(newfile, contents, PATH_MAX)) > 0)) {
3070                 contents[linksize] = '\0';
3071 
3072                 if (is_minor_node(contents, &ptr) == DEVFSADM_TRUE) {
3073                         devfsadm_rm_work(++ptr, FALSE, TYPE_DEVICES);
3074                 } else {
3075                         if (strncmp(contents, DEV "/", strlen(DEV) + 1) == 0) {
3076                                 devfsadm_rm_work(&contents[strlen(DEV) + 1],
3077                                     TRUE, TYPE_LINK);
3078                         } else {
3079                                 if ((ptr = strrchr(file, '/')) != NULL) {
3080                                         *ptr = '\0';
3081                                         (void) strcpy(nextfile, file);
3082                                         *ptr = '/';
3083                                         (void) strcat(nextfile, "/");
3084                                 } else {
3085                                         (void) strcpy(nextfile, "");
3086                                 }
3087                                 (void) strcat(nextfile, contents);
3088                                 devfsadm_rm_work(nextfile, TRUE, TYPE_LINK);
3089                         }
3090                 }
3091         }
3092 
3093         if (file_type == TYPE_LINK) {
3094                 vprint(VERBOSE_MID, DEVFSADM_UNLINK, newfile);
3095                 if (file_mods == TRUE) {
3096                         rm_link_from_cache(file);
3097                         s_unlink(newfile);
3098                         rm_parent_dir_if_empty(newfile);
3099                         invalidate_enumerate_cache();
3100                         (void) di_devlink_rm_link(devlink_cache, file);
3101