OpenGrok

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