xref: /titanic_53/usr/src/lib/libbsm/common/devalloc.c (revision 7e3e5701c73b753fb9dd17a0cbe0568b4cdda39e)
145916cd2Sjpk /*
245916cd2Sjpk  * CDDL HEADER START
345916cd2Sjpk  *
445916cd2Sjpk  * The contents of this file are subject to the terms of the
545916cd2Sjpk  * Common Development and Distribution License (the "License").
645916cd2Sjpk  * You may not use this file except in compliance with the License.
745916cd2Sjpk  *
845916cd2Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
945916cd2Sjpk  * or http://www.opensolaris.org/os/licensing.
1045916cd2Sjpk  * See the License for the specific language governing permissions
1145916cd2Sjpk  * and limitations under the License.
1245916cd2Sjpk  *
1345916cd2Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
1445916cd2Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1545916cd2Sjpk  * If applicable, add the following below this CDDL HEADER, with the
1645916cd2Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
1745916cd2Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
1845916cd2Sjpk  *
1945916cd2Sjpk  * CDDL HEADER END
2045916cd2Sjpk  */
2145916cd2Sjpk 
2245916cd2Sjpk /*
23*7e3e5701SJan Parcel  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
2445916cd2Sjpk  * Use is subject to license terms.
2545916cd2Sjpk  */
2645916cd2Sjpk 
2745916cd2Sjpk #include <stdlib.h>
2845916cd2Sjpk #include <ctype.h>
2945916cd2Sjpk #include <unistd.h>
3045916cd2Sjpk #include <limits.h>
3145916cd2Sjpk #include <fcntl.h>
3245916cd2Sjpk #include <sys/types.h>
3345916cd2Sjpk #include <sys/stat.h>
3445916cd2Sjpk #include <utime.h>
3545916cd2Sjpk #include <synch.h>
3645916cd2Sjpk #include <strings.h>
3745916cd2Sjpk #include <string.h>
3845916cd2Sjpk #include <libintl.h>
3945916cd2Sjpk #include <errno.h>
4045916cd2Sjpk #include <auth_list.h>
41*7e3e5701SJan Parcel #include <syslog.h>
4245916cd2Sjpk #include <bsm/devices.h>
4345916cd2Sjpk #include <bsm/devalloc.h>
4445916cd2Sjpk 
4545916cd2Sjpk #define	DA_DEFS	"/etc/security/tsol/devalloc_defaults"
4645916cd2Sjpk 
4745916cd2Sjpk extern int _readbufline(char *, int, char *, int, int *);
4845916cd2Sjpk extern char *strtok_r(char *, const char *, char **);
4945916cd2Sjpk extern char *_strtok_escape(char *, char *, char **);
5045916cd2Sjpk extern int getdaon(void);
5145916cd2Sjpk extern int da_matchname(devalloc_t *, char *);
5245916cd2Sjpk extern int da_match(devalloc_t *, da_args *);
5345916cd2Sjpk extern int dmap_matchname(devmap_t *, char *);
5445916cd2Sjpk extern int dm_match(devmap_t *, da_args *);
55*7e3e5701SJan Parcel extern int dmap_matchtype(devmap_t *dmap, char *type);
56*7e3e5701SJan Parcel extern int dmap_matchdev(devmap_t *dmap, char *dev);
57*7e3e5701SJan Parcel extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num);
58*7e3e5701SJan Parcel extern char *dmap_physname(devmap_t *dmap);
5945916cd2Sjpk 
6045916cd2Sjpk /*
6145916cd2Sjpk  * The following structure is for recording old entries to be retained.
6245916cd2Sjpk  * We read the entries from the database into a linked list in memory,
6345916cd2Sjpk  * then turn around and write them out again.
6445916cd2Sjpk  */
6545916cd2Sjpk typedef struct strentry {
6645916cd2Sjpk 	struct strentry	*se_next;
6745916cd2Sjpk 	char		se_str[4096 + 1];
6845916cd2Sjpk } strentry_t;
6945916cd2Sjpk 
7045916cd2Sjpk /*
7145916cd2Sjpk  * da_check_longindevperm -
7245916cd2Sjpk  *	reads /etc/logindevperm and checks if specified device is in the file.
7345916cd2Sjpk  *	returns 1 if specified device found in /etc/logindevperm, else returns 0
7445916cd2Sjpk  */
7545916cd2Sjpk int
7645916cd2Sjpk da_check_logindevperm(char *devname)
7745916cd2Sjpk {
7845916cd2Sjpk 	int		ret = 0;
7945916cd2Sjpk 	int		fd = -1;
8045916cd2Sjpk 	int		nlen, plen, slen, lineno, fsize;
8145916cd2Sjpk 	char		line[MAX_CANON];
8245916cd2Sjpk 	char		*field_delims = " \t\n";
8345916cd2Sjpk 	char		*fbuf = NULL;
8445916cd2Sjpk 	char		*ptr, *device;
8545916cd2Sjpk 	char		*lasts = NULL;
8645916cd2Sjpk 	FILE		*fp;
8745916cd2Sjpk 	struct stat	f_stat;
8845916cd2Sjpk 
8945916cd2Sjpk 	/*
9045916cd2Sjpk 	 * check if /etc/logindevperm exists and get its size
9145916cd2Sjpk 	 */
9245916cd2Sjpk 	if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1)
9345916cd2Sjpk 		return (0);
9445916cd2Sjpk 	if (fstat(fd, &f_stat) != 0) {
9545916cd2Sjpk 		(void) close(fd);
9645916cd2Sjpk 		return (0);
9745916cd2Sjpk 	}
9845916cd2Sjpk 	fsize = f_stat.st_size;
9945916cd2Sjpk 	if ((fbuf = (char *)malloc(fsize)) == NULL) {
10045916cd2Sjpk 		(void) close(fd);
10145916cd2Sjpk 		return (0);
10245916cd2Sjpk 	}
103004388ebScasper 	if ((fp = fdopen(fd, "rF")) == NULL) {
10445916cd2Sjpk 		free(fbuf);
10545916cd2Sjpk 		(void) close(fd);
10645916cd2Sjpk 		return (0);
10745916cd2Sjpk 	}
10845916cd2Sjpk 
10945916cd2Sjpk 	/*
11045916cd2Sjpk 	 * read and parse /etc/logindevperm
11145916cd2Sjpk 	 */
11245916cd2Sjpk 	plen = nlen = lineno = 0;
11345916cd2Sjpk 	while (fgets(line, MAX_CANON, fp) != NULL) {
11445916cd2Sjpk 		lineno++;
11545916cd2Sjpk 		if ((ptr = strchr(line, '#')) != NULL)
11645916cd2Sjpk 			*ptr = '\0';	/* handle comments */
11745916cd2Sjpk 		if (strtok_r(line, field_delims, &lasts) == NULL)
11845916cd2Sjpk 			continue;	/* ignore blank lines */
11945916cd2Sjpk 		if (strtok_r(NULL, field_delims, &lasts) == NULL)
12045916cd2Sjpk 			/* invalid entry */
12145916cd2Sjpk 			continue;
12245916cd2Sjpk 		if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL)
12345916cd2Sjpk 			/* empty device list */
12445916cd2Sjpk 			continue;
12545916cd2Sjpk 		nlen = strlen(ptr) + 1;		/* +1 terminator */
12645916cd2Sjpk 		nlen += (plen + 1);
12745916cd2Sjpk 		if (plen == 0)
12845916cd2Sjpk 			slen = snprintf(fbuf, nlen, "%s", ptr);
12945916cd2Sjpk 		else
13045916cd2Sjpk 			slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr);
13145916cd2Sjpk 		if (slen >= fsize) {
13245916cd2Sjpk 			fbuf[0] = '\0';
13345916cd2Sjpk 			(void) fclose(fp);
13445916cd2Sjpk 			return (slen);
13545916cd2Sjpk 		}
13645916cd2Sjpk 		plen += slen;
13745916cd2Sjpk 	}
13845916cd2Sjpk 	(void) fclose(fp);
13945916cd2Sjpk 
14045916cd2Sjpk 	/*
14145916cd2Sjpk 	 * check if devname exists in /etc/logindevperm
14245916cd2Sjpk 	 */
14345916cd2Sjpk 	device = strtok_r(fbuf, ":", &lasts);
14445916cd2Sjpk 	while (device != NULL) {
14545916cd2Sjpk 		/*
14645916cd2Sjpk 		 * device and devname may be one of these types -
14745916cd2Sjpk 		 *    /dev/xx
14845916cd2Sjpk 		 *    /dev/xx*
14945916cd2Sjpk 		 *    /dev/dir/xx
15045916cd2Sjpk 		 *    /dev/dir/xx*
15145916cd2Sjpk 		 *    /dev/dir/"*"
15245916cd2Sjpk 		 */
15345916cd2Sjpk 		if (strcmp(device, devname) == 0) {
15445916cd2Sjpk 			/* /dev/xx, /dev/dir/xx */
15545916cd2Sjpk 			free(fbuf);
15645916cd2Sjpk 			return (1);
15745916cd2Sjpk 		}
15845916cd2Sjpk 		if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) {
15945916cd2Sjpk 			/* all wildcard types */
16045916cd2Sjpk 			*ptr = '\0';
16145916cd2Sjpk 			if (strncmp(device, devname, strlen(device)) == 0) {
16245916cd2Sjpk 				free(fbuf);
16345916cd2Sjpk 				return (1);
16445916cd2Sjpk 			}
16545916cd2Sjpk 		}
16645916cd2Sjpk 		device = strtok_r(NULL, ":", &lasts);
16745916cd2Sjpk 	}
16845916cd2Sjpk 
16945916cd2Sjpk 	return (ret);
17045916cd2Sjpk }
17145916cd2Sjpk 
17245916cd2Sjpk /*
17345916cd2Sjpk  * _da_read_file -
17445916cd2Sjpk  *	establishes readers/writer lock on fname; reads in the file if its
17545916cd2Sjpk  *	contents changed since the last time we read it.
17645916cd2Sjpk  *	returns size of buffer read, or -1 on failure.
17745916cd2Sjpk  */
17845916cd2Sjpk int
17945916cd2Sjpk _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock,
18045916cd2Sjpk     int flag)
18145916cd2Sjpk {
18245916cd2Sjpk 	int		fd = -1;
18345916cd2Sjpk 	int		fsize = 0;
18445916cd2Sjpk 	time_t		newtime;
18545916cd2Sjpk 	struct stat	f_stat;
18645916cd2Sjpk 
18745916cd2Sjpk 	if (flag & DA_FORCE)
18845916cd2Sjpk 		*ftime = 0;
18945916cd2Sjpk 
19045916cd2Sjpk 	/* check the size and the time stamp on the file */
19145916cd2Sjpk 	if (rw_rdlock(flock) != 0)
19245916cd2Sjpk 		return (-1);
19345916cd2Sjpk 	if (stat(fname, &f_stat) != 0) {
19445916cd2Sjpk 		(void) rw_unlock(flock);
19545916cd2Sjpk 		return (-1);
19645916cd2Sjpk 	}
19745916cd2Sjpk 	fsize = f_stat.st_size;
19845916cd2Sjpk 	newtime = f_stat.st_mtime;
19945916cd2Sjpk 	(void) rw_unlock(flock);
20045916cd2Sjpk 
20145916cd2Sjpk 	while (newtime > *ftime) {
20245916cd2Sjpk 		/*
20345916cd2Sjpk 		 * file has been modified since we last read it; or this
20445916cd2Sjpk 		 * is a forced read.
20545916cd2Sjpk 		 * read file into the buffer with rw lock.
20645916cd2Sjpk 		 */
20745916cd2Sjpk 		if (rw_wrlock(flock) != 0)
20845916cd2Sjpk 			return (-1);
209004388ebScasper 		if ((fd = open(fname, O_RDONLY)) == -1) {
21045916cd2Sjpk 			(void) rw_unlock(flock);
21145916cd2Sjpk 			return (-1);
21245916cd2Sjpk 		}
21345916cd2Sjpk 		if (*fbuf != NULL) {
21445916cd2Sjpk 			free(*fbuf);
21545916cd2Sjpk 			*fbuf = NULL;
21645916cd2Sjpk 		}
21745916cd2Sjpk 		if ((*fbuf = malloc(fsize)) == NULL) {
21845916cd2Sjpk 			(void) rw_unlock(flock);
21945916cd2Sjpk 			(void) close(fd);
22045916cd2Sjpk 			return (-1);
22145916cd2Sjpk 		}
22245916cd2Sjpk 		if (read(fd, *fbuf, fsize) < fsize) {
22345916cd2Sjpk 			free(*fbuf);
22445916cd2Sjpk 			(void) rw_unlock(flock);
22545916cd2Sjpk 			(void) close(fd);
22645916cd2Sjpk 			return (-1);
22745916cd2Sjpk 		}
22845916cd2Sjpk 		(void) rw_unlock(flock);
22945916cd2Sjpk 		/*
23045916cd2Sjpk 		 * verify that the file did not change just after we read it.
23145916cd2Sjpk 		 */
23245916cd2Sjpk 		if (rw_rdlock(flock) != 0) {
23345916cd2Sjpk 			free(*fbuf);
23445916cd2Sjpk 			(void) close(fd);
23545916cd2Sjpk 			return (-1);
23645916cd2Sjpk 		}
23745916cd2Sjpk 		if (stat(fname, &f_stat) != 0) {
23845916cd2Sjpk 			free(*fbuf);
23945916cd2Sjpk 			(void) rw_unlock(flock);
24045916cd2Sjpk 			(void) close(fd);
24145916cd2Sjpk 			return (-1);
24245916cd2Sjpk 		}
24345916cd2Sjpk 		fsize = f_stat.st_size;
24445916cd2Sjpk 		newtime = f_stat.st_mtime;
24545916cd2Sjpk 		(void) rw_unlock(flock);
24645916cd2Sjpk 		(void) close(fd);
24745916cd2Sjpk 		*ftime = newtime;
24845916cd2Sjpk 	}
24945916cd2Sjpk 
25045916cd2Sjpk 	return (fsize);
25145916cd2Sjpk }
25245916cd2Sjpk 
25345916cd2Sjpk /*
25445916cd2Sjpk  * _update_zonename -
25545916cd2Sjpk  *	add/remove current zone's name to the given devalloc_t.
25645916cd2Sjpk  */
25745916cd2Sjpk void
25845916cd2Sjpk _update_zonename(da_args *dargs, devalloc_t *dap)
25945916cd2Sjpk {
26045916cd2Sjpk 	int		i, j;
26145916cd2Sjpk 	int		oldsize, newsize;
26245916cd2Sjpk 	int		has_zonename = 0;
26345916cd2Sjpk 	char		*zonename;
26445916cd2Sjpk 	kva_t		*newkva, *oldkva;
26545916cd2Sjpk 	kv_t		*newdata, *olddata;
26645916cd2Sjpk 	devinfo_t	*devinfo;
26745916cd2Sjpk 
26845916cd2Sjpk 	devinfo = dargs->devinfo;
26945916cd2Sjpk 	oldkva = dap->da_devopts;
27045916cd2Sjpk 	if (oldkva == NULL) {
27145916cd2Sjpk 		if (dargs->optflag & DA_REMOVE_ZONE)
27245916cd2Sjpk 			return;
27345916cd2Sjpk 		if (dargs->optflag & DA_ADD_ZONE) {
27445916cd2Sjpk 			newkva = _str2kva(devinfo->devopts, KV_ASSIGN,
27545916cd2Sjpk 			    KV_TOKEN_DELIMIT);
27645916cd2Sjpk 			if (newkva != NULL)
27745916cd2Sjpk 				dap->da_devopts = newkva;
27845916cd2Sjpk 			return;
27945916cd2Sjpk 		}
28045916cd2Sjpk 	}
28145916cd2Sjpk 	newsize = oldsize = oldkva->length;
28245916cd2Sjpk 	if (kva_match(oldkva, DAOPT_ZONE))
28345916cd2Sjpk 		has_zonename = 1;
28445916cd2Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
28545916cd2Sjpk 		if ((zonename = index(devinfo->devopts, '=')) == NULL)
28645916cd2Sjpk 			return;
28745916cd2Sjpk 		zonename++;
28845916cd2Sjpk 		if (has_zonename) {
28945916cd2Sjpk 			(void) _insert2kva(oldkva, DAOPT_ZONE, zonename);
29045916cd2Sjpk 			return;
29145916cd2Sjpk 		}
29245916cd2Sjpk 		newsize += 1;
29345916cd2Sjpk 	} else if (dargs->optflag & DA_REMOVE_ZONE) {
29445916cd2Sjpk 		if (has_zonename) {
29545916cd2Sjpk 			newsize -= 1;
29645916cd2Sjpk 			if (newsize == 0) {
29745916cd2Sjpk 				/*
29845916cd2Sjpk 				 * If zone name was the only key/value pair,
29945916cd2Sjpk 				 * put 'reserved' in the empty slot.
30045916cd2Sjpk 				 */
30145916cd2Sjpk 				_kva_free(oldkva);
30245916cd2Sjpk 				dap->da_devopts = NULL;
30345916cd2Sjpk 				return;
30445916cd2Sjpk 			}
30545916cd2Sjpk 		} else {
30645916cd2Sjpk 			return;
30745916cd2Sjpk 		}
30845916cd2Sjpk 	}
30945916cd2Sjpk 	newkva = _new_kva(newsize);
31045916cd2Sjpk 	newkva->length = 0;
31145916cd2Sjpk 	newdata = newkva->data;
31245916cd2Sjpk 	olddata = oldkva->data;
31345916cd2Sjpk 	for (i = 0, j = 0; i < oldsize; i++) {
31445916cd2Sjpk 		if ((dargs->optflag & DA_REMOVE_ZONE) &&
31545916cd2Sjpk 		    (strcmp(olddata[i].key, DAOPT_ZONE) == 0))
31645916cd2Sjpk 			continue;
31745916cd2Sjpk 		newdata[j].key = strdup(olddata[i].key);
31845916cd2Sjpk 		newdata[j].value = strdup(olddata[i].value);
31945916cd2Sjpk 		newkva->length++;
32045916cd2Sjpk 		j++;
32145916cd2Sjpk 	}
32245916cd2Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
32345916cd2Sjpk 		newdata[j].key = strdup(DAOPT_ZONE);
32445916cd2Sjpk 		newdata[j].value = strdup(zonename);
32545916cd2Sjpk 		newkva->length++;
32645916cd2Sjpk 	}
32745916cd2Sjpk 	_kva_free(oldkva);
32845916cd2Sjpk 	dap->da_devopts = newkva;
32945916cd2Sjpk }
33045916cd2Sjpk 
33145916cd2Sjpk /*
33245916cd2Sjpk  * _dmap2str -
33345916cd2Sjpk  *	converts a device_map entry into a printable string
33445916cd2Sjpk  *	returns 0 on success, -1 on error.
33545916cd2Sjpk  */
33645916cd2Sjpk /*ARGSUSED*/
33745916cd2Sjpk static int
338*7e3e5701SJan Parcel _dmap2str(devmap_t *dmp, char *buf, int size, const char *sep)
33945916cd2Sjpk {
34045916cd2Sjpk 	int	length;
34145916cd2Sjpk 
34245916cd2Sjpk 	length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep);
34345916cd2Sjpk 	if (length >= size)
34445916cd2Sjpk 		return (-1);
34545916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
34645916cd2Sjpk 	    dmp->dmap_devtype, sep);
34745916cd2Sjpk 	if (length >= size)
34845916cd2Sjpk 		return (-1);
34945916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
35045916cd2Sjpk 	    dmp->dmap_devlist);
35145916cd2Sjpk 	if (length >= size)
35245916cd2Sjpk 		return (-1);
35345916cd2Sjpk 	return (0);
35445916cd2Sjpk }
35545916cd2Sjpk 
35645916cd2Sjpk /*
35745916cd2Sjpk  * _dmap2strentry -
35845916cd2Sjpk  *	calls dmap2str to break given devmap_t into printable entry.
35945916cd2Sjpk  *	returns pointer to decoded entry, NULL on error.
36045916cd2Sjpk  */
36145916cd2Sjpk static strentry_t *
362*7e3e5701SJan Parcel _dmap2strentry(devmap_t *devmapp)
36345916cd2Sjpk {
36445916cd2Sjpk 	strentry_t	*sep;
36545916cd2Sjpk 
36645916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
36745916cd2Sjpk 		return (NULL);
368*7e3e5701SJan Parcel 	if (_dmap2str(devmapp, sep->se_str, sizeof (sep->se_str),
36945916cd2Sjpk 	    KV_TOKEN_DELIMIT"\\\n\t") != 0) {
37045916cd2Sjpk 		free(sep);
37145916cd2Sjpk 		return (NULL);
37245916cd2Sjpk 	}
37345916cd2Sjpk 	return (sep);
37445916cd2Sjpk }
37545916cd2Sjpk 
37645916cd2Sjpk /*
37745916cd2Sjpk  * fix_optstr -
37845916cd2Sjpk  * 	removes trailing ':' from buf.
37945916cd2Sjpk  */
38045916cd2Sjpk void
38145916cd2Sjpk fix_optstr(char *buf)
38245916cd2Sjpk {
38345916cd2Sjpk 	char	*p = NULL;
38445916cd2Sjpk 
38545916cd2Sjpk 	if (p = rindex(buf, ':'))
38645916cd2Sjpk 		*p = ';';
38745916cd2Sjpk }
38845916cd2Sjpk 
38945916cd2Sjpk /*
39045916cd2Sjpk  * _da2str -
39145916cd2Sjpk  *	converts a device_allocate entry into a printable string
39245916cd2Sjpk  *	returns 0 on success, -1 on error.
39345916cd2Sjpk  */
39445916cd2Sjpk static int
39545916cd2Sjpk _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep,
39645916cd2Sjpk     const char *osep)
39745916cd2Sjpk {
39845916cd2Sjpk 	int	length;
39945916cd2Sjpk 	int	matching_entry = 0;
40045916cd2Sjpk 	char	**dnames;
40145916cd2Sjpk 
40245916cd2Sjpk 	if (dargs->optflag & DA_UPDATE &&
40345916cd2Sjpk 	    (dargs->optflag & DA_ADD_ZONE ||
40445916cd2Sjpk 	    dargs->optflag & DA_REMOVE_ZONE) &&
40545916cd2Sjpk 	    dargs->devnames) {
40645916cd2Sjpk 		for (dnames = dargs->devnames; *dnames != NULL; dnames++) {
40745916cd2Sjpk 			if (da_matchname(dap, *dnames)) {
40845916cd2Sjpk 				matching_entry = 1;
40945916cd2Sjpk 				break;
41045916cd2Sjpk 			}
41145916cd2Sjpk 		}
41245916cd2Sjpk 	}
41345916cd2Sjpk 	length = snprintf(buf, size, "%s%s", dap->da_devname, sep);
41445916cd2Sjpk 	if (length >= size)
41545916cd2Sjpk 		return (-1);
41645916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
41745916cd2Sjpk 	    dap->da_devtype, sep);
41845916cd2Sjpk 	if (length >= size)
41945916cd2Sjpk 		return (-1);
42045916cd2Sjpk 	if (matching_entry)
42145916cd2Sjpk 		_update_zonename(dargs, dap);
42245916cd2Sjpk 	if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) &&
42345916cd2Sjpk 	    (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) {
42445916cd2Sjpk 		length += snprintf(buf + length, size - length, "%s%s",
42545916cd2Sjpk 		    DA_RESERVED, sep);
42645916cd2Sjpk 	} else {
42745916cd2Sjpk 		if (_kva2str(dap->da_devopts, buf + length, size - length,
42845916cd2Sjpk 		    KV_ASSIGN, (char *)osep) != 0)
42945916cd2Sjpk 			return (-1);
43045916cd2Sjpk 		length = strlen(buf);
43145916cd2Sjpk 	}
43245916cd2Sjpk 	if (dap->da_devopts)
43345916cd2Sjpk 		fix_optstr(buf);
43445916cd2Sjpk 	if (length >= size)
43545916cd2Sjpk 		return (-1);
43645916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
43745916cd2Sjpk 	    DA_RESERVED, sep);
43845916cd2Sjpk 	if (length >= size)
43945916cd2Sjpk 		return (-1);
44045916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
44145916cd2Sjpk 	    dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep);
44245916cd2Sjpk 	if (length >= size)
44345916cd2Sjpk 		return (-1);
44445916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
44545916cd2Sjpk 	    dap->da_devexec ? dap->da_devexec : "");
44645916cd2Sjpk 	if (length >= size)
44745916cd2Sjpk 		return (-1);
44845916cd2Sjpk 
44945916cd2Sjpk 	return (0);
45045916cd2Sjpk }
45145916cd2Sjpk 
45245916cd2Sjpk /*
45345916cd2Sjpk  * _da2strentry -
45445916cd2Sjpk  *	calls da2str to break given devalloc_t into printable entry.
45545916cd2Sjpk  *	returns pointer to decoded entry, NULL on error.
45645916cd2Sjpk  */
45745916cd2Sjpk static strentry_t *
45845916cd2Sjpk _da2strentry(da_args *dargs, devalloc_t *dap)
45945916cd2Sjpk {
46045916cd2Sjpk 	strentry_t	*sep;
46145916cd2Sjpk 
46245916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
46345916cd2Sjpk 		return (NULL);
46445916cd2Sjpk 	if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str),
46545916cd2Sjpk 	    KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) {
46645916cd2Sjpk 		free(sep);
46745916cd2Sjpk 		return (NULL);
46845916cd2Sjpk 	}
46945916cd2Sjpk 	return (sep);
47045916cd2Sjpk }
47145916cd2Sjpk 
47245916cd2Sjpk /*
47345916cd2Sjpk  * _def2str
47445916cd2Sjpk  *	converts da_defs_t into a printable string.
47545916cd2Sjpk  *	returns 0 on success, -1 on error.
47645916cd2Sjpk  */
47745916cd2Sjpk static int
47845916cd2Sjpk _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep)
47945916cd2Sjpk {
48045916cd2Sjpk 	int length;
48145916cd2Sjpk 
48245916cd2Sjpk 	length = snprintf(buf, size, "%s%s", da_defs->devtype, sep);
48345916cd2Sjpk 	if (length >= size)
48445916cd2Sjpk 		return (-1);
48545916cd2Sjpk 	if (da_defs->devopts) {
48645916cd2Sjpk 		if (_kva2str(da_defs->devopts, buf + length, size - length,
48745916cd2Sjpk 		    KV_ASSIGN, KV_DELIMITER) != 0)
48845916cd2Sjpk 			return (-1);
48945916cd2Sjpk 		length = strlen(buf);
49045916cd2Sjpk 	}
49145916cd2Sjpk 	if (length >= size)
49245916cd2Sjpk 		return (-1);
49345916cd2Sjpk 
49445916cd2Sjpk 	return (0);
49545916cd2Sjpk }
49645916cd2Sjpk 
49745916cd2Sjpk /*
49845916cd2Sjpk  * _def2strentry
49945916cd2Sjpk  *	calls _def2str to break given da_defs_t into printable entry.
50045916cd2Sjpk  *	returns pointer decoded entry, NULL on error.
50145916cd2Sjpk  */
50245916cd2Sjpk static strentry_t *
50345916cd2Sjpk _def2strentry(da_defs_t *da_defs)
50445916cd2Sjpk {
50545916cd2Sjpk 	strentry_t	*sep;
50645916cd2Sjpk 
50745916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
50845916cd2Sjpk 		return (NULL);
50945916cd2Sjpk 	if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str),
51045916cd2Sjpk 	    KV_TOKEN_DELIMIT) != 0) {
51145916cd2Sjpk 		free(sep);
51245916cd2Sjpk 		return (NULL);
51345916cd2Sjpk 	}
51445916cd2Sjpk 
51545916cd2Sjpk 	return (sep);
51645916cd2Sjpk }
51745916cd2Sjpk 
51845916cd2Sjpk /*
51945916cd2Sjpk  * _build_defattrs
52045916cd2Sjpk  *	cycles through all defattr entries, stores them in memory. removes
52145916cd2Sjpk  *	entries with the given search_key (device type).
52245916cd2Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
52345916cd2Sjpk  *	error.
52445916cd2Sjpk  */
52545916cd2Sjpk static int
52645916cd2Sjpk _build_defattrs(da_args *dargs, strentry_t **head_defent)
52745916cd2Sjpk {
52845916cd2Sjpk 	int		rc = 0;
52945916cd2Sjpk 	da_defs_t	*da_defs;
53045916cd2Sjpk 	strentry_t	*tail_str, *tmp_str;
53145916cd2Sjpk 
53245916cd2Sjpk 	setdadefent();
53345916cd2Sjpk 	while ((da_defs = getdadefent()) != NULL) {
53445916cd2Sjpk 		rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype));
53545916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
53645916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
53745916cd2Sjpk 			/*
53845916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
53945916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
54045916cd2Sjpk 			 */
54145916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
54245916cd2Sjpk 			rc = 0;
54345916cd2Sjpk 		}
54445916cd2Sjpk 		if (rc == 0) {
54545916cd2Sjpk 			tmp_str = _def2strentry(da_defs);
54645916cd2Sjpk 			if (tmp_str == NULL) {
54745916cd2Sjpk 				freedadefent(da_defs);
54845916cd2Sjpk 				enddadefent();
54945916cd2Sjpk 				return (2);
55045916cd2Sjpk 			}
55145916cd2Sjpk 			/* retaining defattr entry: tmp_str->se_str */
55245916cd2Sjpk 			tmp_str->se_next = NULL;
55345916cd2Sjpk 			if (*head_defent == NULL) {
55445916cd2Sjpk 				*head_defent = tail_str = tmp_str;
55545916cd2Sjpk 			} else {
55645916cd2Sjpk 				tail_str->se_next = tmp_str;
55745916cd2Sjpk 				tail_str = tmp_str;
55845916cd2Sjpk 			}
55945916cd2Sjpk 		}
56045916cd2Sjpk 		freedadefent(da_defs);
56145916cd2Sjpk 	}
56245916cd2Sjpk 	enddadefent();
56345916cd2Sjpk 
56445916cd2Sjpk 	return (rc);
56545916cd2Sjpk }
56645916cd2Sjpk 
56745916cd2Sjpk /*
568*7e3e5701SJan Parcel  * _rebuild_lists -
569*7e3e5701SJan Parcel  *
570*7e3e5701SJan Parcel  *      If dargs->optflag & DA_EVENT, does not assume the dargs list is
571*7e3e5701SJan Parcel  *      complete or completely believable, since devfsadm caches
572*7e3e5701SJan Parcel  *      ONLY what it has been exposed to via syseventd.
573*7e3e5701SJan Parcel  *
574*7e3e5701SJan Parcel  *	Cycles through all the entries in the /etc files, stores them
575*7e3e5701SJan Parcel  *      in memory, takes note of device->dname numbers (i.e. rmdisk0,
576*7e3e5701SJan Parcel  *      rmdisk12)
577*7e3e5701SJan Parcel  *
578*7e3e5701SJan Parcel  *      Cycles through again, adds dargs entry
579*7e3e5701SJan Parcel  *	with the name tname%d (lowest unused number for the device type)
580*7e3e5701SJan Parcel  *	to the list of things for the caller to write out to a file,
581*7e3e5701SJan Parcel  *      IFF it is a new entry.
582*7e3e5701SJan Parcel  *
583*7e3e5701SJan Parcel  *      It is an error for it to already be there.
584*7e3e5701SJan Parcel  *
585*7e3e5701SJan Parcel  *	Add:
586*7e3e5701SJan Parcel  *         Returns 0 if successful and 2 on error.
587*7e3e5701SJan Parcel  *      Remove:
588*7e3e5701SJan Parcel  *         Returns 0 if not found, 1 if found,  2 on error.
589*7e3e5701SJan Parcel  */
590*7e3e5701SJan Parcel static int
591*7e3e5701SJan Parcel _rebuild_lists(da_args *dargs, strentry_t **head_devallocp,
592*7e3e5701SJan Parcel     strentry_t **head_devmapp)
593*7e3e5701SJan Parcel {
594*7e3e5701SJan Parcel 	int		rc = 0;
595*7e3e5701SJan Parcel 	devalloc_t	*devallocp;
596*7e3e5701SJan Parcel 	devmap_t	*devmapp;
597*7e3e5701SJan Parcel 	strentry_t	*tail_str;
598*7e3e5701SJan Parcel 	strentry_t	*tmp_str;
599*7e3e5701SJan Parcel 	uint64_t	tmp_bitmap = 0;
600*7e3e5701SJan Parcel 	int		tmp = 0;
601*7e3e5701SJan Parcel 	char		new_devname[DA_MAXNAME + 1];
602*7e3e5701SJan Parcel 	char		errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80];
603*7e3e5701SJan Parcel 	char		*realname;
604*7e3e5701SJan Parcel 	int		suffix = DA_MAX_DEVNO + 1;
605*7e3e5701SJan Parcel 	int		found = 0;
606*7e3e5701SJan Parcel 
607*7e3e5701SJan Parcel 	if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY))
608*7e3e5701SJan Parcel 		return (2);
609*7e3e5701SJan Parcel 
610*7e3e5701SJan Parcel 	if (dargs->optflag & DA_FORCE)
611*7e3e5701SJan Parcel 		return (2);
612*7e3e5701SJan Parcel 
613*7e3e5701SJan Parcel 	/* read both files, maps first so we can compare actual devices */
614*7e3e5701SJan Parcel 
615*7e3e5701SJan Parcel 	/* build device_maps */
616*7e3e5701SJan Parcel 	setdmapent();
617*7e3e5701SJan Parcel 	while ((devmapp = getdmapent()) != NULL) {
618*7e3e5701SJan Parcel 		if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype))
619*7e3e5701SJan Parcel 		    == 1) {
620*7e3e5701SJan Parcel 			if (dargs->optflag & DA_REMOVE) {
621*7e3e5701SJan Parcel 				if ((devmapp->dmap_devarray == NULL) ||
622*7e3e5701SJan Parcel 				    (devmapp->dmap_devarray[0] == NULL)) {
623*7e3e5701SJan Parcel 					freedmapent(devmapp);
624*7e3e5701SJan Parcel 					enddmapent();
625*7e3e5701SJan Parcel 					return (2);
626*7e3e5701SJan Parcel 				}
627*7e3e5701SJan Parcel 				realname = dmap_physname(devmapp);
628*7e3e5701SJan Parcel 				if (realname == NULL) {
629*7e3e5701SJan Parcel 					freedmapent(devmapp);
630*7e3e5701SJan Parcel 					enddmapent();
631*7e3e5701SJan Parcel 					return (2);
632*7e3e5701SJan Parcel 				}
633*7e3e5701SJan Parcel 				if (strstr(realname, dargs->devinfo->devlist)
634*7e3e5701SJan Parcel 				    != NULL) {
635*7e3e5701SJan Parcel 					if (dargs->devinfo->devname != NULL)
636*7e3e5701SJan Parcel 						free(dargs->devinfo->devname);
637*7e3e5701SJan Parcel 					dargs->devinfo->devname =
638*7e3e5701SJan Parcel 					    strdup(devmapp->dmap_devname);
639*7e3e5701SJan Parcel 					found = 1;
640*7e3e5701SJan Parcel 					freedmapent(devmapp);
641*7e3e5701SJan Parcel 					continue; /* don't retain */
642*7e3e5701SJan Parcel 				}
643*7e3e5701SJan Parcel 			} else if (dargs->optflag & DA_ADD) {
644*7e3e5701SJan Parcel 				/*
645*7e3e5701SJan Parcel 				 * Need to know which suffixes are in use
646*7e3e5701SJan Parcel 				 */
647*7e3e5701SJan Parcel 				rc = (dmap_exact_dev(devmapp,
648*7e3e5701SJan Parcel 				    dargs->devinfo->devlist, &suffix));
649*7e3e5701SJan Parcel 
650*7e3e5701SJan Parcel 				if (rc == 0) {
651*7e3e5701SJan Parcel 					/*
652*7e3e5701SJan Parcel 					 * Same type, different device.  Record
653*7e3e5701SJan Parcel 					 * device suffix already in use.
654*7e3e5701SJan Parcel 					 */
655*7e3e5701SJan Parcel 					if (suffix > DA_MAX_DEVNO) {
656*7e3e5701SJan Parcel 						freedmapent(devmapp);
657*7e3e5701SJan Parcel 						enddmapent();
658*7e3e5701SJan Parcel 						return (2);
659*7e3e5701SJan Parcel 					}
660*7e3e5701SJan Parcel 					tmp_bitmap |= (uint64_t)(1LL << suffix);
661*7e3e5701SJan Parcel 				} else {
662*7e3e5701SJan Parcel 					/*
663*7e3e5701SJan Parcel 					 * Match on add is an error
664*7e3e5701SJan Parcel 					 * or mapping attempt returned error
665*7e3e5701SJan Parcel 					 */
666*7e3e5701SJan Parcel 					freedmapent(devmapp);
667*7e3e5701SJan Parcel 					enddmapent();
668*7e3e5701SJan Parcel 					return (2);
669*7e3e5701SJan Parcel 				}
670*7e3e5701SJan Parcel 			} else
671*7e3e5701SJan Parcel 				/* add other transaction types as needed */
672*7e3e5701SJan Parcel 				return (2);
673*7e3e5701SJan Parcel 
674*7e3e5701SJan Parcel 		}  /* if same type */
675*7e3e5701SJan Parcel 
676*7e3e5701SJan Parcel 		tmp_str = _dmap2strentry(devmapp);
677*7e3e5701SJan Parcel 		if (tmp_str == NULL) {
678*7e3e5701SJan Parcel 			freedmapent(devmapp);
679*7e3e5701SJan Parcel 			enddmapent();
680*7e3e5701SJan Parcel 			return (2);
681*7e3e5701SJan Parcel 		}
682*7e3e5701SJan Parcel 		/* retaining devmap entry: tmp_str->se_str */
683*7e3e5701SJan Parcel 		tmp_str->se_next = NULL;
684*7e3e5701SJan Parcel 		if (*head_devmapp == NULL) {
685*7e3e5701SJan Parcel 			*head_devmapp = tail_str = tmp_str;
686*7e3e5701SJan Parcel 		} else {
687*7e3e5701SJan Parcel 			tail_str->se_next = tmp_str;
688*7e3e5701SJan Parcel 			tail_str = tmp_str;
689*7e3e5701SJan Parcel 		}
690*7e3e5701SJan Parcel 		freedmapent(devmapp);
691*7e3e5701SJan Parcel 	}
692*7e3e5701SJan Parcel 	enddmapent();
693*7e3e5701SJan Parcel 
694*7e3e5701SJan Parcel 	/*
695*7e3e5701SJan Parcel 	 * No need to rewrite the files if the item to be removed is not
696*7e3e5701SJan Parcel 	 * in the files -- wait for another call on another darg.
697*7e3e5701SJan Parcel 	 */
698*7e3e5701SJan Parcel 	if ((dargs->optflag & DA_REMOVE) && !found)
699*7e3e5701SJan Parcel 		return (0);
700*7e3e5701SJan Parcel 
701*7e3e5701SJan Parcel 
702*7e3e5701SJan Parcel 	if (dargs->optflag & DA_ADD) {
703*7e3e5701SJan Parcel 		/*
704*7e3e5701SJan Parcel 		 * Since we got here from an event, we know the stored
705*7e3e5701SJan Parcel 		 * devname is a useless guess, since the files had not
706*7e3e5701SJan Parcel 		 * been read when the name was chosen, and we don't keep
707*7e3e5701SJan Parcel 		 * them anywhere else that is sufficiently definitive.
708*7e3e5701SJan Parcel 		 */
709*7e3e5701SJan Parcel 
710*7e3e5701SJan Parcel 		for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++)
711*7e3e5701SJan Parcel 			if (!(tmp_bitmap & (1LL << tmp)))
712*7e3e5701SJan Parcel 				break;
713*7e3e5701SJan Parcel 		/* Future: support more than 64 hotplug devices per type? */
714*7e3e5701SJan Parcel 		if (tmp > DA_MAX_DEVNO)
715*7e3e5701SJan Parcel 			return (2);
716*7e3e5701SJan Parcel 
717*7e3e5701SJan Parcel 		(void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u",
718*7e3e5701SJan Parcel 		    dargs->devinfo->devtype, tmp);
719*7e3e5701SJan Parcel 		if (dargs->devinfo->devname != NULL)
720*7e3e5701SJan Parcel 			free(dargs->devinfo->devname);
721*7e3e5701SJan Parcel 		dargs->devinfo->devname = strdup(new_devname);
722*7e3e5701SJan Parcel 	}
723*7e3e5701SJan Parcel 
724*7e3e5701SJan Parcel 	/*
725*7e3e5701SJan Parcel 	 * Now adjust devalloc list to match devmaps
726*7e3e5701SJan Parcel 	 * Note we now have the correct devname for da_match to use.
727*7e3e5701SJan Parcel 	 */
728*7e3e5701SJan Parcel 	setdaent();
729*7e3e5701SJan Parcel 	while ((devallocp = getdaent()) != NULL) {
730*7e3e5701SJan Parcel 		rc = da_match(devallocp, dargs);
731*7e3e5701SJan Parcel 		if (rc == 1) {
732*7e3e5701SJan Parcel 			if (dargs->optflag & DA_ADD) {
733*7e3e5701SJan Parcel 				/* logging is on if DA_EVENT is set */
734*7e3e5701SJan Parcel 				if (dargs->optflag & DA_EVENT) {
735*7e3e5701SJan Parcel 					(void) snprintf(errmsg, sizeof (errmsg),
736*7e3e5701SJan Parcel 					    "%s and %s out of sync,"
737*7e3e5701SJan Parcel 					    "%s only in %s.",
738*7e3e5701SJan Parcel 					    DEVALLOC, DEVMAP,
739*7e3e5701SJan Parcel 					    devallocp->da_devname, DEVALLOC);
740*7e3e5701SJan Parcel 					syslog(LOG_ERR, "%s", errmsg);
741*7e3e5701SJan Parcel 				}
742*7e3e5701SJan Parcel 				freedaent(devallocp);
743*7e3e5701SJan Parcel 				enddaent();
744*7e3e5701SJan Parcel 				return (2);
745*7e3e5701SJan Parcel 			} else if (dargs->optflag & DA_REMOVE) {
746*7e3e5701SJan Parcel 				/* make list w/o this entry */
747*7e3e5701SJan Parcel 				freedaent(devallocp);
748*7e3e5701SJan Parcel 				continue;
749*7e3e5701SJan Parcel 			}
750*7e3e5701SJan Parcel 		}
751*7e3e5701SJan Parcel 		tmp_str = _da2strentry(dargs, devallocp);
752*7e3e5701SJan Parcel 		if (tmp_str == NULL) {
753*7e3e5701SJan Parcel 			freedaent(devallocp);
754*7e3e5701SJan Parcel 			enddaent();
755*7e3e5701SJan Parcel 			return (2);
756*7e3e5701SJan Parcel 		}
757*7e3e5701SJan Parcel 		/* retaining devalloc entry: tmp_str->se_str */
758*7e3e5701SJan Parcel 		tmp_str->se_next = NULL;
759*7e3e5701SJan Parcel 		if (*head_devallocp == NULL) {
760*7e3e5701SJan Parcel 			*head_devallocp = tail_str = tmp_str;
761*7e3e5701SJan Parcel 		} else {
762*7e3e5701SJan Parcel 			tail_str->se_next = tmp_str;
763*7e3e5701SJan Parcel 			tail_str = tmp_str;
764*7e3e5701SJan Parcel 		}
765*7e3e5701SJan Parcel 		freedaent(devallocp);
766*7e3e5701SJan Parcel 	}
767*7e3e5701SJan Parcel 	enddaent();
768*7e3e5701SJan Parcel 
769*7e3e5701SJan Parcel 	/* the caller needs to know if a remove needs to rewrite files */
770*7e3e5701SJan Parcel 	if (dargs->optflag & DA_REMOVE)
771*7e3e5701SJan Parcel 		return (1);  /* 0 and 2 cases returned earlier */
772*7e3e5701SJan Parcel 
773*7e3e5701SJan Parcel 	return (0);  /* Successful DA_ADD */
774*7e3e5701SJan Parcel }
775*7e3e5701SJan Parcel /*
77645916cd2Sjpk  * _build_lists -
777*7e3e5701SJan Parcel  *	Cycles through all the entries, stores them in memory. removes entries
77845916cd2Sjpk  *	with the given search_key (device name or type).
77945916cd2Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
78045916cd2Sjpk  *	error.
78145916cd2Sjpk  */
78245916cd2Sjpk static int
78345916cd2Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp,
78445916cd2Sjpk     strentry_t **head_devmapp)
78545916cd2Sjpk {
78645916cd2Sjpk 	int		rc = 0;
78745916cd2Sjpk 	devalloc_t	*devallocp;
78845916cd2Sjpk 	devmap_t	*devmapp;
78945916cd2Sjpk 	strentry_t	*tail_str;
79045916cd2Sjpk 	strentry_t	*tmp_str;
79145916cd2Sjpk 
79245916cd2Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
79345916cd2Sjpk 		goto dmap_only;
79445916cd2Sjpk 
79545916cd2Sjpk 	/* build device_allocate */
79645916cd2Sjpk 	setdaent();
79745916cd2Sjpk 	while ((devallocp = getdaent()) != NULL) {
79845916cd2Sjpk 		rc = da_match(devallocp, dargs);
79945916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
80045916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
80145916cd2Sjpk 			/*
80245916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
80345916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
80445916cd2Sjpk 			 */
80545916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
80645916cd2Sjpk 			rc = 0;
80745916cd2Sjpk 		}
80845916cd2Sjpk 		if (rc == 0) {
80945916cd2Sjpk 			tmp_str = _da2strentry(dargs, devallocp);
81045916cd2Sjpk 			if (tmp_str == NULL) {
81145916cd2Sjpk 				freedaent(devallocp);
81245916cd2Sjpk 				enddaent();
81345916cd2Sjpk 				return (2);
81445916cd2Sjpk 			}
81545916cd2Sjpk 			/* retaining devalloc entry: tmp_str->se_str */
81645916cd2Sjpk 			tmp_str->se_next = NULL;
81745916cd2Sjpk 			if (*head_devallocp == NULL) {
81845916cd2Sjpk 				*head_devallocp = tail_str = tmp_str;
81945916cd2Sjpk 			} else {
82045916cd2Sjpk 				tail_str->se_next = tmp_str;
82145916cd2Sjpk 				tail_str = tmp_str;
82245916cd2Sjpk 			}
82345916cd2Sjpk 		}
82445916cd2Sjpk 		freedaent(devallocp);
82545916cd2Sjpk 	}
82645916cd2Sjpk 	enddaent();
82745916cd2Sjpk 
82845916cd2Sjpk dmap_only:
82945916cd2Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
83045916cd2Sjpk 		return (rc);
83145916cd2Sjpk 
83245916cd2Sjpk 	/* build device_maps */
83345916cd2Sjpk 	rc = 0;
83445916cd2Sjpk 	setdmapent();
83545916cd2Sjpk 	while ((devmapp = getdmapent()) != NULL) {
83645916cd2Sjpk 		rc = dm_match(devmapp, dargs);
83745916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
83845916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
83945916cd2Sjpk 			/*
84045916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
84145916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
84245916cd2Sjpk 			 */
84345916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
84445916cd2Sjpk 			rc = 0;
84545916cd2Sjpk 		}
84645916cd2Sjpk 		if (rc == 0) {
847*7e3e5701SJan Parcel 			tmp_str = _dmap2strentry(devmapp);
84845916cd2Sjpk 			if (tmp_str == NULL) {
84945916cd2Sjpk 				freedmapent(devmapp);
85045916cd2Sjpk 				enddmapent();
85145916cd2Sjpk 				return (2);
85245916cd2Sjpk 			}
85345916cd2Sjpk 			/* retaining devmap entry: tmp_str->se_str */
85445916cd2Sjpk 			tmp_str->se_next = NULL;
85545916cd2Sjpk 			if (*head_devmapp == NULL) {
85645916cd2Sjpk 				*head_devmapp = tail_str = tmp_str;
85745916cd2Sjpk 			} else {
85845916cd2Sjpk 				tail_str->se_next = tmp_str;
85945916cd2Sjpk 				tail_str = tmp_str;
86045916cd2Sjpk 			}
86145916cd2Sjpk 		}
86245916cd2Sjpk 		freedmapent(devmapp);
86345916cd2Sjpk 	}
86445916cd2Sjpk 	enddmapent();
86545916cd2Sjpk 
86645916cd2Sjpk 	return (rc);
86745916cd2Sjpk }
86845916cd2Sjpk 
86945916cd2Sjpk /*
87045916cd2Sjpk  * _write_defattrs
87145916cd2Sjpk  *	writes current entries to devalloc_defaults.
87245916cd2Sjpk  */
87345916cd2Sjpk static void
87445916cd2Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent)
87545916cd2Sjpk {
87645916cd2Sjpk 	strentry_t *tmp_str;
87745916cd2Sjpk 
87845916cd2Sjpk 	for (tmp_str = head_defent; tmp_str != NULL;
87945916cd2Sjpk 	    tmp_str = tmp_str->se_next) {
88045916cd2Sjpk 		(void) fputs(tmp_str->se_str, fp);
88145916cd2Sjpk 		(void) fputs("\n", fp);
88245916cd2Sjpk 	}
88345916cd2Sjpk 
88445916cd2Sjpk }
88545916cd2Sjpk 
88645916cd2Sjpk /*
88745916cd2Sjpk  * _write_device_allocate -
88845916cd2Sjpk  *	writes current entries in the list to device_allocate.
889*7e3e5701SJan Parcel  *	frees the strings
89045916cd2Sjpk  */
89145916cd2Sjpk static void
89245916cd2Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
89345916cd2Sjpk {
89445916cd2Sjpk 	int		is_on = -1;
895*7e3e5701SJan Parcel 	strentry_t	*tmp_str, *old_str;
89645916cd2Sjpk 	struct stat	dastat;
89745916cd2Sjpk 
89845916cd2Sjpk 	(void) fseek(dafp, (off_t)0, SEEK_SET);
89945916cd2Sjpk 
90045916cd2Sjpk 	/*
90145916cd2Sjpk 	 * if the devalloc on/off string existed before,
90245916cd2Sjpk 	 * put it back before anything else.
90345916cd2Sjpk 	 * we need to check for the string only if the file
90445916cd2Sjpk 	 * exists.
90545916cd2Sjpk 	 */
90645916cd2Sjpk 	if (stat(odevalloc, &dastat) == 0) {
90745916cd2Sjpk 		is_on = da_is_on();
90845916cd2Sjpk 		if (is_on == 0)
90945916cd2Sjpk 			(void) fputs(DA_OFF_STR, dafp);
91045916cd2Sjpk 		else if (is_on == 1)
91145916cd2Sjpk 			(void) fputs(DA_ON_STR, dafp);
91245916cd2Sjpk 	}
91345916cd2Sjpk 	tmp_str = head_devallocp;
91445916cd2Sjpk 	while (tmp_str) {
91545916cd2Sjpk 		(void) fputs(tmp_str->se_str, dafp);
91645916cd2Sjpk 		(void) fputs("\n", dafp);
917*7e3e5701SJan Parcel 		old_str = tmp_str;
91845916cd2Sjpk 		tmp_str = tmp_str->se_next;
919*7e3e5701SJan Parcel 		free(old_str);
92045916cd2Sjpk 	}
92145916cd2Sjpk }
92245916cd2Sjpk 
92345916cd2Sjpk /*
92445916cd2Sjpk  * _write_device_maps -
92545916cd2Sjpk  *	writes current entries in the list to device_maps.
926*7e3e5701SJan Parcel  *	and frees the strings
92745916cd2Sjpk  */
92845916cd2Sjpk static void
92945916cd2Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
93045916cd2Sjpk {
931*7e3e5701SJan Parcel 	strentry_t	*tmp_str, *old_str;
93245916cd2Sjpk 
93345916cd2Sjpk 	(void) fseek(dmfp, (off_t)0, SEEK_SET);
93445916cd2Sjpk 
93545916cd2Sjpk 	tmp_str = head_devmapp;
93645916cd2Sjpk 	while (tmp_str) {
93745916cd2Sjpk 		(void) fputs(tmp_str->se_str, dmfp);
93845916cd2Sjpk 		(void) fputs("\n", dmfp);
939*7e3e5701SJan Parcel 		old_str = tmp_str;
94045916cd2Sjpk 		tmp_str = tmp_str->se_next;
941*7e3e5701SJan Parcel 		free(old_str);
94245916cd2Sjpk 	}
94345916cd2Sjpk }
94445916cd2Sjpk 
94545916cd2Sjpk /*
94645916cd2Sjpk  * _write_new_defattrs
94745916cd2Sjpk  *	writes the new entry to devalloc_defaults.
94845916cd2Sjpk  *	returns 0 on success, -1 on error.
94945916cd2Sjpk  */
95045916cd2Sjpk static int
95145916cd2Sjpk _write_new_defattrs(FILE *fp, da_args *dargs)
95245916cd2Sjpk {
95345916cd2Sjpk 	int		count;
95445916cd2Sjpk 	char		*tok = NULL, *tokp = NULL;
95545916cd2Sjpk 	char		*lasts;
95645916cd2Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
95745916cd2Sjpk 
95845916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
95945916cd2Sjpk 		return (-1);
96045916cd2Sjpk 	if (!devinfo->devopts)
96145916cd2Sjpk 		return (0);
96245916cd2Sjpk 	(void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
96345916cd2Sjpk 	    KV_TOKEN_DELIMIT);
964*7e3e5701SJan Parcel 	if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) {
96545916cd2Sjpk 		(void) strcpy(tokp, devinfo->devopts);
96645916cd2Sjpk 		if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) {
96745916cd2Sjpk 			(void) fprintf(fp, "%s", tok);
96845916cd2Sjpk 			count = 1;
96945916cd2Sjpk 		}
97045916cd2Sjpk 		while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
97145916cd2Sjpk 			if (count)
97245916cd2Sjpk 				(void) fprintf(fp, "%s", KV_DELIMITER);
97345916cd2Sjpk 			(void) fprintf(fp, "%s", tok);
97445916cd2Sjpk 			count++;
97545916cd2Sjpk 		}
97645916cd2Sjpk 	} else {
97745916cd2Sjpk 		(void) fprintf(fp, "%s", devinfo->devopts);
97845916cd2Sjpk 	}
97945916cd2Sjpk 
98045916cd2Sjpk 	return (0);
98145916cd2Sjpk }
98245916cd2Sjpk 
98345916cd2Sjpk /*
98445916cd2Sjpk  * _write_new_entry -
98545916cd2Sjpk  *	writes the new devalloc_t to device_allocate or the new devmap_t to
98645916cd2Sjpk  *	device_maps.
98745916cd2Sjpk  *	returns 0 on success, -1 on error.
98845916cd2Sjpk  */
98945916cd2Sjpk static int
99045916cd2Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag)
99145916cd2Sjpk {
99245916cd2Sjpk 	int		count;
99345916cd2Sjpk 	char		*tok = NULL, *tokp = NULL;
99445916cd2Sjpk 	char		*lasts;
99545916cd2Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
99645916cd2Sjpk 
99745916cd2Sjpk 	if (flag & DA_MAPS_ONLY)
99845916cd2Sjpk 		goto dmap_only;
99945916cd2Sjpk 
100045916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
100145916cd2Sjpk 		return (-1);
100245916cd2Sjpk 
100345916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
100445916cd2Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
100545916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
100645916cd2Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
100745916cd2Sjpk 	if (devinfo->devopts == NULL) {
100845916cd2Sjpk 		(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
100945916cd2Sjpk 		    KV_DELIMITER);
101045916cd2Sjpk 	} else {
1011*7e3e5701SJan Parcel 		if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1))
1012*7e3e5701SJan Parcel 		    != NULL) {
101345916cd2Sjpk 			(void) strcpy(tokp, devinfo->devopts);
101445916cd2Sjpk 			if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
101545916cd2Sjpk 			    NULL) {
101645916cd2Sjpk 				(void) fprintf(fp, "%s", tok);
101745916cd2Sjpk 				count = 1;
101845916cd2Sjpk 			}
101945916cd2Sjpk 			while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
102045916cd2Sjpk 			    &lasts)) != NULL) {
102145916cd2Sjpk 				if (count)
102245916cd2Sjpk 					(void) fprintf(fp, "%s",
102345916cd2Sjpk 					    KV_TOKEN_DELIMIT "\\\n\t");
102445916cd2Sjpk 				(void) fprintf(fp, "%s", tok);
102545916cd2Sjpk 				count++;
102645916cd2Sjpk 			}
102745916cd2Sjpk 			if (count)
102845916cd2Sjpk 				(void) fprintf(fp, "%s",
102945916cd2Sjpk 				    KV_DELIMITER "\\\n\t");
103045916cd2Sjpk 		} else {
103145916cd2Sjpk 			(void) fprintf(fp, "%s%s", devinfo->devopts,
103245916cd2Sjpk 			    KV_DELIMITER "\\\n\t");
103345916cd2Sjpk 		}
103445916cd2Sjpk 	}
103545916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
103645916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
103745916cd2Sjpk 	    (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
103845916cd2Sjpk 	    KV_DELIMITER);
103945916cd2Sjpk 	(void) fprintf(fp, "%s\n",
104045916cd2Sjpk 	    (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
104145916cd2Sjpk 
104245916cd2Sjpk dmap_only:
104345916cd2Sjpk 	if (flag & DA_ALLOC_ONLY)
104445916cd2Sjpk 		return (0);
104545916cd2Sjpk 
104645916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
104745916cd2Sjpk 		return (-1);
104845916cd2Sjpk 
104945916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n",
105045916cd2Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
105145916cd2Sjpk 	(void) fprintf(fp, "\t%s%s\\\n",
105245916cd2Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
105345916cd2Sjpk 	(void) fprintf(fp, "\t%s\n",
105445916cd2Sjpk 	    (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
105545916cd2Sjpk 
105645916cd2Sjpk 	return (0);
105745916cd2Sjpk }
105845916cd2Sjpk 
105945916cd2Sjpk /*
106045916cd2Sjpk  * _da_lock_devdb -
106145916cd2Sjpk  *	locks the database files; lock can be either broken explicitly by
106245916cd2Sjpk  *	closing the fd of the lock file, or it expires automatically at process
106345916cd2Sjpk  *	termination.
106445916cd2Sjpk  * 	returns fd of the lock file or -1 on error.
106545916cd2Sjpk  */
106645916cd2Sjpk int
106745916cd2Sjpk _da_lock_devdb(char *rootdir)
106845916cd2Sjpk {
106945916cd2Sjpk 	int		lockfd = -1;
107010ddde3aSaj 	int		ret;
107110ddde3aSaj 	int		count = 0;
107210ddde3aSaj 	int		retry = 10;
107310ddde3aSaj 	int		retry_sleep;
107410ddde3aSaj 	uint_t		seed;
107545916cd2Sjpk 	char		*lockfile;
107645916cd2Sjpk 	char		path[MAXPATHLEN];
107745916cd2Sjpk 	int		size = sizeof (path);
107845916cd2Sjpk 
107945916cd2Sjpk 	if (rootdir == NULL) {
108045916cd2Sjpk 		lockfile = DA_DB_LOCK;
108145916cd2Sjpk 	} else {
108245916cd2Sjpk 		path[0] = '\0';
108345916cd2Sjpk 		if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
108445916cd2Sjpk 			return (-1);
108545916cd2Sjpk 		lockfile = path;
108645916cd2Sjpk 	}
108745916cd2Sjpk 
108845916cd2Sjpk 	if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
108945916cd2Sjpk 		/* cannot open lock file */
109045916cd2Sjpk 		return (-1);
109145916cd2Sjpk 
109245916cd2Sjpk 	(void) fchown(lockfd, DA_UID, DA_GID);
109345916cd2Sjpk 
109445916cd2Sjpk 	if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
109545916cd2Sjpk 		/* cannot position lock file */
109645916cd2Sjpk 		(void) close(lockfd);
109745916cd2Sjpk 		return (-1);
109845916cd2Sjpk 	}
109910ddde3aSaj 	errno = 0;
110010ddde3aSaj 	while (retry > 0) {
110110ddde3aSaj 		count++;
110210ddde3aSaj 		seed = (uint_t)gethrtime();
110310ddde3aSaj 		ret = lockf(lockfd, F_TLOCK, 0);
110410ddde3aSaj 		if (ret == 0) {
110510ddde3aSaj 			(void) utime(lockfile, NULL);
110610ddde3aSaj 			return (lockfd);
110710ddde3aSaj 		}
110810ddde3aSaj 		if ((errno != EACCES) && (errno != EAGAIN)) {
110945916cd2Sjpk 			/* cannot set lock */
111045916cd2Sjpk 			(void) close(lockfd);
111145916cd2Sjpk 			return (-1);
111245916cd2Sjpk 		}
111310ddde3aSaj 		retry--;
111410ddde3aSaj 		retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count;
111510ddde3aSaj 		(void) sleep(retry_sleep);
111610ddde3aSaj 		errno = 0;
111710ddde3aSaj 	}
111845916cd2Sjpk 
111910ddde3aSaj 	return (-1);
112045916cd2Sjpk }
112145916cd2Sjpk 
112245916cd2Sjpk /*
112345916cd2Sjpk  * da_open_devdb -
112445916cd2Sjpk  *	opens one or both database files - device_allocate, device_maps - in
112545916cd2Sjpk  *	the specified mode.
112645916cd2Sjpk  *	locks the database files; lock is either broken explicitly by the
112745916cd2Sjpk  *	caller by closing the lock file fd, or it expires automatically at
112845916cd2Sjpk  *	process termination.
112945916cd2Sjpk  *	writes the file pointer of opened file in the input args - dafp, dmfp.
113045916cd2Sjpk  *	returns fd of the lock file on success, -2 if database file does not
113145916cd2Sjpk  *	exist, -1 on other errors.
113245916cd2Sjpk  */
113345916cd2Sjpk int
113445916cd2Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
113545916cd2Sjpk {
113645916cd2Sjpk 	int	oflag = 0;
113745916cd2Sjpk 	int	fda = -1;
113845916cd2Sjpk 	int	fdm = -1;
113945916cd2Sjpk 	int	lockfd = -1;
114045916cd2Sjpk 	char	*fname;
114145916cd2Sjpk 	char	*fmode;
114245916cd2Sjpk 	char	path[MAXPATHLEN];
114345916cd2Sjpk 	FILE	*devfile;
114445916cd2Sjpk 
114545916cd2Sjpk 	if ((dafp == NULL) && (dmfp == NULL))
114645916cd2Sjpk 		return (-1);
114745916cd2Sjpk 
114845916cd2Sjpk 	if (flag & DA_RDWR) {
114945916cd2Sjpk 		oflag = DA_RDWR;
1150004388ebScasper 		fmode = "r+F";
115145916cd2Sjpk 	} else if (flag & DA_RDONLY) {
115245916cd2Sjpk 		oflag = DA_RDONLY;
1153004388ebScasper 		fmode = "rF";
115445916cd2Sjpk 	}
115545916cd2Sjpk 
115645916cd2Sjpk 	if ((lockfd = _da_lock_devdb(rootdir)) == -1)
115745916cd2Sjpk 		return (-1);
115845916cd2Sjpk 
115945916cd2Sjpk 	if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
116045916cd2Sjpk 		goto dmap_only;
116145916cd2Sjpk 
116245916cd2Sjpk 	path[0] = '\0';
116345916cd2Sjpk 
116445916cd2Sjpk 	/*
116545916cd2Sjpk 	 * open the device allocation file
116645916cd2Sjpk 	 */
116745916cd2Sjpk 	if (rootdir == NULL) {
116845916cd2Sjpk 		fname = DEVALLOC;
116945916cd2Sjpk 	} else {
117045916cd2Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
117145916cd2Sjpk 		    DEVALLOC) >= sizeof (path)) {
117245916cd2Sjpk 			if (lockfd != -1)
117345916cd2Sjpk 				(void) close(lockfd);
117445916cd2Sjpk 			return (-1);
117545916cd2Sjpk 		}
117645916cd2Sjpk 		fname = path;
117745916cd2Sjpk 	}
117845916cd2Sjpk 	if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
117945916cd2Sjpk 		if (lockfd != -1)
118045916cd2Sjpk 			(void) close(lockfd);
118145916cd2Sjpk 		return ((errno == ENOENT) ? -2 : -1);
118245916cd2Sjpk 	}
118345916cd2Sjpk 	if ((devfile = fdopen(fda, fmode)) == NULL) {
118445916cd2Sjpk 		(void) close(fda);
118545916cd2Sjpk 		if (lockfd != -1)
118645916cd2Sjpk 			(void) close(lockfd);
118745916cd2Sjpk 		return (-1);
118845916cd2Sjpk 	}
118945916cd2Sjpk 	*dafp = devfile;
119045916cd2Sjpk 	(void) fchmod(fda, DA_DBMODE);
119145916cd2Sjpk 
119245916cd2Sjpk 	if ((flag & DA_ALLOC_ONLY))
119345916cd2Sjpk 		goto out;
119445916cd2Sjpk 
119545916cd2Sjpk dmap_only:
119645916cd2Sjpk 	path[0] = '\0';
119745916cd2Sjpk 	/*
119845916cd2Sjpk 	 * open the device map file
119945916cd2Sjpk 	 */
120045916cd2Sjpk 	if (rootdir == NULL) {
120145916cd2Sjpk 		fname = DEVMAP;
120245916cd2Sjpk 	} else {
120345916cd2Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
120445916cd2Sjpk 		    DEVMAP) >= sizeof (path)) {
120545916cd2Sjpk 			(void) close(fda);
120645916cd2Sjpk 			if (lockfd != -1)
120745916cd2Sjpk 				(void) close(lockfd);
120845916cd2Sjpk 			return (-1);
120945916cd2Sjpk 		}
121045916cd2Sjpk 		fname = path;
121145916cd2Sjpk 	}
121245916cd2Sjpk 
121345916cd2Sjpk 	if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
121445916cd2Sjpk 		if (lockfd != -1)
121545916cd2Sjpk 			(void) close(lockfd);
121645916cd2Sjpk 		return ((errno == ENOENT) ? -2 : -1);
121745916cd2Sjpk 	}
121845916cd2Sjpk 
121945916cd2Sjpk 	if ((devfile = fdopen(fdm, fmode)) == NULL) {
122045916cd2Sjpk 		(void) close(fdm);
122145916cd2Sjpk 		(void) close(fda);
122245916cd2Sjpk 		if (lockfd != -1)
122345916cd2Sjpk 			(void) close(lockfd);
122445916cd2Sjpk 		return (-1);
122545916cd2Sjpk 	}
122645916cd2Sjpk 	*dmfp = devfile;
122745916cd2Sjpk 	(void) fchmod(fdm, DA_DBMODE);
122845916cd2Sjpk 
122945916cd2Sjpk out:
123045916cd2Sjpk 	return (lockfd);
123145916cd2Sjpk }
123245916cd2Sjpk 
123345916cd2Sjpk /*
123445916cd2Sjpk  * _record_on_off -
123545916cd2Sjpk  *	adds either DA_ON_STR or DA_OFF_STR to device_allocate
123645916cd2Sjpk  *	returns 0 on success, -1 on error.
123745916cd2Sjpk  */
123845916cd2Sjpk static int
123945916cd2Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
124045916cd2Sjpk {
124145916cd2Sjpk 	int		dafd;
124245916cd2Sjpk 	int		nsize;
124345916cd2Sjpk 	int		nitems = 1;
124445916cd2Sjpk 	int		actionlen;
124545916cd2Sjpk 	int		str_found = 0;
124645916cd2Sjpk 	int		len = 0, nlen = 0, plen = 0;
124745916cd2Sjpk 	char		*ptr = NULL;
124845916cd2Sjpk 	char		*actionstr;
124945916cd2Sjpk 	char		*nbuf = NULL;
125045916cd2Sjpk 	char		line[MAX_CANON];
125145916cd2Sjpk 	struct stat	dastat;
125245916cd2Sjpk 
125345916cd2Sjpk 	if (dargs->optflag & DA_ON)
125445916cd2Sjpk 		actionstr = DA_ON_STR;
125545916cd2Sjpk 	else
125645916cd2Sjpk 		actionstr = DA_OFF_STR;
125745916cd2Sjpk 	actionlen = strlen(actionstr);
125845916cd2Sjpk 	dafd = fileno(dafp);
125945916cd2Sjpk 	if (fstat(dafd, &dastat) == -1)
126045916cd2Sjpk 		return (-1);
126145916cd2Sjpk 
126245916cd2Sjpk 	/* check the old device_allocate for on/off string */
126345916cd2Sjpk 	ptr = fgets(line, MAX_CANON, dafp);
126445916cd2Sjpk 	if (ptr != NULL) {
126545916cd2Sjpk 		if ((strcmp(line, DA_ON_STR) == 0) ||
126645916cd2Sjpk 		    (strcmp(line, DA_OFF_STR) == 0)) {
126745916cd2Sjpk 			str_found = 1;
126845916cd2Sjpk 			nsize = dastat.st_size;
126945916cd2Sjpk 		}
127045916cd2Sjpk 	}
127145916cd2Sjpk 	if (!ptr || !str_found) {
127245916cd2Sjpk 		/*
127345916cd2Sjpk 		 * the file never had either the on or the off string;
127445916cd2Sjpk 		 * make room for it.
127545916cd2Sjpk 		 */
127645916cd2Sjpk 		str_found = 0;
127745916cd2Sjpk 		nsize = dastat.st_size + actionlen + 1;
127845916cd2Sjpk 	}
1279*7e3e5701SJan Parcel 	if ((nbuf = (char *)malloc(nsize + 1)) == NULL)
128045916cd2Sjpk 		return (-1);
128145916cd2Sjpk 	nbuf[0] = '\0';
128245916cd2Sjpk 	/* put the on/off string */
128345916cd2Sjpk 	(void) strcpy(nbuf, actionstr);
128445916cd2Sjpk 	nlen = strlen(nbuf);
128545916cd2Sjpk 	plen = nlen;
128645916cd2Sjpk 	if (ptr && !str_found) {
128745916cd2Sjpk 		/* now put the first line that we read in fgets */
128845916cd2Sjpk 		nlen = plen + strlen(line) + 1;
128945916cd2Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
129045916cd2Sjpk 		if (len >= nsize) {
129145916cd2Sjpk 			free(nbuf);
129245916cd2Sjpk 			return (-1);
129345916cd2Sjpk 		}
129445916cd2Sjpk 		plen += len;
129545916cd2Sjpk 	}
129645916cd2Sjpk 
129745916cd2Sjpk 	/* now get the rest of the old file */
129845916cd2Sjpk 	while (fgets(line, MAX_CANON, dafp) != NULL) {
129945916cd2Sjpk 		nlen = plen + strlen(line) + 1;
130045916cd2Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
130145916cd2Sjpk 		if (len >= nsize) {
130245916cd2Sjpk 			free(nbuf);
130345916cd2Sjpk 			return (-1);
130445916cd2Sjpk 		}
130545916cd2Sjpk 		plen += len;
130645916cd2Sjpk 	}
130745916cd2Sjpk 	len = strlen(nbuf) + 1;
130845916cd2Sjpk 	if (len < nsize)
130945916cd2Sjpk 		nbuf[len] = '\n';
131045916cd2Sjpk 
131145916cd2Sjpk 	/* write the on/off str + the old device_allocate to the temp file */
131245916cd2Sjpk 	if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
131345916cd2Sjpk 		free(nbuf);
131445916cd2Sjpk 		return (-1);
131545916cd2Sjpk 	}
131645916cd2Sjpk 
131745916cd2Sjpk 	free(nbuf);
131845916cd2Sjpk 
131945916cd2Sjpk 	return (0);
132045916cd2Sjpk }
132145916cd2Sjpk 
132245916cd2Sjpk /*
132345916cd2Sjpk  * da_update_defattrs -
132445916cd2Sjpk  *	writes default attributes to devalloc_defaults
132545916cd2Sjpk  *	returns 0 on success, -1 on error.
132645916cd2Sjpk  */
132745916cd2Sjpk int
132845916cd2Sjpk da_update_defattrs(da_args *dargs)
132945916cd2Sjpk {
133045916cd2Sjpk 	int		rc = 0, lockfd = 0, tmpfd = 0;
133145916cd2Sjpk 	char		*defpath = DEFATTRS;
133245916cd2Sjpk 	char		*tmpdefpath = TMPATTRS;
133345916cd2Sjpk 	FILE		*tmpfp = NULL;
133445916cd2Sjpk 	struct stat	dstat;
133545916cd2Sjpk 	strentry_t	*head_defent = NULL;
133645916cd2Sjpk 
133745916cd2Sjpk 	if (dargs == NULL)
133845916cd2Sjpk 		return (0);
133945916cd2Sjpk 	if ((lockfd = _da_lock_devdb(NULL)) == -1)
134045916cd2Sjpk 		return (-1);
134145916cd2Sjpk 	if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
134245916cd2Sjpk 		(void) close(lockfd);
134345916cd2Sjpk 		return (-1);
134445916cd2Sjpk 	}
134545916cd2Sjpk 	(void) fchown(tmpfd, DA_UID, DA_GID);
134645916cd2Sjpk 	if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) {
134745916cd2Sjpk 		(void) close(tmpfd);
134845916cd2Sjpk 		(void) unlink(tmpdefpath);
134945916cd2Sjpk 		(void) close(lockfd);
135045916cd2Sjpk 		return (-1);
135145916cd2Sjpk 	}
135245916cd2Sjpk 	/*
135345916cd2Sjpk 	 * examine all entries, remove an old one if required, check
135445916cd2Sjpk 	 * if a new one needs to be added.
135545916cd2Sjpk 	 */
135645916cd2Sjpk 	if (stat(defpath, &dstat) == 0) {
135745916cd2Sjpk 		if ((rc = _build_defattrs(dargs, &head_defent)) != 0) {
135845916cd2Sjpk 			if (rc == 1) {
135945916cd2Sjpk 				(void) close(tmpfd);
136045916cd2Sjpk 				(void) unlink(tmpdefpath);
136145916cd2Sjpk 				(void) close(lockfd);
136245916cd2Sjpk 				return (rc);
136345916cd2Sjpk 			}
136445916cd2Sjpk 		}
136545916cd2Sjpk 	}
136645916cd2Sjpk 	/*
136745916cd2Sjpk 	 * write back any existing entries.
136845916cd2Sjpk 	 */
136945916cd2Sjpk 	_write_defattrs(tmpfp, head_defent);
137045916cd2Sjpk 
137145916cd2Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
137245916cd2Sjpk 		/* add new entries */
137345916cd2Sjpk 		rc = _write_new_defattrs(tmpfp, dargs);
137445916cd2Sjpk 		(void) fclose(tmpfp);
137545916cd2Sjpk 	} else {
137645916cd2Sjpk 		(void) fclose(tmpfp);
137745916cd2Sjpk 	}
137845916cd2Sjpk 	if (rename(tmpdefpath, defpath) != 0) {
137945916cd2Sjpk 		rc = -1;
138045916cd2Sjpk 		(void) unlink(tmpdefpath);
138145916cd2Sjpk 	}
138245916cd2Sjpk 	(void) close(lockfd);
138345916cd2Sjpk 
138445916cd2Sjpk 	return (rc);
138545916cd2Sjpk }
138645916cd2Sjpk 
138745916cd2Sjpk /*
138845916cd2Sjpk  * da_update_device -
1389*7e3e5701SJan Parcel  *	Writes existing entries and the SINGLE change requested by da_args,
1390*7e3e5701SJan Parcel  *      to device_allocate and device_maps.
1391*7e3e5701SJan Parcel  * 	Returns 0 on success, -1 on error.
139245916cd2Sjpk  */
139345916cd2Sjpk int
139445916cd2Sjpk da_update_device(da_args *dargs)
139545916cd2Sjpk {
139645916cd2Sjpk 	int		rc;
139745916cd2Sjpk 	int		tafd = -1, tmfd = -1;
139845916cd2Sjpk 	int		lockfd = -1;
139945916cd2Sjpk 	char		*rootdir = NULL;
140010ddde3aSaj 	char		*apathp = NULL, *mpathp = NULL;
140110ddde3aSaj 	char		*dapathp = NULL, *dmpathp = NULL;
140210ddde3aSaj 	char		apath[MAXPATHLEN], mpath[MAXPATHLEN];
140310ddde3aSaj 	char		dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
140445916cd2Sjpk 	FILE		*tafp = NULL, *tmfp = NULL, *dafp = NULL;
140545916cd2Sjpk 	struct stat	dastat;
140645916cd2Sjpk 	devinfo_t	*devinfo;
140745916cd2Sjpk 	strentry_t	*head_devmapp = NULL;
140845916cd2Sjpk 	strentry_t	*head_devallocp = NULL;
140945916cd2Sjpk 
141045916cd2Sjpk 	if (dargs == NULL)
141145916cd2Sjpk 		return (0);
141245916cd2Sjpk 
141345916cd2Sjpk 	rootdir = dargs->rootdir;
141445916cd2Sjpk 	devinfo = dargs->devinfo;
141545916cd2Sjpk 
141645916cd2Sjpk 	/*
141745916cd2Sjpk 	 * adding/removing entries should be done in both
141845916cd2Sjpk 	 * device_allocate and device_maps. updates can be
141945916cd2Sjpk 	 * done in both or either of the files.
142045916cd2Sjpk 	 */
142145916cd2Sjpk 	if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
142245916cd2Sjpk 		if (dargs->optflag & DA_ALLOC_ONLY ||
142345916cd2Sjpk 		    dargs->optflag & DA_MAPS_ONLY)
142445916cd2Sjpk 			return (0);
142545916cd2Sjpk 	}
142645916cd2Sjpk 
142745916cd2Sjpk 	/*
142845916cd2Sjpk 	 * name, type and list are required fields for adding a new
142945916cd2Sjpk 	 * device.
143045916cd2Sjpk 	 */
143145916cd2Sjpk 	if ((dargs->optflag & DA_ADD) &&
143245916cd2Sjpk 	    ((devinfo->devname == NULL) ||
143345916cd2Sjpk 	    (devinfo->devtype == NULL) ||
143445916cd2Sjpk 	    (devinfo->devlist == NULL))) {
143545916cd2Sjpk 		return (-1);
143645916cd2Sjpk 	}
143745916cd2Sjpk 
143845916cd2Sjpk 	if (rootdir != NULL) {
143945916cd2Sjpk 		if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
144045916cd2Sjpk 		    TMPALLOC) >= sizeof (apath))
144145916cd2Sjpk 			return (-1);
144245916cd2Sjpk 		apathp = apath;
144345916cd2Sjpk 		if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
144445916cd2Sjpk 		    DEVALLOC) >= sizeof (dapath))
144545916cd2Sjpk 			return (-1);
144645916cd2Sjpk 		dapathp = dapath;
144745916cd2Sjpk 		if (!(dargs->optflag & DA_ALLOC_ONLY)) {
144845916cd2Sjpk 			if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
144945916cd2Sjpk 			    TMPMAP) >= sizeof (mpath))
145045916cd2Sjpk 				return (-1);
145145916cd2Sjpk 			mpathp = mpath;
145245916cd2Sjpk 			if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
145345916cd2Sjpk 			    DEVMAP) >= sizeof (dmpath))
145445916cd2Sjpk 				return (-1);
145545916cd2Sjpk 			dmpathp = dmpath;
145645916cd2Sjpk 		}
145745916cd2Sjpk 	} else {
145845916cd2Sjpk 		apathp = TMPALLOC;
145945916cd2Sjpk 		dapathp = DEVALLOC;
146045916cd2Sjpk 		mpathp = TMPMAP;
146145916cd2Sjpk 		dmpathp = DEVMAP;
146245916cd2Sjpk 	}
146345916cd2Sjpk 
146445916cd2Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
146545916cd2Sjpk 		goto dmap_only;
146645916cd2Sjpk 
146745916cd2Sjpk 	/*
146845916cd2Sjpk 	 * Check if we are here just to record on/off status of
146945916cd2Sjpk 	 * device_allocation.
147045916cd2Sjpk 	 */
147145916cd2Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
147245916cd2Sjpk 		lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
147345916cd2Sjpk 		    DA_RDONLY|DA_ALLOC_ONLY);
147445916cd2Sjpk 	else
147545916cd2Sjpk 		lockfd = _da_lock_devdb(rootdir);
147645916cd2Sjpk 	if (lockfd == -1)
147745916cd2Sjpk 		return (-1);
147845916cd2Sjpk 
147945916cd2Sjpk 	if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
148045916cd2Sjpk 		(void) close(lockfd);
148145916cd2Sjpk 		(void) fclose(dafp);
148245916cd2Sjpk 		return (-1);
148345916cd2Sjpk 	}
148445916cd2Sjpk 	(void) fchown(tafd, DA_UID, DA_GID);
148545916cd2Sjpk 	if ((tafp = fdopen(tafd, "r+")) == NULL) {
148645916cd2Sjpk 		(void) close(tafd);
148745916cd2Sjpk 		(void) unlink(apathp);
148845916cd2Sjpk 		(void) fclose(dafp);
148945916cd2Sjpk 		(void) close(lockfd);
149045916cd2Sjpk 		return (-1);
149145916cd2Sjpk 	}
149245916cd2Sjpk 
149345916cd2Sjpk 	/*
149445916cd2Sjpk 	 * We don't need to parse the file if we are here just to record
149545916cd2Sjpk 	 * on/off status of device_allocation.
149645916cd2Sjpk 	 */
149745916cd2Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
149845916cd2Sjpk 		if (_record_on_off(dargs, tafp, dafp) == -1) {
149945916cd2Sjpk 			(void) close(tafd);
150045916cd2Sjpk 			(void) unlink(apathp);
150145916cd2Sjpk 			(void) fclose(dafp);
150245916cd2Sjpk 			(void) close(lockfd);
150345916cd2Sjpk 			return (-1);
150445916cd2Sjpk 		}
150545916cd2Sjpk 		(void) fclose(dafp);
150645916cd2Sjpk 		goto out;
150745916cd2Sjpk 	}
150845916cd2Sjpk 
150945916cd2Sjpk 	/*
1510*7e3e5701SJan Parcel 	 * If reacting to a hotplug, read the file entries,
1511*7e3e5701SJan Parcel 	 * figure out what dname (tname + a new number) goes to the
1512*7e3e5701SJan Parcel 	 * device being added/removed, and create a good head_devallocp and
1513*7e3e5701SJan Parcel 	 * head_devmapp with everything good still in it (_rebuild_lists)
1514*7e3e5701SJan Parcel 	 *
1515*7e3e5701SJan Parcel 	 * Else examine all the entries, remove an old one if it is
1516*7e3e5701SJan Parcel 	 * a duplicate with a device being added, returning the
1517*7e3e5701SJan Parcel 	 * remaining list (_build_lists.)
1518*7e3e5701SJan Parcel 	 *
1519*7e3e5701SJan Parcel 	 * We need to do this only if the file exists already.
1520*7e3e5701SJan Parcel 	 *
1521*7e3e5701SJan Parcel 	 * Once we have built these lists, we need to free the strings
1522*7e3e5701SJan Parcel 	 * in the head_* arrays before returning.
152345916cd2Sjpk 	 */
152445916cd2Sjpk 	if (stat(dapathp, &dastat) == 0) {
1525*7e3e5701SJan Parcel 		/* for device allocation, the /etc files are the "master" */
1526*7e3e5701SJan Parcel 		if ((dargs->optflag & (DA_ADD| DA_EVENT)) &&
1527*7e3e5701SJan Parcel 		    (!(dargs->optflag & DA_FORCE)))
1528*7e3e5701SJan Parcel 			rc = _rebuild_lists(dargs, &head_devallocp,
1529*7e3e5701SJan Parcel 			    &head_devmapp);
1530*7e3e5701SJan Parcel 		else
1531*7e3e5701SJan Parcel 			rc = _build_lists(dargs, &head_devallocp,
1532*7e3e5701SJan Parcel 			    &head_devmapp);
1533*7e3e5701SJan Parcel 
1534*7e3e5701SJan Parcel 		if (rc != 0 && rc != 1) {
153545916cd2Sjpk 			(void) close(tafd);
153645916cd2Sjpk 			(void) unlink(apathp);
153745916cd2Sjpk 			(void) close(lockfd);
1538*7e3e5701SJan Parcel 			return (-1);
153945916cd2Sjpk 		}
1540*7e3e5701SJan Parcel 	} else
1541*7e3e5701SJan Parcel 		rc = 0;
1542*7e3e5701SJan Parcel 
1543*7e3e5701SJan Parcel 	if ((dargs->optflag & DA_REMOVE) && (rc == 0)) {
1544*7e3e5701SJan Parcel 		(void) close(tafd);
1545*7e3e5701SJan Parcel 		(void) unlink(apathp);
1546*7e3e5701SJan Parcel 		(void) close(lockfd);
1547*7e3e5701SJan Parcel 		return (0);
154845916cd2Sjpk 	}
1549*7e3e5701SJan Parcel 	/*
1550*7e3e5701SJan Parcel 	 * TODO: clean up the workings of DA_UPDATE.
1551*7e3e5701SJan Parcel 	 * Due to da_match looking at fields that are missing
1552*7e3e5701SJan Parcel 	 * in dargs for DA_UPDATE, the da_match call returns no match,
1553*7e3e5701SJan Parcel 	 * but due to the way _da2str combines the devalloc_t info with
1554*7e3e5701SJan Parcel 	 * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work.
1555*7e3e5701SJan Parcel 	 *
1556*7e3e5701SJan Parcel 	 * This would not scale if any type of update was ever needed
1557*7e3e5701SJan Parcel 	 * from the daemon.
1558*7e3e5701SJan Parcel 	 */
155945916cd2Sjpk 
156045916cd2Sjpk 	/*
1561*7e3e5701SJan Parcel 	 * Write out devallocp along with the devalloc on/off string.
156245916cd2Sjpk 	 */
156345916cd2Sjpk 	_write_device_allocate(dapathp, tafp, head_devallocp);
156445916cd2Sjpk 
156545916cd2Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
156645916cd2Sjpk 		goto out;
156745916cd2Sjpk 
156845916cd2Sjpk dmap_only:
156945916cd2Sjpk 	if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
157045916cd2Sjpk 		(void) close(tafd);
157145916cd2Sjpk 		(void) unlink(apathp);
157245916cd2Sjpk 		(void) close(lockfd);
157345916cd2Sjpk 		return (-1);
157445916cd2Sjpk 	}
157545916cd2Sjpk 	(void) fchown(tmfd, DA_UID, DA_GID);
157645916cd2Sjpk 	if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
157745916cd2Sjpk 		(void) close(tafd);
157845916cd2Sjpk 		(void) unlink(apathp);
157945916cd2Sjpk 		(void) close(tmfd);
158045916cd2Sjpk 		(void) unlink(mpathp);
158145916cd2Sjpk 		(void) close(lockfd);
158245916cd2Sjpk 		return (-1);
158345916cd2Sjpk 	}
158445916cd2Sjpk 
1585*7e3e5701SJan Parcel 	/*
1586*7e3e5701SJan Parcel 	 * Write back any non-removed pre-existing entries.
1587*7e3e5701SJan Parcel 	 */
158845916cd2Sjpk 	if (head_devmapp != NULL)
158945916cd2Sjpk 		_write_device_maps(tmfp, head_devmapp);
159045916cd2Sjpk 
159145916cd2Sjpk out:
1592*7e3e5701SJan Parcel 	/*
1593*7e3e5701SJan Parcel 	 * Add any new entries here.
1594*7e3e5701SJan Parcel 	 */
159545916cd2Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
159645916cd2Sjpk 		/* add any new entries */
159745916cd2Sjpk 		rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
159845916cd2Sjpk 		(void) fclose(tafp);
159945916cd2Sjpk 
160045916cd2Sjpk 		if (rc == 0)
160145916cd2Sjpk 			rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
160245916cd2Sjpk 		(void) fclose(tmfp);
160345916cd2Sjpk 	} else {
160445916cd2Sjpk 		if (tafp)
160545916cd2Sjpk 			(void) fclose(tafp);
160645916cd2Sjpk 		if (tmfp)
160745916cd2Sjpk 			(void) fclose(tmfp);
160845916cd2Sjpk 	}
160945916cd2Sjpk 
161045916cd2Sjpk 	rc = 0;
161145916cd2Sjpk 	if (!(dargs->optflag & DA_MAPS_ONLY)) {
161245916cd2Sjpk 		if (rename(apathp, dapathp) != 0) {
161345916cd2Sjpk 			rc = -1;
161445916cd2Sjpk 			(void) unlink(apathp);
161545916cd2Sjpk 		}
161645916cd2Sjpk 	}
161745916cd2Sjpk 	if (!(dargs->optflag & DA_ALLOC_ONLY)) {
161845916cd2Sjpk 		if (rename(mpathp, dmpathp) != 0) {
161945916cd2Sjpk 			rc = -1;
162045916cd2Sjpk 			(void) unlink(mpathp);
162145916cd2Sjpk 		}
162245916cd2Sjpk 	}
162345916cd2Sjpk 
162445916cd2Sjpk 	(void) close(lockfd);
162545916cd2Sjpk 
162645916cd2Sjpk 	return (rc);
162745916cd2Sjpk }
162845916cd2Sjpk 
162945916cd2Sjpk /*
163045916cd2Sjpk  * da_add_list -
163145916cd2Sjpk  *	adds new /dev link name to the linked list of devices.
163245916cd2Sjpk  *	returns 0 if link added successfully, -1 on error.
163345916cd2Sjpk  */
163445916cd2Sjpk int
163545916cd2Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
163645916cd2Sjpk {
163745916cd2Sjpk 	int		instance;
163845916cd2Sjpk 	int		nlen, plen;
163945916cd2Sjpk 	int		new_entry = 0;
164045916cd2Sjpk 	char		*dtype, *dexec, *tname, *kval;
164145916cd2Sjpk 	char		*minstr = NULL, *maxstr = NULL;
1642*7e3e5701SJan Parcel 	char		dname[DA_MAXNAME + 1];
164345916cd2Sjpk 	kva_t		*kva;
164445916cd2Sjpk 	deventry_t	*dentry = NULL, *nentry = NULL, *pentry = NULL;
164545916cd2Sjpk 	da_defs_t	*da_defs;
164645916cd2Sjpk 
164745916cd2Sjpk 	if (dlist == NULL || link == NULL)
164845916cd2Sjpk 		return (-1);
164945916cd2Sjpk 
165045916cd2Sjpk 	dname[0] = '\0';
165145916cd2Sjpk 	if (flag & DA_AUDIO) {
165245916cd2Sjpk 		dentry = dlist->audio;
165345916cd2Sjpk 		tname = DA_AUDIO_NAME;
165445916cd2Sjpk 		dtype = DA_AUDIO_TYPE;
165545916cd2Sjpk 		dexec = DA_DEFAULT_AUDIO_CLEAN;
165645916cd2Sjpk 	} else if (flag & DA_CD) {
165745916cd2Sjpk 		dentry = dlist->cd;
165845916cd2Sjpk 		tname = DA_CD_NAME;
165945916cd2Sjpk 		dtype = DA_CD_TYPE;
166045916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
166145916cd2Sjpk 	} else if (flag & DA_FLOPPY) {
166245916cd2Sjpk 		dentry = dlist->floppy;
166345916cd2Sjpk 		tname = DA_FLOPPY_NAME;
166445916cd2Sjpk 		dtype = DA_FLOPPY_TYPE;
166545916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
166645916cd2Sjpk 	} else if (flag & DA_TAPE) {
166745916cd2Sjpk 		dentry = dlist->tape;
166845916cd2Sjpk 		tname = DA_TAPE_NAME;
166945916cd2Sjpk 		dtype = DA_TAPE_TYPE;
167045916cd2Sjpk 		dexec = DA_DEFAULT_TAPE_CLEAN;
167145916cd2Sjpk 	} else if (flag & DA_RMDISK) {
167245916cd2Sjpk 		dentry = dlist->rmdisk;
167345916cd2Sjpk 		tname = DA_RMDISK_NAME;
167445916cd2Sjpk 		dtype = DA_RMDISK_TYPE;
167545916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
167645916cd2Sjpk 	} else {
167745916cd2Sjpk 		return (-1);
167845916cd2Sjpk 	}
167945916cd2Sjpk 
168045916cd2Sjpk 	for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
168145916cd2Sjpk 		pentry = nentry;
168245916cd2Sjpk 		(void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
168345916cd2Sjpk 		if (nentry->devinfo.instance == new_instance)
168445916cd2Sjpk 			/*
168545916cd2Sjpk 			 * Add the new link name to the list of links
168645916cd2Sjpk 			 * that the device 'dname' has.
168745916cd2Sjpk 			 */
168845916cd2Sjpk 			break;
168945916cd2Sjpk 	}
169045916cd2Sjpk 
169145916cd2Sjpk 	if (nentry == NULL) {
169245916cd2Sjpk 		/*
169345916cd2Sjpk 		 * Either this is the first entry ever, or no matching entry
169445916cd2Sjpk 		 * was found. Create a new one and add to the list.
169545916cd2Sjpk 		 */
169645916cd2Sjpk 		if (dentry == NULL)		/* first entry ever */
169745916cd2Sjpk 			instance = 0;
169845916cd2Sjpk 		else				/* no matching entry */
169945916cd2Sjpk 			instance++;
170045916cd2Sjpk 		(void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
170145916cd2Sjpk 		if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
170245916cd2Sjpk 		    NULL)
170345916cd2Sjpk 			return (-1);
170445916cd2Sjpk 		if (pentry != NULL)
170545916cd2Sjpk 			pentry->next = nentry;
170645916cd2Sjpk 		new_entry = 1;
170745916cd2Sjpk 		nentry->devinfo.devname = strdup(dname);
170845916cd2Sjpk 		nentry->devinfo.devtype = dtype;
170945916cd2Sjpk 		nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
171045916cd2Sjpk 		nentry->devinfo.devexec = dexec;
171145916cd2Sjpk 		nentry->devinfo.instance = new_instance;
171245916cd2Sjpk 		/*
171345916cd2Sjpk 		 * Look for default label range, authorizations and cleaning
171445916cd2Sjpk 		 * program in devalloc_defaults. If label range is not
171545916cd2Sjpk 		 * specified in devalloc_defaults, assume it to be admin_low
171645916cd2Sjpk 		 * to admin_high.
171745916cd2Sjpk 		 */
171845916cd2Sjpk 		minstr = DA_DEFAULT_MIN;
171945916cd2Sjpk 		maxstr = DA_DEFAULT_MAX;
172045916cd2Sjpk 		setdadefent();
172145916cd2Sjpk 		if (da_defs = getdadeftype(nentry->devinfo.devtype)) {
172245916cd2Sjpk 			kva = da_defs->devopts;
172345916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
172445916cd2Sjpk 				minstr = strdup(kval);
172545916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
172645916cd2Sjpk 				maxstr = strdup(kval);
172745916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
172845916cd2Sjpk 				nentry->devinfo.devauths = strdup(kval);
172945916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
173045916cd2Sjpk 				nentry->devinfo.devexec = strdup(kval);
173145916cd2Sjpk 			freedadefent(da_defs);
173245916cd2Sjpk 		}
173345916cd2Sjpk 		enddadefent();
173445916cd2Sjpk 		kval = NULL;
173545916cd2Sjpk 		nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
173645916cd2Sjpk 		    strlen(minstr) + strlen(KV_TOKEN_DELIMIT) +
173745916cd2Sjpk 		    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr)
173845916cd2Sjpk 		    + 1;			/* +1 for terminator */
173945916cd2Sjpk 		if (kval = (char *)malloc(nlen))
174045916cd2Sjpk 			(void) snprintf(kval, nlen, "%s%s%s%s%s%s%s",
174145916cd2Sjpk 			    DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT,
174245916cd2Sjpk 			    DAOPT_MAXLABEL, KV_ASSIGN, maxstr);
174345916cd2Sjpk 		nentry->devinfo.devopts = kval;
174445916cd2Sjpk 
174545916cd2Sjpk 		nentry->devinfo.devlist = NULL;
174645916cd2Sjpk 		nentry->next = NULL;
174745916cd2Sjpk 	}
174845916cd2Sjpk 
174945916cd2Sjpk 	nlen = strlen(link) + 1;		/* +1 terminator */
175045916cd2Sjpk 	if (nentry->devinfo.devlist) {
175145916cd2Sjpk 		plen = strlen(nentry->devinfo.devlist);
175245916cd2Sjpk 		nlen = nlen + plen + 1;	/* +1 for blank to separate entries */
175345916cd2Sjpk 	} else {
175445916cd2Sjpk 		plen = 0;
175545916cd2Sjpk 	}
175645916cd2Sjpk 
175745916cd2Sjpk 	if ((nentry->devinfo.devlist =
175845916cd2Sjpk 	    (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
175945916cd2Sjpk 		if (new_entry) {
176045916cd2Sjpk 			free(nentry->devinfo.devname);
176145916cd2Sjpk 			free(nentry);
176245916cd2Sjpk 			if (pentry != NULL)
176345916cd2Sjpk 				pentry->next = NULL;
176445916cd2Sjpk 		}
176545916cd2Sjpk 		return (-1);
176645916cd2Sjpk 	}
176745916cd2Sjpk 
176845916cd2Sjpk 	if (plen == 0)
176945916cd2Sjpk 		(void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
177045916cd2Sjpk 	else
177145916cd2Sjpk 		(void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
177245916cd2Sjpk 		    " %s", link);
177345916cd2Sjpk 
177445916cd2Sjpk 	if (pentry == NULL) {
177545916cd2Sjpk 		/*
177645916cd2Sjpk 		 * This is the first entry of this device type.
177745916cd2Sjpk 		 */
177845916cd2Sjpk 		if (flag & DA_AUDIO)
177945916cd2Sjpk 			dlist->audio = nentry;
178045916cd2Sjpk 		else if (flag & DA_CD)
178145916cd2Sjpk 			dlist->cd = nentry;
178245916cd2Sjpk 		else if (flag & DA_FLOPPY)
178345916cd2Sjpk 			dlist->floppy = nentry;
178445916cd2Sjpk 		else if (flag & DA_TAPE)
178545916cd2Sjpk 			dlist->tape = nentry;
178645916cd2Sjpk 		else if (flag & DA_RMDISK)
178745916cd2Sjpk 			dlist->rmdisk = nentry;
178845916cd2Sjpk 	}
178945916cd2Sjpk 
179045916cd2Sjpk 	return (0);
179145916cd2Sjpk }
179245916cd2Sjpk 
179345916cd2Sjpk /*
179445916cd2Sjpk  * da_remove_list -
179545916cd2Sjpk  *	removes a /dev link name from the linked list of devices.
179645916cd2Sjpk  *	returns type of device if link for that device removed
179745916cd2Sjpk  *	successfully, else returns -1 on error.
179845916cd2Sjpk  *	if all links for a device are removed, stores that device
179945916cd2Sjpk  *	name in devname.
180045916cd2Sjpk  */
180145916cd2Sjpk int
180245916cd2Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
180345916cd2Sjpk {
180445916cd2Sjpk 	int		flag;
180545916cd2Sjpk 	int		remove_dev = 0;
180645916cd2Sjpk 	int		nlen, plen, slen;
180745916cd2Sjpk 	char		*lasts, *lname, *oldlist;
180845916cd2Sjpk 	struct stat	rmstat;
180945916cd2Sjpk 	deventry_t	*dentry, *current, *prev;
181045916cd2Sjpk 
181145916cd2Sjpk 	if (type != NULL)
181245916cd2Sjpk 		flag = type;
181345916cd2Sjpk 	else if (link == NULL)
181445916cd2Sjpk 		return (-1);
181545916cd2Sjpk 	else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
181645916cd2Sjpk 		flag = DA_AUDIO;
181745916cd2Sjpk 	else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
181845916cd2Sjpk 	    strstr(link, "sr") || strstr(link, "rsr"))
181945916cd2Sjpk 		flag = DA_CD;
182045916cd2Sjpk 	else if (strstr(link, "fd") || strstr(link, "rfd") ||
182145916cd2Sjpk 	    strstr(link, "diskette") || strstr(link, "rdiskette"))
182245916cd2Sjpk 		flag = DA_FLOPPY;
182345916cd2Sjpk 	else if (strstr(link, DA_TAPE_NAME))
182445916cd2Sjpk 		flag = DA_TAPE;
182545916cd2Sjpk 	else
182645916cd2Sjpk 		flag = DA_RMDISK;
182745916cd2Sjpk 
182845916cd2Sjpk 	switch (type) {
182945916cd2Sjpk 	case DA_AUDIO:
183045916cd2Sjpk 		dentry = dlist->audio;
183145916cd2Sjpk 		break;
183245916cd2Sjpk 	case DA_CD:
183345916cd2Sjpk 		dentry = dlist->cd;
183445916cd2Sjpk 		break;
183545916cd2Sjpk 	case DA_FLOPPY:
183645916cd2Sjpk 		dentry = dlist->floppy;
183745916cd2Sjpk 		break;
183845916cd2Sjpk 	case DA_TAPE:
183945916cd2Sjpk 		dentry = dlist->tape;
184045916cd2Sjpk 		break;
184145916cd2Sjpk 	case DA_RMDISK:
184245916cd2Sjpk 		dentry = dlist->rmdisk;
184345916cd2Sjpk 		break;
184445916cd2Sjpk 	default:
184545916cd2Sjpk 		return (-1);
184645916cd2Sjpk 	}
184745916cd2Sjpk 
184845916cd2Sjpk 	if ((type != NULL) && (link == NULL)) {
184945916cd2Sjpk 		for (current = dentry, prev = dentry; current != NULL;
185045916cd2Sjpk 		    current = current->next) {
185145916cd2Sjpk 			oldlist = strdup(current->devinfo.devlist);
185245916cd2Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
185345916cd2Sjpk 			    lname != NULL;
185445916cd2Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
185545916cd2Sjpk 				if (stat(lname, &rmstat) != 0) {
185645916cd2Sjpk 					remove_dev = 1;
185745916cd2Sjpk 					goto remove_dev;
185845916cd2Sjpk 				}
185945916cd2Sjpk 			}
186045916cd2Sjpk 			prev = current;
186145916cd2Sjpk 		}
186245916cd2Sjpk 		return (-1);
186345916cd2Sjpk 	}
186445916cd2Sjpk 
186545916cd2Sjpk 	for (current = dentry, prev = dentry; current != NULL;
186645916cd2Sjpk 	    current = current->next) {
186745916cd2Sjpk 		plen = strlen(current->devinfo.devlist);
186845916cd2Sjpk 		nlen = strlen(link);
186945916cd2Sjpk 		if (plen == nlen) {
187045916cd2Sjpk 			if (strcmp(current->devinfo.devlist, link) == 0) {
187145916cd2Sjpk 				/* last name in the list */
187245916cd2Sjpk 				remove_dev = 1;
187345916cd2Sjpk 				break;
187445916cd2Sjpk 			}
187545916cd2Sjpk 		}
187645916cd2Sjpk 		if (strstr(current->devinfo.devlist, link)) {
187745916cd2Sjpk 			nlen = plen - nlen + 1;
187845916cd2Sjpk 			oldlist = strdup(current->devinfo.devlist);
187945916cd2Sjpk 			if ((current->devinfo.devlist =
188045916cd2Sjpk 			    (char *)realloc(current->devinfo.devlist,
188145916cd2Sjpk 			    nlen)) == NULL) {
188245916cd2Sjpk 				free(oldlist);
188345916cd2Sjpk 				return (-1);
188445916cd2Sjpk 			}
188545916cd2Sjpk 			current->devinfo.devlist[0] = '\0';
188645916cd2Sjpk 			nlen = plen = slen = 0;
188745916cd2Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
188845916cd2Sjpk 			    lname != NULL;
188945916cd2Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
189045916cd2Sjpk 				if (strcmp(lname, link) == 0)
189145916cd2Sjpk 					continue;
189245916cd2Sjpk 				nlen = strlen(lname) + plen + 1;
189345916cd2Sjpk 				if (plen == 0) {
189445916cd2Sjpk 					slen =
189545916cd2Sjpk 					    snprintf(current->devinfo.devlist,
189645916cd2Sjpk 					    nlen, "%s", lname);
189745916cd2Sjpk 				} else {
189845916cd2Sjpk 					slen =
189945916cd2Sjpk 					    snprintf(current->devinfo.devlist +
190010ddde3aSaj 					    plen, nlen - plen, " %s", lname);
190145916cd2Sjpk 				}
190245916cd2Sjpk 				plen = plen + slen + 1;
190345916cd2Sjpk 			}
190445916cd2Sjpk 			free(oldlist);
190545916cd2Sjpk 			break;
190645916cd2Sjpk 		}
190745916cd2Sjpk 		prev = current;
190845916cd2Sjpk 	}
190945916cd2Sjpk 
191045916cd2Sjpk remove_dev:
191145916cd2Sjpk 	if (remove_dev == 1) {
191245916cd2Sjpk 		(void) strlcpy(devname, current->devinfo.devname, size);
191345916cd2Sjpk 		free(current->devinfo.devname);
191445916cd2Sjpk 		free(current->devinfo.devlist);
191545916cd2Sjpk 		current->devinfo.devname = current->devinfo.devlist = NULL;
191645916cd2Sjpk 		prev->next = current->next;
191745916cd2Sjpk 		free(current);
191845916cd2Sjpk 		current = NULL;
191945916cd2Sjpk 	}
192045916cd2Sjpk 	if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
192145916cd2Sjpk 		if (prev->next) {
192245916cd2Sjpk 			/*
192345916cd2Sjpk 			 * what we removed above was the first entry
192445916cd2Sjpk 			 * in the list. make the next entry to be the
192545916cd2Sjpk 			 * first.
192645916cd2Sjpk 			 */
192745916cd2Sjpk 			current = prev->next;
192845916cd2Sjpk 		} else {
192945916cd2Sjpk 			/*
193045916cd2Sjpk 			 * the matching entry was the only entry in the list
193145916cd2Sjpk 			 * for this type.
193245916cd2Sjpk 			 */
193345916cd2Sjpk 			current = NULL;
193445916cd2Sjpk 		}
193545916cd2Sjpk 		if (flag & DA_AUDIO)
193645916cd2Sjpk 			dlist->audio = current;
193745916cd2Sjpk 		else if (flag & DA_CD)
193845916cd2Sjpk 			dlist->cd = current;
193945916cd2Sjpk 		else if (flag & DA_FLOPPY)
194045916cd2Sjpk 			dlist->floppy = current;
194145916cd2Sjpk 		else if (flag & DA_TAPE)
194245916cd2Sjpk 			dlist->tape = current;
194345916cd2Sjpk 		else if (flag & DA_RMDISK)
194445916cd2Sjpk 			dlist->rmdisk = current;
194545916cd2Sjpk 	}
194645916cd2Sjpk 
194745916cd2Sjpk 	return (flag);
194845916cd2Sjpk }
194945916cd2Sjpk 
195045916cd2Sjpk /*
1951*7e3e5701SJan Parcel  * da_rm_list_entry -
1952*7e3e5701SJan Parcel  *
1953*7e3e5701SJan Parcel  *	The adding of devnames to a devlist and the removal of a
1954*7e3e5701SJan Parcel  *	device are not symmetrical -- hot_cleanup gives a /devices
1955*7e3e5701SJan Parcel  *	name which is used to remove the dentry whose links all point to
1956*7e3e5701SJan Parcel  *	that /devices entry.
1957*7e3e5701SJan Parcel  *
1958*7e3e5701SJan Parcel  *	The link argument is present if available to make debugging
1959*7e3e5701SJan Parcel  *	easier.
1960*7e3e5701SJan Parcel  *
1961*7e3e5701SJan Parcel  *	da_rm_list_entry removes an entry from the linked list of devices.
1962*7e3e5701SJan Parcel  *
1963*7e3e5701SJan Parcel  *	Returns 1 if the devname was removed successfully,
1964*7e3e5701SJan Parcel  *	0 if not found, -1 for error.
1965*7e3e5701SJan Parcel  */
1966*7e3e5701SJan Parcel /*ARGSUSED*/
1967*7e3e5701SJan Parcel int
1968*7e3e5701SJan Parcel da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname)
1969*7e3e5701SJan Parcel {
1970*7e3e5701SJan Parcel 	int		retval = 0;
1971*7e3e5701SJan Parcel 	deventry_t	**dentry, *current, *prev;
1972*7e3e5701SJan Parcel 
1973*7e3e5701SJan Parcel 	switch (type) {
1974*7e3e5701SJan Parcel 	case DA_AUDIO:
1975*7e3e5701SJan Parcel 		dentry = &(dlist->audio);
1976*7e3e5701SJan Parcel 		break;
1977*7e3e5701SJan Parcel 	case DA_CD:
1978*7e3e5701SJan Parcel 		dentry = &(dlist->cd);
1979*7e3e5701SJan Parcel 		break;
1980*7e3e5701SJan Parcel 	case DA_FLOPPY:
1981*7e3e5701SJan Parcel 		dentry = &(dlist->floppy);
1982*7e3e5701SJan Parcel 		break;
1983*7e3e5701SJan Parcel 	case DA_TAPE:
1984*7e3e5701SJan Parcel 		dentry = &(dlist->tape);
1985*7e3e5701SJan Parcel 		break;
1986*7e3e5701SJan Parcel 	case DA_RMDISK:
1987*7e3e5701SJan Parcel 		dentry = &(dlist->rmdisk);
1988*7e3e5701SJan Parcel 		break;
1989*7e3e5701SJan Parcel 	default:
1990*7e3e5701SJan Parcel 		return (-1);
1991*7e3e5701SJan Parcel 	}
1992*7e3e5701SJan Parcel 
1993*7e3e5701SJan Parcel 	/* Presumably in daemon mode, no need to remove entry, list is empty */
1994*7e3e5701SJan Parcel 	if (*dentry == (deventry_t *)NULL)
1995*7e3e5701SJan Parcel 		return (0);
1996*7e3e5701SJan Parcel 
1997*7e3e5701SJan Parcel 	prev = NULL;
1998*7e3e5701SJan Parcel 	for (current = *dentry; current != NULL;
1999*7e3e5701SJan Parcel 	    prev = current, current = current->next) {
2000*7e3e5701SJan Parcel 		if (strcmp(devname, current->devinfo.devname))
2001*7e3e5701SJan Parcel 			continue;
2002*7e3e5701SJan Parcel 		retval = 1;
2003*7e3e5701SJan Parcel 		break;
2004*7e3e5701SJan Parcel 	}
2005*7e3e5701SJan Parcel 	if (retval == 0)
2006*7e3e5701SJan Parcel 		return (0);
2007*7e3e5701SJan Parcel 	free(current->devinfo.devname);
2008*7e3e5701SJan Parcel 	if (current->devinfo.devlist != NULL)
2009*7e3e5701SJan Parcel 		free(current->devinfo.devlist);
2010*7e3e5701SJan Parcel 	if (current->devinfo.devopts != NULL)
2011*7e3e5701SJan Parcel 		free(current->devinfo.devopts);
2012*7e3e5701SJan Parcel 
2013*7e3e5701SJan Parcel 	if (prev == NULL)
2014*7e3e5701SJan Parcel 		*dentry = current->next;
2015*7e3e5701SJan Parcel 	else
2016*7e3e5701SJan Parcel 		prev->next = current->next;
2017*7e3e5701SJan Parcel 
2018*7e3e5701SJan Parcel 	free(current);
2019*7e3e5701SJan Parcel 	return (retval);
2020*7e3e5701SJan Parcel }
2021*7e3e5701SJan Parcel 
2022*7e3e5701SJan Parcel /*
202345916cd2Sjpk  * da_is_on -
202445916cd2Sjpk  *	checks if device allocation feature is turned on.
202545916cd2Sjpk  *	returns 1 if on, 0 if off, -1 if status string not
202645916cd2Sjpk  *	found in device_allocate.
202745916cd2Sjpk  */
202845916cd2Sjpk int
202945916cd2Sjpk da_is_on()
203045916cd2Sjpk {
203145916cd2Sjpk 	return (getdaon());
203245916cd2Sjpk }
203345916cd2Sjpk 
203445916cd2Sjpk /*
203545916cd2Sjpk  * da_print_device -
203645916cd2Sjpk  *	debug routine to print device entries.
203745916cd2Sjpk  */
203845916cd2Sjpk void
203945916cd2Sjpk da_print_device(int flag, devlist_t *devlist)
204045916cd2Sjpk {
204145916cd2Sjpk 	deventry_t	*entry, *dentry;
204245916cd2Sjpk 	devinfo_t	*devinfo;
204345916cd2Sjpk 
204445916cd2Sjpk 	if (flag & DA_AUDIO)
204545916cd2Sjpk 		dentry = devlist->audio;
204645916cd2Sjpk 	else if (flag & DA_CD)
204745916cd2Sjpk 		dentry = devlist->cd;
204845916cd2Sjpk 	else if (flag & DA_FLOPPY)
204945916cd2Sjpk 		dentry = devlist->floppy;
205045916cd2Sjpk 	else if (flag & DA_TAPE)
205145916cd2Sjpk 		dentry = devlist->tape;
205245916cd2Sjpk 	else if (flag & DA_RMDISK)
205345916cd2Sjpk 		dentry = devlist->rmdisk;
205445916cd2Sjpk 	else
205545916cd2Sjpk 		return;
205645916cd2Sjpk 
205745916cd2Sjpk 	for (entry = dentry; entry != NULL; entry = entry->next) {
205845916cd2Sjpk 		devinfo = &(entry->devinfo);
205945916cd2Sjpk 		(void) fprintf(stdout, "name: %s\n", devinfo->devname);
206045916cd2Sjpk 		(void) fprintf(stdout, "type: %s\n", devinfo->devtype);
206145916cd2Sjpk 		(void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
206245916cd2Sjpk 		(void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
206345916cd2Sjpk 		(void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);
206445916cd2Sjpk 	}
206545916cd2Sjpk }
2066