xref: /illumos-gate/usr/src/cmd/devfsadm/devfsadm.c (revision cb2bfa20)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5055e805aSedp  * Common Development and Distribution License (the "License").
6055e805aSedp  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21055e805aSedp 
227c478bd9Sstevel@tonic-gate /*
23406fc510SToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
24540b2cc7SHans Rosenfeld  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
2594c894bbSVikram Hegde  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
26f2dbfd32SRobert Mustacchi  * Copyright 2019, Joyent, Inc.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * Devfsadm replaces drvconfig, audlinks, disks, tapes, ports, devlinks
317c478bd9Sstevel@tonic-gate  * as a general purpose device administrative utility.	It creates
327c478bd9Sstevel@tonic-gate  * devices special files in /devices and logical links in /dev, and
337c478bd9Sstevel@tonic-gate  * coordinates updates to /etc/path_to_instance with the kernel.  It
347c478bd9Sstevel@tonic-gate  * operates in both command line mode to handle user or script invoked
357c478bd9Sstevel@tonic-gate  * reconfiguration updates, and operates in daemon mode to handle dynamic
367c478bd9Sstevel@tonic-gate  * reconfiguration for hotplugging support.
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
3945916cd2Sjpk #include <string.h>
40f875b4ebSrica #include <deflt.h>
4145916cd2Sjpk #include <tsol/label.h>
4245916cd2Sjpk #include <bsm/devices.h>
4345916cd2Sjpk #include <bsm/devalloc.h>
447c478bd9Sstevel@tonic-gate #include <utime.h>
456638bf60Saj #include <sys/param.h>
466638bf60Saj #include <bsm/libbsm.h>
4717e9b2b7SDhanaraj M #include <zone.h>
4845916cd2Sjpk #include "devfsadm_impl.h"
497c478bd9Sstevel@tonic-gate 
5045916cd2Sjpk /* externs from devalloc.c */
5145916cd2Sjpk extern void  _reset_devalloc(int);
5245916cd2Sjpk extern void _update_devalloc_db(devlist_t *, int, int, char *, char *);
5345916cd2Sjpk extern int _da_check_for_usb(char *, char *);
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /* create or remove nodes or links. unset with -n */
567c478bd9Sstevel@tonic-gate static int file_mods = TRUE;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* cleanup mode.  Set with -C */
597c478bd9Sstevel@tonic-gate static int cleanup = FALSE;
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /* devlinks -d compatibility */
627c478bd9Sstevel@tonic-gate static int devlinks_debug = FALSE;
637c478bd9Sstevel@tonic-gate 
6445916cd2Sjpk /* flag to check if system is labeled */
6545916cd2Sjpk int system_labeled = FALSE;
6645916cd2Sjpk 
6745916cd2Sjpk /* flag to enable/disable device allocation with -e/-d */
6845916cd2Sjpk static int devalloc_flag = 0;
6945916cd2Sjpk 
706638bf60Saj /* flag that indicates if device allocation is on or not */
716638bf60Saj static int devalloc_is_on = 0;
726638bf60Saj 
7345916cd2Sjpk /* flag to update device allocation database for this device type */
7445916cd2Sjpk static int update_devdb = 0;
7545916cd2Sjpk 
7645916cd2Sjpk /*
7745916cd2Sjpk  * devices to be deallocated with -d :
7845916cd2Sjpk  *	audio, floppy, cd, floppy, tape, rmdisk.
7945916cd2Sjpk  */
8045916cd2Sjpk static char *devalloc_list[10] = {DDI_NT_AUDIO, DDI_NT_CD, DDI_NT_CD_CHAN,
8145916cd2Sjpk 				    DDI_NT_FD, DDI_NT_TAPE, DDI_NT_BLOCK_CHAN,
8245916cd2Sjpk 				    DDI_NT_UGEN, DDI_NT_USB_ATTACHMENT_POINT,
8345916cd2Sjpk 				    DDI_NT_SCSI_NEXUS, NULL};
847c478bd9Sstevel@tonic-gate 
8545916cd2Sjpk /* list of allocatable devices */
8645916cd2Sjpk static devlist_t devlist;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /* load a single driver only.  set with -i */
897c478bd9Sstevel@tonic-gate static int single_drv = FALSE;
907c478bd9Sstevel@tonic-gate static char *driver = NULL;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /* attempt to load drivers or defer attach nodes */
937c478bd9Sstevel@tonic-gate static int load_attach_drv = TRUE;
947c478bd9Sstevel@tonic-gate 
95c9cc1492SJerry Gilliam /* reload all driver.conf files */
96c9cc1492SJerry Gilliam static int update_all_drivers = FALSE;
97c9cc1492SJerry Gilliam 
987c478bd9Sstevel@tonic-gate /* set if invoked via /usr/lib/devfsadm/devfsadmd */
997c478bd9Sstevel@tonic-gate static int daemon_mode = FALSE;
1007c478bd9Sstevel@tonic-gate 
1017e3e5701SJan Parcel /* set if event_handler triggered */
1027e3e5701SJan Parcel int event_driven = FALSE;
1037e3e5701SJan Parcel 
1047c478bd9Sstevel@tonic-gate /* output directed to syslog during daemon mode if set */
1057c478bd9Sstevel@tonic-gate static int logflag = FALSE;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /* build links in /dev.  -x to turn off */
1087c478bd9Sstevel@tonic-gate static int build_dev = TRUE;
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate /* build nodes in /devices.  -y to turn off */
1117c478bd9Sstevel@tonic-gate static int build_devices = TRUE;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /* -z to turn off */
1147c478bd9Sstevel@tonic-gate static int flush_path_to_inst_enable = TRUE;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /* variables used for path_to_inst flushing */
1177c478bd9Sstevel@tonic-gate static int inst_count = 0;
1187c478bd9Sstevel@tonic-gate static mutex_t count_lock;
1197c478bd9Sstevel@tonic-gate static cond_t cv;
1207c478bd9Sstevel@tonic-gate 
121ff2aee48Scth /* variables for minor_fini thread */
1227c478bd9Sstevel@tonic-gate static mutex_t minor_fini_mutex;
123ff2aee48Scth static int minor_fini_canceled = TRUE;
124ff2aee48Scth static int minor_fini_delayed = FALSE;
125ff2aee48Scth static cond_t minor_fini_cv;
126ff2aee48Scth static int minor_fini_timeout = MINOR_FINI_TIMEOUT_DEFAULT;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate /* single-threads /dev modification */
1297c478bd9Sstevel@tonic-gate static sema_t dev_sema;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /* the program we were invoked as; ie argv[0] */
1327c478bd9Sstevel@tonic-gate static char *prog;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /* pointers to create/remove link lists */
1357c478bd9Sstevel@tonic-gate static create_list_t *create_head = NULL;
1367c478bd9Sstevel@tonic-gate static remove_list_t *remove_head = NULL;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*  supports the class -c option */
1397c478bd9Sstevel@tonic-gate static char **classes = NULL;
1407c478bd9Sstevel@tonic-gate static int num_classes = 0;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /* used with verbose option -v or -V */
1437c478bd9Sstevel@tonic-gate static int num_verbose = 0;
1447c478bd9Sstevel@tonic-gate static char **verbose = NULL;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static struct mperm *minor_perms = NULL;
1477c478bd9Sstevel@tonic-gate static driver_alias_t *driver_aliases = NULL;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /* set if -r alternate root given */
1507c478bd9Sstevel@tonic-gate static char *root_dir = "";
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate /* /devices or <rootdir>/devices */
1537c478bd9Sstevel@tonic-gate static char *devices_dir  = DEVICES;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /* /dev or <rootdir>/dev */
1567c478bd9Sstevel@tonic-gate static char *dev_dir = DEV;
1577c478bd9Sstevel@tonic-gate 
158facf4a8dSllai /* /etc/dev or <rootdir>/etc/dev */
159facf4a8dSllai static char *etc_dev_dir = ETCDEV;
160facf4a8dSllai 
161facf4a8dSllai /*
162facf4a8dSllai  * writable root (for lock files and doors during install).
163facf4a8dSllai  * This is also root dir for /dev attr dir during install.
164facf4a8dSllai  */
165facf4a8dSllai static char *attr_root = NULL;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /* /etc/path_to_inst unless -p used */
1687c478bd9Sstevel@tonic-gate static char *inst_file = INSTANCE_FILE;
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate /* /usr/lib/devfsadm/linkmods unless -l used */
1717c478bd9Sstevel@tonic-gate static char *module_dirs = MODULE_DIRS;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /* default uid/gid used if /etc/minor_perm entry not found */
1747c478bd9Sstevel@tonic-gate static uid_t root_uid;
1757c478bd9Sstevel@tonic-gate static gid_t sys_gid;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate /* /etc/devlink.tab unless devlinks -t used */
1787c478bd9Sstevel@tonic-gate static char *devlinktab_file = NULL;
1797c478bd9Sstevel@tonic-gate 
1808d483882Smlf /* File and data structure to reserve enumerate IDs */
1818d483882Smlf static char *enumerate_file = ENUMERATE_RESERVED;
1828d483882Smlf static enumerate_file_t *enumerate_reserved = NULL;
1838d483882Smlf 
1847c478bd9Sstevel@tonic-gate /* set if /dev link is new. speeds up rm_stale_links */
1857c478bd9Sstevel@tonic-gate static int linknew = TRUE;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate /* variables for devlink.tab compat processing */
1887c478bd9Sstevel@tonic-gate static devlinktab_list_t *devlinktab_list = NULL;
1897c478bd9Sstevel@tonic-gate static unsigned int devlinktab_line = 0;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate /* cache head for devfsadm_enumerate*() functions */
1927c478bd9Sstevel@tonic-gate static numeral_set_t *head_numeral_set = NULL;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate /* list list of devfsadm modules */
1957c478bd9Sstevel@tonic-gate static module_t *module_head = NULL;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /* name_to_major list used in utility function */
1987c478bd9Sstevel@tonic-gate static n2m_t *n2m_list = NULL;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /* cache of some links used for performance */
2017c478bd9Sstevel@tonic-gate static linkhead_t *headlinkhead = NULL;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate /* locking variables to prevent multiples writes to /dev */
2047c478bd9Sstevel@tonic-gate static int hold_dev_lock = FALSE;
2057c478bd9Sstevel@tonic-gate static int hold_daemon_lock = FALSE;
2067c478bd9Sstevel@tonic-gate static int dev_lock_fd;
2077c478bd9Sstevel@tonic-gate static int daemon_lock_fd;
2087c478bd9Sstevel@tonic-gate static char dev_lockfile[PATH_MAX + 1];
2097c478bd9Sstevel@tonic-gate static char daemon_lockfile[PATH_MAX + 1];
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /* last devinfo node/minor processed. used for performance */
2127c478bd9Sstevel@tonic-gate static di_node_t lnode;
2137c478bd9Sstevel@tonic-gate static di_minor_t lminor;
2147c478bd9Sstevel@tonic-gate static char lphy_path[PATH_MAX + 1] = {""};
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate /* Globals used by the link database */
2177c478bd9Sstevel@tonic-gate static di_devlink_handle_t devlink_cache;
2187c478bd9Sstevel@tonic-gate static int update_database = FALSE;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate /* Globals used to set logindev perms */
2217c478bd9Sstevel@tonic-gate static struct login_dev *login_dev_cache = NULL;
2227c478bd9Sstevel@tonic-gate static int login_dev_enable = FALSE;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /* Global to use devinfo snapshot cache */
2257c478bd9Sstevel@tonic-gate static int use_snapshot_cache = FALSE;
2267c478bd9Sstevel@tonic-gate 
227aa646b9dSvikram /* Global for no-further-processing hash */
228aa646b9dSvikram static item_t **nfp_hash;
229aa646b9dSvikram static mutex_t  nfp_mutex = DEFAULTMUTEX;
230aa646b9dSvikram 
2317c478bd9Sstevel@tonic-gate /*
23267323fc4SJohn Levon  * Directories not removed even when empty.  They are packaged, or may
23367323fc4SJohn Levon  * be referred to from a non-global zone.  The dirs must be listed in
23467323fc4SJohn Levon  * canonical form i.e. without leading "/dev/"
2357c478bd9Sstevel@tonic-gate  */
23667323fc4SJohn Levon static char *sticky_dirs[] =
23767323fc4SJohn Levon 	{"dsk", "rdsk", "term", "lofi", "rlofi", NULL};
2387c478bd9Sstevel@tonic-gate 
239facf4a8dSllai /* Devname globals */
240facf4a8dSllai static int lookup_door_fd = -1;
241facf4a8dSllai static char *lookup_door_path;
242facf4a8dSllai 
2437c478bd9Sstevel@tonic-gate static void load_dev_acl(void);
244c9cc1492SJerry Gilliam static void update_drvconf(major_t, int);
245facf4a8dSllai static void check_reconfig_state(void);
246facf4a8dSllai static int s_stat(const char *, struct stat *);
2477c478bd9Sstevel@tonic-gate 
2481ca93273Seota static int is_blank(char *);
2491ca93273Seota 
250f05faa4eSjacobs /* sysevent queue related globals */
251f05faa4eSjacobs static mutex_t  syseventq_mutex = DEFAULTMUTEX;
252f05faa4eSjacobs static syseventq_t *syseventq_front;
253f05faa4eSjacobs static syseventq_t *syseventq_back;
254f05faa4eSjacobs static void process_syseventq();
255f05faa4eSjacobs 
25694c894bbSVikram Hegde static di_node_t devi_root_node = DI_NODE_NIL;
25794c894bbSVikram Hegde 
2587c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])2597c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
2607c478bd9Sstevel@tonic-gate {
2617c478bd9Sstevel@tonic-gate 	struct passwd *pw;
2627c478bd9Sstevel@tonic-gate 	struct group *gp;
2637c478bd9Sstevel@tonic-gate 	pid_t pid;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2667c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 	if ((prog = strrchr(argv[0], '/')) == NULL) {
2697c478bd9Sstevel@tonic-gate 		prog = argv[0];
2707c478bd9Sstevel@tonic-gate 	} else {
2717c478bd9Sstevel@tonic-gate 		prog++;
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	if (getuid() != 0) {
2757c478bd9Sstevel@tonic-gate 		err_print(MUST_BE_ROOT);
2767c478bd9Sstevel@tonic-gate 		devfsadm_exit(1);
277537714daSvikram 		/*NOTREACHED*/
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 
28017e9b2b7SDhanaraj M 	if (getzoneid() != GLOBAL_ZONEID) {
28117e9b2b7SDhanaraj M 		err_print(MUST_BE_GLOBAL_ZONE);
28217e9b2b7SDhanaraj M 		devfsadm_exit(1);
28317e9b2b7SDhanaraj M 	}
28417e9b2b7SDhanaraj M 
2857c478bd9Sstevel@tonic-gate 	/*
2867c478bd9Sstevel@tonic-gate 	 * Close all files except stdin/stdout/stderr
2877c478bd9Sstevel@tonic-gate 	 */
2887c478bd9Sstevel@tonic-gate 	closefrom(3);
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if ((pw = getpwnam(DEFAULT_DEV_USER)) != NULL) {
2917c478bd9Sstevel@tonic-gate 		root_uid = pw->pw_uid;
2927c478bd9Sstevel@tonic-gate 	} else {
2937c478bd9Sstevel@tonic-gate 		err_print(CANT_FIND_USER, DEFAULT_DEV_USER);
2947c478bd9Sstevel@tonic-gate 		root_uid = (uid_t)0;	/* assume 0 is root */
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/* the default group is sys */
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	if ((gp = getgrnam(DEFAULT_DEV_GROUP)) != NULL) {
3007c478bd9Sstevel@tonic-gate 		sys_gid = gp->gr_gid;
3017c478bd9Sstevel@tonic-gate 	} else {
3027c478bd9Sstevel@tonic-gate 		err_print(CANT_FIND_GROUP, DEFAULT_DEV_GROUP);
3037c478bd9Sstevel@tonic-gate 		sys_gid = (gid_t)3;	/* assume 3 is sys */
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	(void) umask(0);
3077c478bd9Sstevel@tonic-gate 
30845916cd2Sjpk 	system_labeled = is_system_labeled();
30945916cd2Sjpk 	if (system_labeled == FALSE) {
31045916cd2Sjpk 		/*
31145916cd2Sjpk 		 * is_system_labeled() will return false in case we are
31245916cd2Sjpk 		 * starting before the first reboot after Trusted Extensions
313f875b4ebSrica 		 * is enabled.  Check the setting in /etc/system to see if
314f875b4ebSrica 		 * TX is enabled (even if not yet booted).
31545916cd2Sjpk 		 */
316f875b4ebSrica 		if (defopen("/etc/system") == 0) {
317f875b4ebSrica 			if (defread("set sys_labeling=1") != NULL)
318f875b4ebSrica 				system_labeled = TRUE;
319f875b4ebSrica 
320f875b4ebSrica 			/* close defaults file */
321f875b4ebSrica 			(void) defopen(NULL);
322facf4a8dSllai 		}
32345916cd2Sjpk 	}
3246638bf60Saj 	/*
3256638bf60Saj 	 * Check if device allocation is enabled.
3266638bf60Saj 	 */
3274dd25bdcSJerry Gilliam 	devalloc_is_on = (da_is_on() == 1) ? 1 : 0;
32845916cd2Sjpk 
329f875b4ebSrica #ifdef DEBUG
330f875b4ebSrica 	if (system_labeled == FALSE) {
331f875b4ebSrica 		struct stat tx_stat;
332f875b4ebSrica 
333f875b4ebSrica 		/* test hook: see also mkdevalloc.c and allocate.c */
334f875b4ebSrica 		system_labeled = is_system_labeled_debug(&tx_stat);
335f875b4ebSrica 	}
336f875b4ebSrica #endif
337f875b4ebSrica 
3387c478bd9Sstevel@tonic-gate 	parse_args(argc, argv);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	(void) sema_init(&dev_sema, 1, USYNC_THREAD, NULL);
3417c478bd9Sstevel@tonic-gate 
34245916cd2Sjpk 	/* Initialize device allocation list */
34345916cd2Sjpk 	devlist.audio = devlist.cd = devlist.floppy = devlist.tape =
3440a653502Swroche 	    devlist.rmdisk = NULL;
34545916cd2Sjpk 
3467c478bd9Sstevel@tonic-gate 	if (daemon_mode == TRUE) {
3477c478bd9Sstevel@tonic-gate 		/*
3487c478bd9Sstevel@tonic-gate 		 * Build /dev and /devices before daemonizing if
3497c478bd9Sstevel@tonic-gate 		 * reconfig booting and daemon invoked with alternate
3507c478bd9Sstevel@tonic-gate 		 * root. This is to support install.
3517c478bd9Sstevel@tonic-gate 		 */
3527c478bd9Sstevel@tonic-gate 		if (getenv(RECONFIG_BOOT) != NULL && root_dir[0] != '\0') {
3537c478bd9Sstevel@tonic-gate 			vprint(INFO_MID, CONFIGURING);
3547c478bd9Sstevel@tonic-gate 			load_dev_acl();
355c9cc1492SJerry Gilliam 			update_drvconf((major_t)-1, 0);
3567c478bd9Sstevel@tonic-gate 			process_devinfo_tree();
3577c478bd9Sstevel@tonic-gate 			(void) modctl(MODSETMINIROOT);
3587c478bd9Sstevel@tonic-gate 		}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 		/*
3617c478bd9Sstevel@tonic-gate 		 * fork before detaching from tty in order to print error
3627c478bd9Sstevel@tonic-gate 		 * message if unable to acquire file lock.  locks not preserved
3637c478bd9Sstevel@tonic-gate 		 * across forks.  Even under debug we want to fork so that
3647c478bd9Sstevel@tonic-gate 		 * when executed at boot we don't hang.
3657c478bd9Sstevel@tonic-gate 		 */
3667c478bd9Sstevel@tonic-gate 		if (fork() != 0) {
3677c478bd9Sstevel@tonic-gate 			devfsadm_exit(0);
368537714daSvikram 			/*NOTREACHED*/
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 		/* set directory to / so it coredumps there */
3727c478bd9Sstevel@tonic-gate 		if (chdir("/") == -1) {
3737c478bd9Sstevel@tonic-gate 			err_print(CHROOT_FAILED, strerror(errno));
3747c478bd9Sstevel@tonic-gate 		}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		/* only one daemon can run at a time */
3777c478bd9Sstevel@tonic-gate 		if ((pid = enter_daemon_lock()) == getpid()) {
3787c478bd9Sstevel@tonic-gate 			detachfromtty();
3797c478bd9Sstevel@tonic-gate 			(void) cond_init(&cv, USYNC_THREAD, 0);
3807c478bd9Sstevel@tonic-gate 			(void) mutex_init(&count_lock, USYNC_THREAD, 0);
381a3ab7e85SToomas Soome 			if (thr_create(NULL, 0,
382ff2aee48Scth 			    (void *(*)(void *))instance_flush_thread,
383ff2aee48Scth 			    NULL, THR_DETACHED, NULL) != 0) {
3847c478bd9Sstevel@tonic-gate 				err_print(CANT_CREATE_THREAD, "daemon",
3850a653502Swroche 				    strerror(errno));
3867c478bd9Sstevel@tonic-gate 				devfsadm_exit(1);
387537714daSvikram 				/*NOTREACHED*/
3887c478bd9Sstevel@tonic-gate 			}
3897c478bd9Sstevel@tonic-gate 
390ff2aee48Scth 			/* start the minor_fini_thread */
391ff2aee48Scth 			(void) mutex_init(&minor_fini_mutex, USYNC_THREAD, 0);
392ff2aee48Scth 			(void) cond_init(&minor_fini_cv, USYNC_THREAD, 0);
393*cb2bfa20SToomas Soome 			if (thr_create(NULL, 0, minor_fini_thread,
394ff2aee48Scth 			    NULL, THR_DETACHED, NULL)) {
395ff2aee48Scth 				err_print(CANT_CREATE_THREAD, "minor_fini",
396ff2aee48Scth 				    strerror(errno));
397ff2aee48Scth 				devfsadm_exit(1);
398537714daSvikram 				/*NOTREACHED*/
399ff2aee48Scth 			}
400ff2aee48Scth 
401ff2aee48Scth 
4027c478bd9Sstevel@tonic-gate 			/*
4030dc974a9SCathy Zhou 			 * logindevperms need only be set
4047c478bd9Sstevel@tonic-gate 			 * in daemon mode and when root dir is "/".
4057c478bd9Sstevel@tonic-gate 			 */
4060dc974a9SCathy Zhou 			if (root_dir[0] == '\0')
4077c478bd9Sstevel@tonic-gate 				login_dev_enable = TRUE;
4087c478bd9Sstevel@tonic-gate 			daemon_update();
409537714daSvikram 			devfsadm_exit(0);
410537714daSvikram 			/*NOTREACHED*/
4117c478bd9Sstevel@tonic-gate 		} else {
4127c478bd9Sstevel@tonic-gate 			err_print(DAEMON_RUNNING, pid);
4137c478bd9Sstevel@tonic-gate 			devfsadm_exit(1);
414537714daSvikram 			/*NOTREACHED*/
4157c478bd9Sstevel@tonic-gate 		}
4167c478bd9Sstevel@tonic-gate 	} else {
4177c478bd9Sstevel@tonic-gate 		/* not a daemon, so just build /dev and /devices */
4188c206d17Spr 
4198c206d17Spr 		/*
4208c206d17Spr 		 * If turning off device allocation, load the
4218c206d17Spr 		 * minor_perm file because process_devinfo_tree() will
4228c206d17Spr 		 * need this in order to reset the permissions of the
4238c206d17Spr 		 * device files.
4248c206d17Spr 		 */
4258c206d17Spr 		if (devalloc_flag == DA_OFF) {
4268c206d17Spr 			read_minor_perm_file();
4278c206d17Spr 		}
4288c206d17Spr 
4297c478bd9Sstevel@tonic-gate 		process_devinfo_tree();
43045916cd2Sjpk 		if (devalloc_flag != 0)
43145916cd2Sjpk 			/* Enable/disable device allocation */
43245916cd2Sjpk 			_reset_devalloc(devalloc_flag);
4337c478bd9Sstevel@tonic-gate 	}
4347c478bd9Sstevel@tonic-gate 	return (0);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate static void
update_drvconf(major_t major,int flags)438c9cc1492SJerry Gilliam update_drvconf(major_t major, int flags)
4397c478bd9Sstevel@tonic-gate {
440c9cc1492SJerry Gilliam 	if (modctl(MODLOADDRVCONF, major, flags) != 0)
4417c478bd9Sstevel@tonic-gate 		err_print(gettext("update_drvconf failed for major %d\n"),
4427c478bd9Sstevel@tonic-gate 		    major);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate static void
load_dev_acl()4467c478bd9Sstevel@tonic-gate load_dev_acl()
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate 	if (load_devpolicy() != 0)
4497c478bd9Sstevel@tonic-gate 		err_print(gettext("device policy load failed\n"));
4507c478bd9Sstevel@tonic-gate 	load_minor_perm_file();
4517c478bd9Sstevel@tonic-gate }
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate /*
454facf4a8dSllai  * As devfsadm is run early in boot to provide the kernel with
455facf4a8dSllai  * minor_perm info, we might as well check for reconfig at the
456facf4a8dSllai  * same time to avoid running devfsadm twice.  This gets invoked
457facf4a8dSllai  * earlier than the env variable RECONFIG_BOOT is set up.
4587c478bd9Sstevel@tonic-gate  */
459facf4a8dSllai static void
check_reconfig_state()460facf4a8dSllai check_reconfig_state()
4617c478bd9Sstevel@tonic-gate {
462facf4a8dSllai 	struct stat sb;
4637c478bd9Sstevel@tonic-gate 
464facf4a8dSllai 	if (s_stat("/reconfigure", &sb) == 0) {
465facf4a8dSllai 		(void) modctl(MODDEVNAME, MODDEVNAME_RECONFIG, 0);
4667c478bd9Sstevel@tonic-gate 	}
467facf4a8dSllai }
4687c478bd9Sstevel@tonic-gate 
469facf4a8dSllai static void
modctl_sysavail()470facf4a8dSllai modctl_sysavail()
471facf4a8dSllai {
472facf4a8dSllai 	/*
473facf4a8dSllai 	 * Inform /dev that system is available, that
474facf4a8dSllai 	 * implicit reconfig can now be performed.
475facf4a8dSllai 	 */
476facf4a8dSllai 	(void) modctl(MODDEVNAME, MODDEVNAME_SYSAVAIL, 0);
477facf4a8dSllai }
4787c478bd9Sstevel@tonic-gate 
479facf4a8dSllai static void
set_lock_root(void)480facf4a8dSllai set_lock_root(void)
481facf4a8dSllai {
482facf4a8dSllai 	struct stat sb;
483facf4a8dSllai 	char *lock_root;
484facf4a8dSllai 	size_t len;
4857c478bd9Sstevel@tonic-gate 
486facf4a8dSllai 	lock_root = attr_root ? attr_root : root_dir;
4877c478bd9Sstevel@tonic-gate 
488facf4a8dSllai 	len = strlen(lock_root) + strlen(ETCDEV) + 1;
489facf4a8dSllai 	etc_dev_dir = s_malloc(len);
490facf4a8dSllai 	(void) snprintf(etc_dev_dir, len, "%s%s", lock_root, ETCDEV);
4917c478bd9Sstevel@tonic-gate 
492facf4a8dSllai 	if (s_stat(etc_dev_dir, &sb) != 0) {
493facf4a8dSllai 		s_mkdirp(etc_dev_dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH);
494facf4a8dSllai 	} else if (!S_ISDIR(sb.st_mode)) {
495facf4a8dSllai 		err_print(NOT_DIR, etc_dev_dir);
496facf4a8dSllai 		devfsadm_exit(1);
497537714daSvikram 		/*NOTREACHED*/
498facf4a8dSllai 	}
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
501facf4a8dSllai 
5027c478bd9Sstevel@tonic-gate /*
5037c478bd9Sstevel@tonic-gate  * Parse arguments for all 6 programs handled from devfsadm.
5047c478bd9Sstevel@tonic-gate  */
5057c478bd9Sstevel@tonic-gate static void
parse_args(int argc,char * argv[])5067c478bd9Sstevel@tonic-gate parse_args(int argc, char *argv[])
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate 	char opt;
5097c478bd9Sstevel@tonic-gate 	char get_linkcompat_opts = FALSE;
5107c478bd9Sstevel@tonic-gate 	char *compat_class;
5117c478bd9Sstevel@tonic-gate 	int num_aliases = 0;
5127c478bd9Sstevel@tonic-gate 	int len;
5137c478bd9Sstevel@tonic-gate 	int retval;
5146532b960SJerry Gilliam 	int config = TRUE;
5156532b960SJerry Gilliam 	int bind = FALSE;
5166532b960SJerry Gilliam 	int force_flag = FALSE;
5177c478bd9Sstevel@tonic-gate 	struct aliases *ap = NULL;
5187c478bd9Sstevel@tonic-gate 	struct aliases *a_head = NULL;
5197c478bd9Sstevel@tonic-gate 	struct aliases *a_tail = NULL;
5207c478bd9Sstevel@tonic-gate 	struct modconfig mc;
5217c478bd9Sstevel@tonic-gate 
5226532b960SJerry Gilliam 	(void) bzero(&mc, sizeof (mc));
5236532b960SJerry Gilliam 
5247c478bd9Sstevel@tonic-gate 	if (strcmp(prog, DISKS) == 0) {
5257c478bd9Sstevel@tonic-gate 		compat_class = "disk";
5267c478bd9Sstevel@tonic-gate 		get_linkcompat_opts = TRUE;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	} else if (strcmp(prog, TAPES) == 0) {
5297c478bd9Sstevel@tonic-gate 		compat_class = "tape";
5307c478bd9Sstevel@tonic-gate 		get_linkcompat_opts = TRUE;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	} else if (strcmp(prog, PORTS) == 0) {
5337c478bd9Sstevel@tonic-gate 		compat_class = "port";
5347c478bd9Sstevel@tonic-gate 		get_linkcompat_opts = TRUE;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	} else if (strcmp(prog, AUDLINKS) == 0) {
5377c478bd9Sstevel@tonic-gate 		compat_class = "audio";
5387c478bd9Sstevel@tonic-gate 		get_linkcompat_opts = TRUE;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 	} else if (strcmp(prog, DEVLINKS) == 0) {
5417c478bd9Sstevel@tonic-gate 		devlinktab_file = DEVLINKTAB_FILE;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 		build_devices = FALSE;
5447c478bd9Sstevel@tonic-gate 		load_attach_drv = FALSE;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 		while ((opt = getopt(argc, argv, "dnr:st:vV:")) != EOF) {
5477c478bd9Sstevel@tonic-gate 			switch (opt) {
5487c478bd9Sstevel@tonic-gate 			case 'd':
5497c478bd9Sstevel@tonic-gate 				file_mods = FALSE;
5507c478bd9Sstevel@tonic-gate 				flush_path_to_inst_enable = FALSE;
5517c478bd9Sstevel@tonic-gate 				devlinks_debug = TRUE;
5527c478bd9Sstevel@tonic-gate 				break;
5537c478bd9Sstevel@tonic-gate 			case 'n':
5547c478bd9Sstevel@tonic-gate 				/* prevent driver loading and deferred attach */
5557c478bd9Sstevel@tonic-gate 				load_attach_drv = FALSE;
5567c478bd9Sstevel@tonic-gate 				break;
5577c478bd9Sstevel@tonic-gate 			case 'r':
558facf4a8dSllai 				set_root_devices_dev_dir(optarg);
5597c478bd9Sstevel@tonic-gate 				if (zone_pathcheck(root_dir) !=
5607c478bd9Sstevel@tonic-gate 				    DEVFSADM_SUCCESS)
5617c478bd9Sstevel@tonic-gate 					devfsadm_exit(1);
562537714daSvikram 					/*NOTREACHED*/
5637c478bd9Sstevel@tonic-gate 				break;
5647c478bd9Sstevel@tonic-gate 			case 's':
5657c478bd9Sstevel@tonic-gate 				/*
5667c478bd9Sstevel@tonic-gate 				 * suppress.  don't create/remove links/nodes
5677c478bd9Sstevel@tonic-gate 				 * useful with -v or -V
5687c478bd9Sstevel@tonic-gate 				 */
5697c478bd9Sstevel@tonic-gate 				file_mods = FALSE;
5707c478bd9Sstevel@tonic-gate 				flush_path_to_inst_enable = FALSE;
5717c478bd9Sstevel@tonic-gate 				break;
5727c478bd9Sstevel@tonic-gate 			case 't':
5737c478bd9Sstevel@tonic-gate 				/* supply a non-default table file */
5747c478bd9Sstevel@tonic-gate 				devlinktab_file = optarg;
5757c478bd9Sstevel@tonic-gate 				break;
5767c478bd9Sstevel@tonic-gate 			case 'v':
5777c478bd9Sstevel@tonic-gate 				/* documented verbose flag */
5787c478bd9Sstevel@tonic-gate 				add_verbose_id(VERBOSE_MID);
5797c478bd9Sstevel@tonic-gate 				break;
5807c478bd9Sstevel@tonic-gate 			case 'V':
5817c478bd9Sstevel@tonic-gate 				/* undocumented for extra verbose levels */
5827c478bd9Sstevel@tonic-gate 				add_verbose_id(optarg);
5837c478bd9Sstevel@tonic-gate 				break;
5847c478bd9Sstevel@tonic-gate 			default:
5857c478bd9Sstevel@tonic-gate 				usage();
5867c478bd9Sstevel@tonic-gate 				break;
5877c478bd9Sstevel@tonic-gate 			}
5887c478bd9Sstevel@tonic-gate 		}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 		if (optind < argc) {
5917c478bd9Sstevel@tonic-gate 			usage();
5927c478bd9Sstevel@tonic-gate 		}
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	} else if (strcmp(prog, DRVCONFIG) == 0) {
595c9cc1492SJerry Gilliam 		int update_only = 0;
5967c478bd9Sstevel@tonic-gate 		build_dev = FALSE;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 		while ((opt =
599c9cc1492SJerry Gilliam 		    getopt(argc, argv, "a:bc:dfi:m:np:R:r:suvV:x")) != EOF) {
6007c478bd9Sstevel@tonic-gate 			switch (opt) {
6017c478bd9Sstevel@tonic-gate 			case 'a':
6027c478bd9Sstevel@tonic-gate 				ap = calloc(sizeof (struct aliases), 1);
6037c478bd9Sstevel@tonic-gate 				ap->a_name = dequote(optarg);
6047c478bd9Sstevel@tonic-gate 				len = strlen(ap->a_name) + 1;
6057c478bd9Sstevel@tonic-gate 				if (len > MAXMODCONFNAME) {
6067c478bd9Sstevel@tonic-gate 					err_print(ALIAS_TOO_LONG,
6077c478bd9Sstevel@tonic-gate 					    MAXMODCONFNAME, ap->a_name);
6087c478bd9Sstevel@tonic-gate 					devfsadm_exit(1);
609537714daSvikram 					/*NOTREACHED*/
6107c478bd9Sstevel@tonic-gate 				}
6117c478bd9Sstevel@tonic-gate 				ap->a_len = len;
6127c478bd9Sstevel@tonic-gate 				if (a_tail == NULL) {
6137c478bd9Sstevel@tonic-gate 					a_head = ap;
6147c478bd9Sstevel@tonic-gate 				} else {
6157c478bd9Sstevel@tonic-gate 					a_tail->a_next = ap;
6167c478bd9Sstevel@tonic-gate 				}
6177c478bd9Sstevel@tonic-gate 				a_tail = ap;
6187c478bd9Sstevel@tonic-gate 				num_aliases++;
6196532b960SJerry Gilliam 				bind = TRUE;
6207c478bd9Sstevel@tonic-gate 				break;
6217c478bd9Sstevel@tonic-gate 			case 'b':
6226532b960SJerry Gilliam 				bind = TRUE;
6237c478bd9Sstevel@tonic-gate 				break;
6247c478bd9Sstevel@tonic-gate 			case 'c':
6257c478bd9Sstevel@tonic-gate 				(void) strcpy(mc.drvclass, optarg);
6267c478bd9Sstevel@tonic-gate 				break;
6277c478bd9Sstevel@tonic-gate 			case 'd':
6287c478bd9Sstevel@tonic-gate 				/*
6297c478bd9Sstevel@tonic-gate 				 * need to keep for compatibility, but
6307c478bd9Sstevel@tonic-gate 				 * do nothing.
6317c478bd9Sstevel@tonic-gate 				 */
6327c478bd9Sstevel@tonic-gate 				break;
6336532b960SJerry Gilliam 			case 'f':
6346532b960SJerry Gilliam 				force_flag = TRUE;
6356532b960SJerry Gilliam 				break;
6367c478bd9Sstevel@tonic-gate 			case 'i':
6377c478bd9Sstevel@tonic-gate 				single_drv = TRUE;
6387c478bd9Sstevel@tonic-gate 				(void) strcpy(mc.drvname, optarg);
6397c478bd9Sstevel@tonic-gate 				driver = s_strdup(optarg);
6407c478bd9Sstevel@tonic-gate 				break;
6417c478bd9Sstevel@tonic-gate 			case 'm':
6427c478bd9Sstevel@tonic-gate 				mc.major = atoi(optarg);
6437c478bd9Sstevel@tonic-gate 				break;
6447c478bd9Sstevel@tonic-gate 			case 'n':
6457c478bd9Sstevel@tonic-gate 				/* prevent driver loading and deferred attach */
6467c478bd9Sstevel@tonic-gate 				load_attach_drv = FALSE;
6477c478bd9Sstevel@tonic-gate 				break;
6487c478bd9Sstevel@tonic-gate 			case 'p':
6497c478bd9Sstevel@tonic-gate 				/* specify alternate path_to_inst file */
6507c478bd9Sstevel@tonic-gate 				inst_file = s_strdup(optarg);
6517c478bd9Sstevel@tonic-gate 				break;
6527c478bd9Sstevel@tonic-gate 			case 'R':
6537c478bd9Sstevel@tonic-gate 				/*
6547c478bd9Sstevel@tonic-gate 				 * Private flag for suninstall to populate
6557c478bd9Sstevel@tonic-gate 				 * device information on the installed root.
6567c478bd9Sstevel@tonic-gate 				 */
6577c478bd9Sstevel@tonic-gate 				root_dir = s_strdup(optarg);
6587c478bd9Sstevel@tonic-gate 				if (zone_pathcheck(root_dir) !=
6597c478bd9Sstevel@tonic-gate 				    DEVFSADM_SUCCESS)
6607c478bd9Sstevel@tonic-gate 				devfsadm_exit(devfsadm_copy());
661537714daSvikram 				/*NOTREACHED*/
6627c478bd9Sstevel@tonic-gate 				break;
6637c478bd9Sstevel@tonic-gate 			case 'r':
6647c478bd9Sstevel@tonic-gate 				devices_dir = s_strdup(optarg);
6657c478bd9Sstevel@tonic-gate 				if (zone_pathcheck(devices_dir) !=
6667c478bd9Sstevel@tonic-gate 				    DEVFSADM_SUCCESS)
6677c478bd9Sstevel@tonic-gate 					devfsadm_exit(1);
668537714daSvikram 					/*NOTREACHED*/
6697c478bd9Sstevel@tonic-gate 				break;
6707c478bd9Sstevel@tonic-gate 			case 's':
6717c478bd9Sstevel@tonic-gate 				/*
6727c478bd9Sstevel@tonic-gate 				 * suppress.  don't create nodes
6737c478bd9Sstevel@tonic-gate 				 * useful with -v or -V
6747c478bd9Sstevel@tonic-gate 				 */
6757c478bd9Sstevel@tonic-gate 				file_mods = FALSE;
6767c478bd9Sstevel@tonic-gate 				flush_path_to_inst_enable = FALSE;
6777c478bd9Sstevel@tonic-gate 				break;
6786532b960SJerry Gilliam 			case 'u':
6796532b960SJerry Gilliam 				/*
6806532b960SJerry Gilliam 				 * Invoked via update_drv(1m) to update
6816532b960SJerry Gilliam 				 * the kernel's driver/alias binding
6826532b960SJerry Gilliam 				 * when removing one or more aliases.
6836532b960SJerry Gilliam 				 */
6846532b960SJerry Gilliam 				config = FALSE;
6856532b960SJerry Gilliam 				break;
6867c478bd9Sstevel@tonic-gate 			case 'v':
6877c478bd9Sstevel@tonic-gate 				/* documented verbose flag */
6887c478bd9Sstevel@tonic-gate 				add_verbose_id(VERBOSE_MID);
6897c478bd9Sstevel@tonic-gate 				break;
6907c478bd9Sstevel@tonic-gate 			case 'V':
6917c478bd9Sstevel@tonic-gate 				/* undocumented for extra verbose levels */
6927c478bd9Sstevel@tonic-gate 				add_verbose_id(optarg);
6937c478bd9Sstevel@tonic-gate 				break;
694c9cc1492SJerry Gilliam 			case 'x':
695c9cc1492SJerry Gilliam 				update_only = 1;
696c9cc1492SJerry Gilliam 				break;
6977c478bd9Sstevel@tonic-gate 			default:
6987c478bd9Sstevel@tonic-gate 				usage();
6997c478bd9Sstevel@tonic-gate 			}
7007c478bd9Sstevel@tonic-gate 		}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 		if (optind < argc) {
7037c478bd9Sstevel@tonic-gate 			usage();
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 
7066532b960SJerry Gilliam 		if (bind == TRUE) {
707a3ab7e85SToomas Soome 			if ((mc.major == -1) || (mc.drvname[0] == '\0')) {
7086532b960SJerry Gilliam 				err_print(MAJOR_AND_B_FLAG);
7096532b960SJerry Gilliam 				devfsadm_exit(1);
7106532b960SJerry Gilliam 				/*NOTREACHED*/
7116532b960SJerry Gilliam 			}
712c9cc1492SJerry Gilliam 			mc.flags = 0;
713c9cc1492SJerry Gilliam 			if (force_flag)
714c9cc1492SJerry Gilliam 				mc.flags |= MOD_UNBIND_OVERRIDE;
715c9cc1492SJerry Gilliam 			if (update_only)
716c9cc1492SJerry Gilliam 				mc.flags |= MOD_ADDMAJBIND_UPDATE;
7177c478bd9Sstevel@tonic-gate 			mc.num_aliases = num_aliases;
7187c478bd9Sstevel@tonic-gate 			mc.ap = a_head;
7196532b960SJerry Gilliam 			retval =  modctl((config == TRUE) ? MODADDMAJBIND :
7206532b960SJerry Gilliam 			    MODREMDRVALIAS, NULL, (caddr_t)&mc);
7217c478bd9Sstevel@tonic-gate 			if (retval < 0) {
7226532b960SJerry Gilliam 				err_print((config == TRUE) ? MODCTL_ADDMAJBIND :
7236532b960SJerry Gilliam 				    MODCTL_REMMAJBIND);
7247c478bd9Sstevel@tonic-gate 			}
7257c478bd9Sstevel@tonic-gate 			devfsadm_exit(retval);
726537714daSvikram 			/*NOTREACHED*/
7277c478bd9Sstevel@tonic-gate 		}
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	} else if ((strcmp(prog, DEVFSADM) == 0) ||
7307c478bd9Sstevel@tonic-gate 	    (strcmp(prog, DEVFSADMD) == 0)) {
7317c478bd9Sstevel@tonic-gate 		char *zonename = NULL;
7327c478bd9Sstevel@tonic-gate 		int init_drvconf = 0;
7337c478bd9Sstevel@tonic-gate 		int init_perm = 0;
7347c478bd9Sstevel@tonic-gate 		int public_mode = 0;
735facf4a8dSllai 		int init_sysavail = 0;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate 		if (strcmp(prog, DEVFSADMD) == 0) {
7387c478bd9Sstevel@tonic-gate 			daemon_mode = TRUE;
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 		devlinktab_file = DEVLINKTAB_FILE;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 		while ((opt = getopt(argc, argv,
744c9cc1492SJerry Gilliam 		    "a:Cc:deIi:l:np:PR:r:sSt:uvV:x:")) != EOF) {
745facf4a8dSllai 			if (opt == 'I' || opt == 'P' || opt == 'S') {
7467c478bd9Sstevel@tonic-gate 				if (public_mode)
7477c478bd9Sstevel@tonic-gate 					usage();
7487c478bd9Sstevel@tonic-gate 			} else {
749facf4a8dSllai 				if (init_perm || init_drvconf || init_sysavail)
7507c478bd9Sstevel@tonic-gate 					usage();
7517c478bd9Sstevel@tonic-gate 				public_mode = 1;
7527c478bd9Sstevel@tonic-gate 			}
7537c478bd9Sstevel@tonic-gate 			switch (opt) {
754facf4a8dSllai 			case 'a':
755facf4a8dSllai 				attr_root = s_strdup(optarg);
756facf4a8dSllai 				break;
7577c478bd9Sstevel@tonic-gate 			case 'C':
7587c478bd9Sstevel@tonic-gate 				cleanup = TRUE;
7597c478bd9Sstevel@tonic-gate 				break;
7607c478bd9Sstevel@tonic-gate 			case 'c':
7617c478bd9Sstevel@tonic-gate 				num_classes++;
7620a653502Swroche 				classes = s_realloc(classes,
7630a653502Swroche 				    num_classes * sizeof (char *));
7647c478bd9Sstevel@tonic-gate 				classes[num_classes - 1] = optarg;
7657c478bd9Sstevel@tonic-gate 				break;
76645916cd2Sjpk 			case 'd':
7677c478bd9Sstevel@tonic-gate 				if (daemon_mode == FALSE) {
76845916cd2Sjpk 					/*
76945916cd2Sjpk 					 * Device allocation to be disabled.
77045916cd2Sjpk 					 */
77145916cd2Sjpk 					devalloc_flag = DA_OFF;
77245916cd2Sjpk 					build_dev = FALSE;
77345916cd2Sjpk 				}
77445916cd2Sjpk 				break;
77545916cd2Sjpk 			case 'e':
77645916cd2Sjpk 				if (daemon_mode == FALSE) {
77745916cd2Sjpk 					/*
77845916cd2Sjpk 					 * Device allocation to be enabled.
77945916cd2Sjpk 					 */
78045916cd2Sjpk 					devalloc_flag = DA_ON;
7817c478bd9Sstevel@tonic-gate 					build_dev = FALSE;
7827c478bd9Sstevel@tonic-gate 				}
7837c478bd9Sstevel@tonic-gate 				break;
7847c478bd9Sstevel@tonic-gate 			case 'I':	/* update kernel driver.conf cache */
7857c478bd9Sstevel@tonic-gate 				if (daemon_mode == TRUE)
7867c478bd9Sstevel@tonic-gate 					usage();
7877c478bd9Sstevel@tonic-gate 				init_drvconf = 1;
7887c478bd9Sstevel@tonic-gate 				break;
7897c478bd9Sstevel@tonic-gate 			case 'i':
7907c478bd9Sstevel@tonic-gate 				single_drv = TRUE;
7917c478bd9Sstevel@tonic-gate 				driver = s_strdup(optarg);
7927c478bd9Sstevel@tonic-gate 				break;
7937c478bd9Sstevel@tonic-gate 			case 'l':
7947c478bd9Sstevel@tonic-gate 				/* specify an alternate module load path */
7957c478bd9Sstevel@tonic-gate 				module_dirs = s_strdup(optarg);
7967c478bd9Sstevel@tonic-gate 				break;
7977c478bd9Sstevel@tonic-gate 			case 'n':
7987c478bd9Sstevel@tonic-gate 				/* prevent driver loading and deferred attach */
7997c478bd9Sstevel@tonic-gate 				load_attach_drv = FALSE;
8007c478bd9Sstevel@tonic-gate 				break;
8017c478bd9Sstevel@tonic-gate 			case 'p':
8027c478bd9Sstevel@tonic-gate 				/* specify alternate path_to_inst file */
8037c478bd9Sstevel@tonic-gate 				inst_file = s_strdup(optarg);
8047c478bd9Sstevel@tonic-gate 				break;
8057c478bd9Sstevel@tonic-gate 			case 'P':
8067c478bd9Sstevel@tonic-gate 				if (daemon_mode == TRUE)
8077c478bd9Sstevel@tonic-gate 					usage();
8087c478bd9Sstevel@tonic-gate 				/* load minor_perm and device_policy */
8097c478bd9Sstevel@tonic-gate 				init_perm = 1;
8107c478bd9Sstevel@tonic-gate 				break;
8117c478bd9Sstevel@tonic-gate 			case 'R':
8127c478bd9Sstevel@tonic-gate 				/*
8137c478bd9Sstevel@tonic-gate 				 * Private flag for suninstall to populate
8147c478bd9Sstevel@tonic-gate 				 * device information on the installed root.
8157c478bd9Sstevel@tonic-gate 				 */
8167c478bd9Sstevel@tonic-gate 				root_dir = s_strdup(optarg);
8177c478bd9Sstevel@tonic-gate 				devfsadm_exit(devfsadm_copy());
818537714daSvikram 				/*NOTREACHED*/
8197c478bd9Sstevel@tonic-gate 				break;
8207c478bd9Sstevel@tonic-gate 			case 'r':
821facf4a8dSllai 				set_root_devices_dev_dir(optarg);
8227c478bd9Sstevel@tonic-gate 				break;
8237c478bd9Sstevel@tonic-gate 			case 's':
8247c478bd9Sstevel@tonic-gate 				/*
8257c478bd9Sstevel@tonic-gate 				 * suppress. don't create/remove links/nodes
8267c478bd9Sstevel@tonic-gate 				 * useful with -v or -V
8277c478bd9Sstevel@tonic-gate 				 */
8287c478bd9Sstevel@tonic-gate 				file_mods = FALSE;
8297c478bd9Sstevel@tonic-gate 				flush_path_to_inst_enable = FALSE;
8307c478bd9Sstevel@tonic-gate 				break;
831facf4a8dSllai 			case 'S':
832facf4a8dSllai 				if (daemon_mode == TRUE)
833facf4a8dSllai 					usage();
834facf4a8dSllai 				init_sysavail = 1;
835facf4a8dSllai 				break;
8367c478bd9Sstevel@tonic-gate 			case 't':
8377c478bd9Sstevel@tonic-gate 				devlinktab_file = optarg;
8387c478bd9Sstevel@tonic-gate 				break;
839c9cc1492SJerry Gilliam 			case 'u':	/* complete configuration after */
840c9cc1492SJerry Gilliam 					/* adding a driver update-only */
841c9cc1492SJerry Gilliam 				if (daemon_mode == TRUE)
842c9cc1492SJerry Gilliam 					usage();
843c9cc1492SJerry Gilliam 				update_all_drivers = TRUE;
844c9cc1492SJerry Gilliam 				break;
8457c478bd9Sstevel@tonic-gate 			case 'v':
8467c478bd9Sstevel@tonic-gate 				/* documented verbose flag */
8477c478bd9Sstevel@tonic-gate 				add_verbose_id(VERBOSE_MID);
8487c478bd9Sstevel@tonic-gate 				break;
8497c478bd9Sstevel@tonic-gate 			case 'V':
8507c478bd9Sstevel@tonic-gate 				/* undocumented: specify verbose lvl */
8517c478bd9Sstevel@tonic-gate 				add_verbose_id(optarg);
8527c478bd9Sstevel@tonic-gate 				break;
8537c478bd9Sstevel@tonic-gate 			case 'x':
8547c478bd9Sstevel@tonic-gate 				/*
8557c478bd9Sstevel@tonic-gate 				 * x is the "private switch" option.  The
8567c478bd9Sstevel@tonic-gate 				 * goal is to not suck up all the other
8577c478bd9Sstevel@tonic-gate 				 * option letters.
8587c478bd9Sstevel@tonic-gate 				 */
8597c478bd9Sstevel@tonic-gate 				if (strcmp(optarg, "update_devlinksdb") == 0) {
8607c478bd9Sstevel@tonic-gate 					update_database = TRUE;
8617c478bd9Sstevel@tonic-gate 				} else if (strcmp(optarg, "no_dev") == 0) {
8627c478bd9Sstevel@tonic-gate 					/* don't build /dev */
8637c478bd9Sstevel@tonic-gate 					build_dev = FALSE;
8647c478bd9Sstevel@tonic-gate 				} else if (strcmp(optarg, "no_devices") == 0) {
8657c478bd9Sstevel@tonic-gate 					/* don't build /devices */
8667c478bd9Sstevel@tonic-gate 					build_devices = FALSE;
8677c478bd9Sstevel@tonic-gate 				} else if (strcmp(optarg, "no_p2i") == 0) {
8687c478bd9Sstevel@tonic-gate 					/* don't flush path_to_inst */
8697c478bd9Sstevel@tonic-gate 					flush_path_to_inst_enable = FALSE;
8707c478bd9Sstevel@tonic-gate 				} else if (strcmp(optarg, "use_dicache") == 0) {
8717c478bd9Sstevel@tonic-gate 					use_snapshot_cache = TRUE;
8727c478bd9Sstevel@tonic-gate 				} else {
8737c478bd9Sstevel@tonic-gate 					usage();
8747c478bd9Sstevel@tonic-gate 				}
8757c478bd9Sstevel@tonic-gate 				break;
8767c478bd9Sstevel@tonic-gate 			default:
8777c478bd9Sstevel@tonic-gate 				usage();
8787c478bd9Sstevel@tonic-gate 				break;
8797c478bd9Sstevel@tonic-gate 			}
8807c478bd9Sstevel@tonic-gate 		}
8817c478bd9Sstevel@tonic-gate 		if (optind < argc) {
8827c478bd9Sstevel@tonic-gate 			usage();
8837c478bd9Sstevel@tonic-gate 		}
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 		/*
8867c478bd9Sstevel@tonic-gate 		 * We're not in zone mode; Check to see if the rootpath
8877c478bd9Sstevel@tonic-gate 		 * collides with any zonepaths.
8887c478bd9Sstevel@tonic-gate 		 */
8897c478bd9Sstevel@tonic-gate 		if (zonename == NULL) {
8907c478bd9Sstevel@tonic-gate 			if (zone_pathcheck(root_dir) != DEVFSADM_SUCCESS)
8917c478bd9Sstevel@tonic-gate 				devfsadm_exit(1);
892537714daSvikram 				/*NOTREACHED*/
8937c478bd9Sstevel@tonic-gate 		}
8947c478bd9Sstevel@tonic-gate 
895facf4a8dSllai 		if (init_drvconf || init_perm || init_sysavail) {
8967c478bd9Sstevel@tonic-gate 			/*
8977c478bd9Sstevel@tonic-gate 			 * Load minor perm before force-loading drivers
8987c478bd9Sstevel@tonic-gate 			 * so the correct permissions are picked up.
8997c478bd9Sstevel@tonic-gate 			 */
900facf4a8dSllai 			if (init_perm) {
901facf4a8dSllai 				check_reconfig_state();
9027c478bd9Sstevel@tonic-gate 				load_dev_acl();
903facf4a8dSllai 			}
9047c478bd9Sstevel@tonic-gate 			if (init_drvconf)
905c9cc1492SJerry Gilliam 				update_drvconf((major_t)-1, 0);
906facf4a8dSllai 			if (init_sysavail)
907facf4a8dSllai 				modctl_sysavail();
9087c478bd9Sstevel@tonic-gate 			devfsadm_exit(0);
909537714daSvikram 			/*NOTREACHED*/
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 	}
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	if (get_linkcompat_opts == TRUE) {
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 		build_devices = FALSE;
9177c478bd9Sstevel@tonic-gate 		load_attach_drv = FALSE;
9187c478bd9Sstevel@tonic-gate 		num_classes++;
9197c478bd9Sstevel@tonic-gate 		classes = s_realloc(classes, num_classes *
9207c478bd9Sstevel@tonic-gate 		    sizeof (char *));
9217c478bd9Sstevel@tonic-gate 		classes[num_classes - 1] = compat_class;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 		while ((opt = getopt(argc, argv, "Cnr:svV:")) != EOF) {
9247c478bd9Sstevel@tonic-gate 			switch (opt) {
9257c478bd9Sstevel@tonic-gate 			case 'C':
9267c478bd9Sstevel@tonic-gate 				cleanup = TRUE;
9277c478bd9Sstevel@tonic-gate 				break;
9287c478bd9Sstevel@tonic-gate 			case 'n':
9297c478bd9Sstevel@tonic-gate 				/* prevent driver loading or deferred attach */
9307c478bd9Sstevel@tonic-gate 				load_attach_drv = FALSE;
9317c478bd9Sstevel@tonic-gate 				break;
9327c478bd9Sstevel@tonic-gate 			case 'r':
933facf4a8dSllai 				set_root_devices_dev_dir(optarg);
9347c478bd9Sstevel@tonic-gate 				if (zone_pathcheck(root_dir) !=
9357c478bd9Sstevel@tonic-gate 				    DEVFSADM_SUCCESS)
9367c478bd9Sstevel@tonic-gate 					devfsadm_exit(1);
937537714daSvikram 					/*NOTREACHED*/
9387c478bd9Sstevel@tonic-gate 				break;
9397c478bd9Sstevel@tonic-gate 			case 's':
9407c478bd9Sstevel@tonic-gate 				/* suppress.  don't create/remove links/nodes */
9417c478bd9Sstevel@tonic-gate 				/* useful with -v or -V */
9427c478bd9Sstevel@tonic-gate 				file_mods = FALSE;
9437c478bd9Sstevel@tonic-gate 				flush_path_to_inst_enable = FALSE;
9447c478bd9Sstevel@tonic-gate 				break;
9457c478bd9Sstevel@tonic-gate 			case 'v':
9467c478bd9Sstevel@tonic-gate 				/* documented verbose flag */
9477c478bd9Sstevel@tonic-gate 				add_verbose_id(VERBOSE_MID);
9487c478bd9Sstevel@tonic-gate 				break;
9497c478bd9Sstevel@tonic-gate 			case 'V':
9507c478bd9Sstevel@tonic-gate 				/* undocumented for extra verbose levels */
9517c478bd9Sstevel@tonic-gate 				add_verbose_id(optarg);
9527c478bd9Sstevel@tonic-gate 				break;
9537c478bd9Sstevel@tonic-gate 			default:
9547c478bd9Sstevel@tonic-gate 				usage();
9557c478bd9Sstevel@tonic-gate 			}
9567c478bd9Sstevel@tonic-gate 		}
9577c478bd9Sstevel@tonic-gate 		if (optind < argc) {
9587c478bd9Sstevel@tonic-gate 			usage();
9597c478bd9Sstevel@tonic-gate 		}
9607c478bd9Sstevel@tonic-gate 	}
961facf4a8dSllai 	set_lock_root();
9627c478bd9Sstevel@tonic-gate }
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate void
usage(void)9657c478bd9Sstevel@tonic-gate usage(void)
9667c478bd9Sstevel@tonic-gate {
9677c478bd9Sstevel@tonic-gate 	if (strcmp(prog, DEVLINKS) == 0) {
9687c478bd9Sstevel@tonic-gate 		err_print(DEVLINKS_USAGE);
9697c478bd9Sstevel@tonic-gate 	} else if (strcmp(prog, DRVCONFIG) == 0) {
9707c478bd9Sstevel@tonic-gate 		err_print(DRVCONFIG_USAGE);
9717c478bd9Sstevel@tonic-gate 	} else if ((strcmp(prog, DEVFSADM) == 0) ||
9720a653502Swroche 	    (strcmp(prog, DEVFSADMD) == 0)) {
9737c478bd9Sstevel@tonic-gate 		err_print(DEVFSADM_USAGE);
9747c478bd9Sstevel@tonic-gate 	} else {
9757c478bd9Sstevel@tonic-gate 		err_print(COMPAT_LINK_USAGE);
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	devfsadm_exit(1);
979537714daSvikram 	/*NOTREACHED*/
9807c478bd9Sstevel@tonic-gate }
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate static void
devi_tree_walk(struct dca_impl * dcip,int flags,char * ev_subclass)9837c478bd9Sstevel@tonic-gate devi_tree_walk(struct dca_impl *dcip, int flags, char *ev_subclass)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate 	char *msg, *name;
9867c478bd9Sstevel@tonic-gate 	struct mlist	mlist = {0};
9877c478bd9Sstevel@tonic-gate 	di_node_t	node;
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	vprint(CHATTY_MID, "devi_tree_walk: root=%s, minor=%s, driver=%s,"
9907c478bd9Sstevel@tonic-gate 	    " error=%d, flags=%u\n", dcip->dci_root,
9917c478bd9Sstevel@tonic-gate 	    dcip->dci_minor ? dcip->dci_minor : "<NULL>",
9927c478bd9Sstevel@tonic-gate 	    dcip->dci_driver ? dcip->dci_driver : "<NULL>", dcip->dci_error,
9937c478bd9Sstevel@tonic-gate 	    dcip->dci_flags);
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	assert(dcip->dci_root);
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	if (dcip->dci_flags & DCA_LOAD_DRV) {
9987c478bd9Sstevel@tonic-gate 		node = di_init_driver(dcip->dci_driver, flags);
9997c478bd9Sstevel@tonic-gate 		msg = DRIVER_FAILURE;
10007c478bd9Sstevel@tonic-gate 		name = dcip->dci_driver;
10017c478bd9Sstevel@tonic-gate 	} else {
10027c478bd9Sstevel@tonic-gate 		node = di_init(dcip->dci_root, flags);
10037c478bd9Sstevel@tonic-gate 		msg = DI_INIT_FAILED;
10047c478bd9Sstevel@tonic-gate