xref: /titanic_51/usr/src/lib/libbsm/common/devalloc.c (revision 10ddde3aee60d88fa580028fcf7642a87e80a2c6)
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*10ddde3aSaj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2445916cd2Sjpk  * Use is subject to license terms.
2545916cd2Sjpk  */
2645916cd2Sjpk 
2745916cd2Sjpk #pragma ident	"%Z%%M%	%I%	%E% SMI"
2845916cd2Sjpk 
2945916cd2Sjpk #include <stdlib.h>
3045916cd2Sjpk #include <ctype.h>
3145916cd2Sjpk #include <unistd.h>
3245916cd2Sjpk #include <limits.h>
3345916cd2Sjpk #include <fcntl.h>
3445916cd2Sjpk #include <sys/types.h>
3545916cd2Sjpk #include <sys/stat.h>
3645916cd2Sjpk #include <utime.h>
3745916cd2Sjpk #include <synch.h>
3845916cd2Sjpk #include <strings.h>
3945916cd2Sjpk #include <string.h>
4045916cd2Sjpk #include <libintl.h>
4145916cd2Sjpk #include <errno.h>
4245916cd2Sjpk #include <auth_list.h>
4345916cd2Sjpk #include <bsm/devices.h>
4445916cd2Sjpk #include <bsm/devalloc.h>
4545916cd2Sjpk 
4645916cd2Sjpk #define	DA_DEFS	"/etc/security/tsol/devalloc_defaults"
4745916cd2Sjpk 
4845916cd2Sjpk extern int _readbufline(char *, int, char *, int, int *);
4945916cd2Sjpk extern char *strtok_r(char *, const char *, char **);
5045916cd2Sjpk extern char *_strtok_escape(char *, char *, char **);
5145916cd2Sjpk extern int getdaon(void);
5245916cd2Sjpk extern int da_matchname(devalloc_t *, char *);
5345916cd2Sjpk extern int da_match(devalloc_t *, da_args *);
5445916cd2Sjpk extern int dmap_matchname(devmap_t *, char *);
5545916cd2Sjpk extern int dm_match(devmap_t *, da_args *);
5645916cd2Sjpk 
5745916cd2Sjpk /*
5845916cd2Sjpk  * The following structure is for recording old entries to be retained.
5945916cd2Sjpk  * We read the entries from the database into a linked list in memory,
6045916cd2Sjpk  * then turn around and write them out again.
6145916cd2Sjpk  */
6245916cd2Sjpk typedef struct strentry {
6345916cd2Sjpk 	struct strentry	*se_next;
6445916cd2Sjpk 	char		se_str[4096 + 1];
6545916cd2Sjpk } strentry_t;
6645916cd2Sjpk 
6745916cd2Sjpk /*
6845916cd2Sjpk  * da_check_longindevperm -
6945916cd2Sjpk  *	reads /etc/logindevperm and checks if specified device is in the file.
7045916cd2Sjpk  *	returns 1 if specified device found in /etc/logindevperm, else returns 0
7145916cd2Sjpk  */
7245916cd2Sjpk int
7345916cd2Sjpk da_check_logindevperm(char *devname)
7445916cd2Sjpk {
7545916cd2Sjpk 	int		ret = 0;
7645916cd2Sjpk 	int		fd = -1;
7745916cd2Sjpk 	int		nlen, plen, slen, lineno, fsize;
7845916cd2Sjpk 	char		line[MAX_CANON];
7945916cd2Sjpk 	char		*field_delims = " \t\n";
8045916cd2Sjpk 	char		*fbuf = NULL;
8145916cd2Sjpk 	char		*ptr, *device;
8245916cd2Sjpk 	char		*lasts = NULL;
8345916cd2Sjpk 	FILE		*fp;
8445916cd2Sjpk 	struct stat	f_stat;
8545916cd2Sjpk 
8645916cd2Sjpk 	/*
8745916cd2Sjpk 	 * check if /etc/logindevperm exists and get its size
8845916cd2Sjpk 	 */
8945916cd2Sjpk 	if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1)
9045916cd2Sjpk 		return (0);
9145916cd2Sjpk 	if (fstat(fd, &f_stat) != 0) {
9245916cd2Sjpk 		(void) close(fd);
9345916cd2Sjpk 		return (0);
9445916cd2Sjpk 	}
9545916cd2Sjpk 	fsize = f_stat.st_size;
9645916cd2Sjpk 	if ((fbuf = (char *)malloc(fsize)) == NULL) {
9745916cd2Sjpk 		(void) close(fd);
9845916cd2Sjpk 		return (0);
9945916cd2Sjpk 	}
100004388ebScasper 	if ((fp = fdopen(fd, "rF")) == NULL) {
10145916cd2Sjpk 		free(fbuf);
10245916cd2Sjpk 		(void) close(fd);
10345916cd2Sjpk 		return (0);
10445916cd2Sjpk 	}
10545916cd2Sjpk 
10645916cd2Sjpk 	/*
10745916cd2Sjpk 	 * read and parse /etc/logindevperm
10845916cd2Sjpk 	 */
10945916cd2Sjpk 	plen = nlen = lineno = 0;
11045916cd2Sjpk 	while (fgets(line, MAX_CANON, fp) != NULL) {
11145916cd2Sjpk 		lineno++;
11245916cd2Sjpk 		if ((ptr = strchr(line, '#')) != NULL)
11345916cd2Sjpk 			*ptr = '\0';	/* handle comments */
11445916cd2Sjpk 		if (strtok_r(line, field_delims, &lasts) == NULL)
11545916cd2Sjpk 			continue;	/* ignore blank lines */
11645916cd2Sjpk 		if (strtok_r(NULL, field_delims, &lasts) == NULL)
11745916cd2Sjpk 			/* invalid entry */
11845916cd2Sjpk 			continue;
11945916cd2Sjpk 		if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL)
12045916cd2Sjpk 			/* empty device list */
12145916cd2Sjpk 			continue;
12245916cd2Sjpk 		nlen = strlen(ptr) + 1;		/* +1 terminator */
12345916cd2Sjpk 		nlen += (plen + 1);
12445916cd2Sjpk 		if (plen == 0)
12545916cd2Sjpk 			slen = snprintf(fbuf, nlen, "%s", ptr);
12645916cd2Sjpk 		else
12745916cd2Sjpk 			slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr);
12845916cd2Sjpk 		if (slen >= fsize) {
12945916cd2Sjpk 			fbuf[0] = '\0';
13045916cd2Sjpk 			(void) fclose(fp);
13145916cd2Sjpk 			return (slen);
13245916cd2Sjpk 		}
13345916cd2Sjpk 		plen += slen;
13445916cd2Sjpk 	}
13545916cd2Sjpk 	(void) fclose(fp);
13645916cd2Sjpk 
13745916cd2Sjpk 	/*
13845916cd2Sjpk 	 * check if devname exists in /etc/logindevperm
13945916cd2Sjpk 	 */
14045916cd2Sjpk 	device = strtok_r(fbuf, ":", &lasts);
14145916cd2Sjpk 	while (device != NULL) {
14245916cd2Sjpk 		/*
14345916cd2Sjpk 		 * device and devname may be one of these types -
14445916cd2Sjpk 		 *    /dev/xx
14545916cd2Sjpk 		 *    /dev/xx*
14645916cd2Sjpk 		 *    /dev/dir/xx
14745916cd2Sjpk 		 *    /dev/dir/xx*
14845916cd2Sjpk 		 *    /dev/dir/"*"
14945916cd2Sjpk 		 */
15045916cd2Sjpk 		if (strcmp(device, devname) == 0) {
15145916cd2Sjpk 			/* /dev/xx, /dev/dir/xx */
15245916cd2Sjpk 			free(fbuf);
15345916cd2Sjpk 			return (1);
15445916cd2Sjpk 		}
15545916cd2Sjpk 		if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) {
15645916cd2Sjpk 			/* all wildcard types */
15745916cd2Sjpk 			*ptr = '\0';
15845916cd2Sjpk 			if (strncmp(device, devname, strlen(device)) == 0) {
15945916cd2Sjpk 				free(fbuf);
16045916cd2Sjpk 				return (1);
16145916cd2Sjpk 			}
16245916cd2Sjpk 		}
16345916cd2Sjpk 		device = strtok_r(NULL, ":", &lasts);
16445916cd2Sjpk 	}
16545916cd2Sjpk 
16645916cd2Sjpk 	return (ret);
16745916cd2Sjpk }
16845916cd2Sjpk 
16945916cd2Sjpk /*
17045916cd2Sjpk  * _da_read_file -
17145916cd2Sjpk  *	establishes readers/writer lock on fname; reads in the file if its
17245916cd2Sjpk  *	contents changed since the last time we read it.
17345916cd2Sjpk  *	returns size of buffer read, or -1 on failure.
17445916cd2Sjpk  */
17545916cd2Sjpk int
17645916cd2Sjpk _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock,
17745916cd2Sjpk     int flag)
17845916cd2Sjpk {
17945916cd2Sjpk 	int		fd = -1;
18045916cd2Sjpk 	int		fsize = 0;
18145916cd2Sjpk 	time_t		newtime;
18245916cd2Sjpk 	struct stat	f_stat;
18345916cd2Sjpk 
18445916cd2Sjpk 	if (flag & DA_FORCE)
18545916cd2Sjpk 		*ftime = 0;
18645916cd2Sjpk 
18745916cd2Sjpk 	/* check the size and the time stamp on the file */
18845916cd2Sjpk 	if (rw_rdlock(flock) != 0)
18945916cd2Sjpk 		return (-1);
19045916cd2Sjpk 	if (stat(fname, &f_stat) != 0) {
19145916cd2Sjpk 		(void) rw_unlock(flock);
19245916cd2Sjpk 		return (-1);
19345916cd2Sjpk 	}
19445916cd2Sjpk 	fsize = f_stat.st_size;
19545916cd2Sjpk 	newtime = f_stat.st_mtime;
19645916cd2Sjpk 	(void) rw_unlock(flock);
19745916cd2Sjpk 
19845916cd2Sjpk 	while (newtime > *ftime) {
19945916cd2Sjpk 		/*
20045916cd2Sjpk 		 * file has been modified since we last read it; or this
20145916cd2Sjpk 		 * is a forced read.
20245916cd2Sjpk 		 * read file into the buffer with rw lock.
20345916cd2Sjpk 		 */
20445916cd2Sjpk 		if (rw_wrlock(flock) != 0)
20545916cd2Sjpk 			return (-1);
206004388ebScasper 		if ((fd = open(fname, O_RDONLY)) == -1) {
20745916cd2Sjpk 			(void) rw_unlock(flock);
20845916cd2Sjpk 			return (-1);
20945916cd2Sjpk 		}
21045916cd2Sjpk 		if (*fbuf != NULL) {
21145916cd2Sjpk 			free(*fbuf);
21245916cd2Sjpk 			*fbuf = NULL;
21345916cd2Sjpk 		}
21445916cd2Sjpk 		if ((*fbuf = malloc(fsize)) == NULL) {
21545916cd2Sjpk 			(void) rw_unlock(flock);
21645916cd2Sjpk 			(void) close(fd);
21745916cd2Sjpk 			return (-1);
21845916cd2Sjpk 		}
21945916cd2Sjpk 		if (read(fd, *fbuf, fsize) < fsize) {
22045916cd2Sjpk 			free(*fbuf);
22145916cd2Sjpk 			(void) rw_unlock(flock);
22245916cd2Sjpk 			(void) close(fd);
22345916cd2Sjpk 			return (-1);
22445916cd2Sjpk 		}
22545916cd2Sjpk 		(void) rw_unlock(flock);
22645916cd2Sjpk 		/*
22745916cd2Sjpk 		 * verify that the file did not change just after we read it.
22845916cd2Sjpk 		 */
22945916cd2Sjpk 		if (rw_rdlock(flock) != 0) {
23045916cd2Sjpk 			free(*fbuf);
23145916cd2Sjpk 			(void) close(fd);
23245916cd2Sjpk 			return (-1);
23345916cd2Sjpk 		}
23445916cd2Sjpk 		if (stat(fname, &f_stat) != 0) {
23545916cd2Sjpk 			free(*fbuf);
23645916cd2Sjpk 			(void) rw_unlock(flock);
23745916cd2Sjpk 			(void) close(fd);
23845916cd2Sjpk 			return (-1);
23945916cd2Sjpk 		}
24045916cd2Sjpk 		fsize = f_stat.st_size;
24145916cd2Sjpk 		newtime = f_stat.st_mtime;
24245916cd2Sjpk 		(void) rw_unlock(flock);
24345916cd2Sjpk 		(void) close(fd);
24445916cd2Sjpk 		*ftime = newtime;
24545916cd2Sjpk 	}
24645916cd2Sjpk 
24745916cd2Sjpk 	return (fsize);
24845916cd2Sjpk }
24945916cd2Sjpk 
25045916cd2Sjpk /*
25145916cd2Sjpk  * _update_zonename -
25245916cd2Sjpk  *	add/remove current zone's name to the given devalloc_t.
25345916cd2Sjpk  */
25445916cd2Sjpk void
25545916cd2Sjpk _update_zonename(da_args *dargs, devalloc_t *dap)
25645916cd2Sjpk {
25745916cd2Sjpk 	int		i, j;
25845916cd2Sjpk 	int		oldsize, newsize;
25945916cd2Sjpk 	int		has_zonename = 0;
26045916cd2Sjpk 	char		*zonename;
26145916cd2Sjpk 	kva_t		*newkva, *oldkva;
26245916cd2Sjpk 	kv_t		*newdata, *olddata;
26345916cd2Sjpk 	devinfo_t	*devinfo;
26445916cd2Sjpk 
26545916cd2Sjpk 	devinfo = dargs->devinfo;
26645916cd2Sjpk 	oldkva = dap->da_devopts;
26745916cd2Sjpk 	if (oldkva == NULL) {
26845916cd2Sjpk 		if (dargs->optflag & DA_REMOVE_ZONE)
26945916cd2Sjpk 			return;
27045916cd2Sjpk 		if (dargs->optflag & DA_ADD_ZONE) {
27145916cd2Sjpk 			newkva = _str2kva(devinfo->devopts, KV_ASSIGN,
27245916cd2Sjpk 			    KV_TOKEN_DELIMIT);
27345916cd2Sjpk 			if (newkva != NULL)
27445916cd2Sjpk 				dap->da_devopts = newkva;
27545916cd2Sjpk 			return;
27645916cd2Sjpk 		}
27745916cd2Sjpk 	}
27845916cd2Sjpk 	newsize = oldsize = oldkva->length;
27945916cd2Sjpk 	if (kva_match(oldkva, DAOPT_ZONE))
28045916cd2Sjpk 		has_zonename = 1;
28145916cd2Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
28245916cd2Sjpk 		if ((zonename = index(devinfo->devopts, '=')) == NULL)
28345916cd2Sjpk 			return;
28445916cd2Sjpk 		zonename++;
28545916cd2Sjpk 		if (has_zonename) {
28645916cd2Sjpk 			(void) _insert2kva(oldkva, DAOPT_ZONE, zonename);
28745916cd2Sjpk 			return;
28845916cd2Sjpk 		}
28945916cd2Sjpk 		newsize += 1;
29045916cd2Sjpk 	} else if (dargs->optflag & DA_REMOVE_ZONE) {
29145916cd2Sjpk 		if (has_zonename) {
29245916cd2Sjpk 			newsize -= 1;
29345916cd2Sjpk 			if (newsize == 0) {
29445916cd2Sjpk 				/*
29545916cd2Sjpk 				 * If zone name was the only key/value pair,
29645916cd2Sjpk 				 * put 'reserved' in the empty slot.
29745916cd2Sjpk 				 */
29845916cd2Sjpk 				_kva_free(oldkva);
29945916cd2Sjpk 				dap->da_devopts = NULL;
30045916cd2Sjpk 				return;
30145916cd2Sjpk 			}
30245916cd2Sjpk 		} else {
30345916cd2Sjpk 			return;
30445916cd2Sjpk 		}
30545916cd2Sjpk 	}
30645916cd2Sjpk 	newkva = _new_kva(newsize);
30745916cd2Sjpk 	newkva->length = 0;
30845916cd2Sjpk 	newdata = newkva->data;
30945916cd2Sjpk 	olddata = oldkva->data;
31045916cd2Sjpk 	for (i = 0, j = 0; i < oldsize; i++) {
31145916cd2Sjpk 		if ((dargs->optflag & DA_REMOVE_ZONE) &&
31245916cd2Sjpk 		    (strcmp(olddata[i].key, DAOPT_ZONE) == 0))
31345916cd2Sjpk 			continue;
31445916cd2Sjpk 		newdata[j].key = strdup(olddata[i].key);
31545916cd2Sjpk 		newdata[j].value = strdup(olddata[i].value);
31645916cd2Sjpk 		newkva->length++;
31745916cd2Sjpk 		j++;
31845916cd2Sjpk 	}
31945916cd2Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
32045916cd2Sjpk 		newdata[j].key = strdup(DAOPT_ZONE);
32145916cd2Sjpk 		newdata[j].value = strdup(zonename);
32245916cd2Sjpk 		newkva->length++;
32345916cd2Sjpk 	}
32445916cd2Sjpk 	_kva_free(oldkva);
32545916cd2Sjpk 	dap->da_devopts = newkva;
32645916cd2Sjpk }
32745916cd2Sjpk 
32845916cd2Sjpk /*
32945916cd2Sjpk  * _dmap2str -
33045916cd2Sjpk  *	converts a device_map entry into a printable string
33145916cd2Sjpk  *	returns 0 on success, -1 on error.
33245916cd2Sjpk  */
33345916cd2Sjpk /*ARGSUSED*/
33445916cd2Sjpk static int
33545916cd2Sjpk _dmap2str(da_args *dargs, devmap_t *dmp, char *buf, int size, const char *sep)
33645916cd2Sjpk {
33745916cd2Sjpk 	int	length;
33845916cd2Sjpk 
33945916cd2Sjpk 	length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep);
34045916cd2Sjpk 	if (length >= size)
34145916cd2Sjpk 		return (-1);
34245916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
34345916cd2Sjpk 	    dmp->dmap_devtype, sep);
34445916cd2Sjpk 	if (length >= size)
34545916cd2Sjpk 		return (-1);
34645916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
34745916cd2Sjpk 	    dmp->dmap_devlist);
34845916cd2Sjpk 	if (length >= size)
34945916cd2Sjpk 		return (-1);
35045916cd2Sjpk 	return (0);
35145916cd2Sjpk }
35245916cd2Sjpk 
35345916cd2Sjpk /*
35445916cd2Sjpk  * _dmap2strentry -
35545916cd2Sjpk  *	calls dmap2str to break given devmap_t into printable entry.
35645916cd2Sjpk  *	returns pointer to decoded entry, NULL on error.
35745916cd2Sjpk  */
35845916cd2Sjpk static strentry_t *
35945916cd2Sjpk _dmap2strentry(da_args *dargs, devmap_t *devmapp)
36045916cd2Sjpk {
36145916cd2Sjpk 	strentry_t	*sep;
36245916cd2Sjpk 
36345916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
36445916cd2Sjpk 		return (NULL);
36545916cd2Sjpk 	if (_dmap2str(dargs, devmapp, sep->se_str, sizeof (sep->se_str),
36645916cd2Sjpk 	    KV_TOKEN_DELIMIT"\\\n\t") != 0) {
36745916cd2Sjpk 		free(sep);
36845916cd2Sjpk 		return (NULL);
36945916cd2Sjpk 	}
37045916cd2Sjpk 	return (sep);
37145916cd2Sjpk }
37245916cd2Sjpk 
37345916cd2Sjpk /*
37445916cd2Sjpk  * fix_optstr -
37545916cd2Sjpk  * 	removes trailing ':' from buf.
37645916cd2Sjpk  */
37745916cd2Sjpk void
37845916cd2Sjpk fix_optstr(char *buf)
37945916cd2Sjpk {
38045916cd2Sjpk 	char	*p = NULL;
38145916cd2Sjpk 
38245916cd2Sjpk 	if (p = rindex(buf, ':'))
38345916cd2Sjpk 		*p = ';';
38445916cd2Sjpk }
38545916cd2Sjpk 
38645916cd2Sjpk /*
38745916cd2Sjpk  * _da2str -
38845916cd2Sjpk  *	converts a device_allocate entry into a printable string
38945916cd2Sjpk  *	returns 0 on success, -1 on error.
39045916cd2Sjpk  */
39145916cd2Sjpk static int
39245916cd2Sjpk _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep,
39345916cd2Sjpk     const char *osep)
39445916cd2Sjpk {
39545916cd2Sjpk 	int	length;
39645916cd2Sjpk 	int	matching_entry = 0;
39745916cd2Sjpk 	char	**dnames;
39845916cd2Sjpk 
39945916cd2Sjpk 	if (dargs->optflag & DA_UPDATE &&
40045916cd2Sjpk 	    (dargs->optflag & DA_ADD_ZONE ||
40145916cd2Sjpk 	    dargs->optflag & DA_REMOVE_ZONE) &&
40245916cd2Sjpk 	    dargs->devnames) {
40345916cd2Sjpk 		for (dnames = dargs->devnames; *dnames != NULL; dnames++) {
40445916cd2Sjpk 			if (da_matchname(dap, *dnames)) {
40545916cd2Sjpk 				matching_entry = 1;
40645916cd2Sjpk 				break;
40745916cd2Sjpk 			}
40845916cd2Sjpk 		}
40945916cd2Sjpk 	}
41045916cd2Sjpk 	length = snprintf(buf, size, "%s%s", dap->da_devname, sep);
41145916cd2Sjpk 	if (length >= size)
41245916cd2Sjpk 		return (-1);
41345916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
41445916cd2Sjpk 	    dap->da_devtype, sep);
41545916cd2Sjpk 	if (length >= size)
41645916cd2Sjpk 		return (-1);
41745916cd2Sjpk 	if (matching_entry)
41845916cd2Sjpk 		_update_zonename(dargs, dap);
41945916cd2Sjpk 	if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) &&
42045916cd2Sjpk 	    (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) {
42145916cd2Sjpk 		length += snprintf(buf + length, size - length, "%s%s",
42245916cd2Sjpk 		    DA_RESERVED, sep);
42345916cd2Sjpk 	} else {
42445916cd2Sjpk 		if (_kva2str(dap->da_devopts, buf + length, size - length,
42545916cd2Sjpk 		    KV_ASSIGN, (char *)osep) != 0)
42645916cd2Sjpk 			return (-1);
42745916cd2Sjpk 		length = strlen(buf);
42845916cd2Sjpk 	}
42945916cd2Sjpk 	if (dap->da_devopts)
43045916cd2Sjpk 		fix_optstr(buf);
43145916cd2Sjpk 	if (length >= size)
43245916cd2Sjpk 		return (-1);
43345916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
43445916cd2Sjpk 	    DA_RESERVED, sep);
43545916cd2Sjpk 	if (length >= size)
43645916cd2Sjpk 		return (-1);
43745916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
43845916cd2Sjpk 	    dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep);
43945916cd2Sjpk 	if (length >= size)
44045916cd2Sjpk 		return (-1);
44145916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
44245916cd2Sjpk 	    dap->da_devexec ? dap->da_devexec : "");
44345916cd2Sjpk 	if (length >= size)
44445916cd2Sjpk 		return (-1);
44545916cd2Sjpk 
44645916cd2Sjpk 	return (0);
44745916cd2Sjpk }
44845916cd2Sjpk 
44945916cd2Sjpk /*
45045916cd2Sjpk  * _da2strentry -
45145916cd2Sjpk  *	calls da2str to break given devalloc_t into printable entry.
45245916cd2Sjpk  *	returns pointer to decoded entry, NULL on error.
45345916cd2Sjpk  */
45445916cd2Sjpk static strentry_t *
45545916cd2Sjpk _da2strentry(da_args *dargs, devalloc_t *dap)
45645916cd2Sjpk {
45745916cd2Sjpk 	strentry_t	*sep;
45845916cd2Sjpk 
45945916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
46045916cd2Sjpk 		return (NULL);
46145916cd2Sjpk 	if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str),
46245916cd2Sjpk 	    KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) {
46345916cd2Sjpk 		free(sep);
46445916cd2Sjpk 		return (NULL);
46545916cd2Sjpk 	}
46645916cd2Sjpk 	return (sep);
46745916cd2Sjpk }
46845916cd2Sjpk 
46945916cd2Sjpk /*
47045916cd2Sjpk  * _def2str
47145916cd2Sjpk  *	converts da_defs_t into a printable string.
47245916cd2Sjpk  *	returns 0 on success, -1 on error.
47345916cd2Sjpk  */
47445916cd2Sjpk static int
47545916cd2Sjpk _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep)
47645916cd2Sjpk {
47745916cd2Sjpk 	int length;
47845916cd2Sjpk 
47945916cd2Sjpk 	length = snprintf(buf, size, "%s%s", da_defs->devtype, sep);
48045916cd2Sjpk 	if (length >= size)
48145916cd2Sjpk 		return (-1);
48245916cd2Sjpk 	if (da_defs->devopts) {
48345916cd2Sjpk 		if (_kva2str(da_defs->devopts, buf + length, size - length,
48445916cd2Sjpk 		    KV_ASSIGN, KV_DELIMITER) != 0)
48545916cd2Sjpk 			return (-1);
48645916cd2Sjpk 		length = strlen(buf);
48745916cd2Sjpk 	}
48845916cd2Sjpk 	if (length >= size)
48945916cd2Sjpk 		return (-1);
49045916cd2Sjpk 
49145916cd2Sjpk 	return (0);
49245916cd2Sjpk }
49345916cd2Sjpk 
49445916cd2Sjpk /*
49545916cd2Sjpk  * _def2strentry
49645916cd2Sjpk  *	calls _def2str to break given da_defs_t into printable entry.
49745916cd2Sjpk  *	returns pointer decoded entry, NULL on error.
49845916cd2Sjpk  */
49945916cd2Sjpk static strentry_t *
50045916cd2Sjpk _def2strentry(da_defs_t *da_defs)
50145916cd2Sjpk {
50245916cd2Sjpk 	strentry_t	*sep;
50345916cd2Sjpk 
50445916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
50545916cd2Sjpk 		return (NULL);
50645916cd2Sjpk 	if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str),
50745916cd2Sjpk 	    KV_TOKEN_DELIMIT) != 0) {
50845916cd2Sjpk 		free(sep);
50945916cd2Sjpk 		return (NULL);
51045916cd2Sjpk 	}
51145916cd2Sjpk 
51245916cd2Sjpk 	return (sep);
51345916cd2Sjpk }
51445916cd2Sjpk 
51545916cd2Sjpk /*
51645916cd2Sjpk  * _build_defattrs
51745916cd2Sjpk  *	cycles through all defattr entries, stores them in memory. removes
51845916cd2Sjpk  *	entries with the given search_key (device type).
51945916cd2Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
52045916cd2Sjpk  *	error.
52145916cd2Sjpk  */
52245916cd2Sjpk static int
52345916cd2Sjpk _build_defattrs(da_args *dargs, strentry_t **head_defent)
52445916cd2Sjpk {
52545916cd2Sjpk 	int		rc = 0;
52645916cd2Sjpk 	da_defs_t	*da_defs;
52745916cd2Sjpk 	strentry_t	*tail_str, *tmp_str;
52845916cd2Sjpk 
52945916cd2Sjpk 	setdadefent();
53045916cd2Sjpk 	while ((da_defs = getdadefent()) != NULL) {
53145916cd2Sjpk 		rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype));
53245916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
53345916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
53445916cd2Sjpk 			/*
53545916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
53645916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
53745916cd2Sjpk 			 */
53845916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
53945916cd2Sjpk 			rc = 0;
54045916cd2Sjpk 		}
54145916cd2Sjpk 		if (rc == 0) {
54245916cd2Sjpk 			tmp_str = _def2strentry(da_defs);
54345916cd2Sjpk 			if (tmp_str == NULL) {
54445916cd2Sjpk 				freedadefent(da_defs);
54545916cd2Sjpk 				enddadefent();
54645916cd2Sjpk 				return (2);
54745916cd2Sjpk 			}
54845916cd2Sjpk 			/* retaining defattr entry: tmp_str->se_str */
54945916cd2Sjpk 			tmp_str->se_next = NULL;
55045916cd2Sjpk 			if (*head_defent == NULL) {
55145916cd2Sjpk 				*head_defent = tail_str = tmp_str;
55245916cd2Sjpk 			} else {
55345916cd2Sjpk 				tail_str->se_next = tmp_str;
55445916cd2Sjpk 				tail_str = tmp_str;
55545916cd2Sjpk 			}
55645916cd2Sjpk 		}
55745916cd2Sjpk 		freedadefent(da_defs);
55845916cd2Sjpk 	}
55945916cd2Sjpk 	enddadefent();
56045916cd2Sjpk 
56145916cd2Sjpk 	return (rc);
56245916cd2Sjpk }
56345916cd2Sjpk 
56445916cd2Sjpk /*
56545916cd2Sjpk  * _build_lists -
56645916cd2Sjpk  *	cycles through all the entries, stores them in memory. removes entries
56745916cd2Sjpk  *	with the given search_key (device name or type).
56845916cd2Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
56945916cd2Sjpk  *	error.
57045916cd2Sjpk  */
57145916cd2Sjpk static int
57245916cd2Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp,
57345916cd2Sjpk     strentry_t **head_devmapp)
57445916cd2Sjpk {
57545916cd2Sjpk 	int		rc = 0;
57645916cd2Sjpk 	devalloc_t	*devallocp;
57745916cd2Sjpk 	devmap_t	*devmapp;
57845916cd2Sjpk 	strentry_t	*tail_str;
57945916cd2Sjpk 	strentry_t	*tmp_str;
58045916cd2Sjpk 
58145916cd2Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
58245916cd2Sjpk 		goto dmap_only;
58345916cd2Sjpk 
58445916cd2Sjpk 	/* build device_allocate */
58545916cd2Sjpk 	setdaent();
58645916cd2Sjpk 	while ((devallocp = getdaent()) != NULL) {
58745916cd2Sjpk 		rc = da_match(devallocp, dargs);
58845916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
58945916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
59045916cd2Sjpk 			/*
59145916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
59245916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
59345916cd2Sjpk 			 */
59445916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
59545916cd2Sjpk 			rc = 0;
59645916cd2Sjpk 		}
59745916cd2Sjpk 		if (rc == 0) {
59845916cd2Sjpk 			tmp_str = _da2strentry(dargs, devallocp);
59945916cd2Sjpk 			if (tmp_str == NULL) {
60045916cd2Sjpk 				freedaent(devallocp);
60145916cd2Sjpk 				enddaent();
60245916cd2Sjpk 				return (2);
60345916cd2Sjpk 			}
60445916cd2Sjpk 			/* retaining devalloc entry: tmp_str->se_str */
60545916cd2Sjpk 			tmp_str->se_next = NULL;
60645916cd2Sjpk 			if (*head_devallocp == NULL) {
60745916cd2Sjpk 				*head_devallocp = tail_str = tmp_str;
60845916cd2Sjpk 			} else {
60945916cd2Sjpk 				tail_str->se_next = tmp_str;
61045916cd2Sjpk 				tail_str = tmp_str;
61145916cd2Sjpk 			}
61245916cd2Sjpk 		}
61345916cd2Sjpk 		freedaent(devallocp);
61445916cd2Sjpk 	}
61545916cd2Sjpk 	enddaent();
61645916cd2Sjpk 
61745916cd2Sjpk dmap_only:
61845916cd2Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
61945916cd2Sjpk 		return (rc);
62045916cd2Sjpk 
62145916cd2Sjpk 	/* build device_maps */
62245916cd2Sjpk 	rc = 0;
62345916cd2Sjpk 	setdmapent();
62445916cd2Sjpk 	while ((devmapp = getdmapent()) != NULL) {
62545916cd2Sjpk 		rc = dm_match(devmapp, dargs);
62645916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
62745916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
62845916cd2Sjpk 			/*
62945916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
63045916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
63145916cd2Sjpk 			 */
63245916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
63345916cd2Sjpk 			rc = 0;
63445916cd2Sjpk 		}
63545916cd2Sjpk 		if (rc == 0) {
63645916cd2Sjpk 			tmp_str = _dmap2strentry(dargs, devmapp);
63745916cd2Sjpk 			if (tmp_str == NULL) {
63845916cd2Sjpk 				freedmapent(devmapp);
63945916cd2Sjpk 				enddmapent();
64045916cd2Sjpk 				return (2);
64145916cd2Sjpk 			}
64245916cd2Sjpk 			/* retaining devmap entry: tmp_str->se_str */
64345916cd2Sjpk 			tmp_str->se_next = NULL;
64445916cd2Sjpk 			if (*head_devmapp == NULL) {
64545916cd2Sjpk 				*head_devmapp = tail_str = tmp_str;
64645916cd2Sjpk 			} else {
64745916cd2Sjpk 				tail_str->se_next = tmp_str;
64845916cd2Sjpk 				tail_str = tmp_str;
64945916cd2Sjpk 			}
65045916cd2Sjpk 		}
65145916cd2Sjpk 		freedmapent(devmapp);
65245916cd2Sjpk 	}
65345916cd2Sjpk 	enddmapent();
65445916cd2Sjpk 
65545916cd2Sjpk 	return (rc);
65645916cd2Sjpk }
65745916cd2Sjpk 
65845916cd2Sjpk /*
65945916cd2Sjpk  * _write_defattrs
66045916cd2Sjpk  *	writes current entries to devalloc_defaults.
66145916cd2Sjpk  */
66245916cd2Sjpk static void
66345916cd2Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent)
66445916cd2Sjpk {
66545916cd2Sjpk 	strentry_t *tmp_str;
66645916cd2Sjpk 
66745916cd2Sjpk 	for (tmp_str = head_defent; tmp_str != NULL;
66845916cd2Sjpk 	    tmp_str = tmp_str->se_next) {
66945916cd2Sjpk 		(void) fputs(tmp_str->se_str, fp);
67045916cd2Sjpk 		(void) fputs("\n", fp);
67145916cd2Sjpk 	}
67245916cd2Sjpk 
67345916cd2Sjpk }
67445916cd2Sjpk 
67545916cd2Sjpk /*
67645916cd2Sjpk  * _write_device_allocate -
67745916cd2Sjpk  *	writes current entries in the list to device_allocate.
67845916cd2Sjpk  */
67945916cd2Sjpk static void
68045916cd2Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
68145916cd2Sjpk {
68245916cd2Sjpk 	int		is_on = -1;
68345916cd2Sjpk 	strentry_t	*tmp_str;
68445916cd2Sjpk 	struct stat	dastat;
68545916cd2Sjpk 
68645916cd2Sjpk 	(void) fseek(dafp, (off_t)0, SEEK_SET);
68745916cd2Sjpk 
68845916cd2Sjpk 	/*
68945916cd2Sjpk 	 * if the devalloc on/off string existed before,
69045916cd2Sjpk 	 * put it back before anything else.
69145916cd2Sjpk 	 * we need to check for the string only if the file
69245916cd2Sjpk 	 * exists.
69345916cd2Sjpk 	 */
69445916cd2Sjpk 	if (stat(odevalloc, &dastat) == 0) {
69545916cd2Sjpk 		is_on = da_is_on();
69645916cd2Sjpk 		if (is_on == 0)
69745916cd2Sjpk 			(void) fputs(DA_OFF_STR, dafp);
69845916cd2Sjpk 		else if (is_on == 1)
69945916cd2Sjpk 			(void) fputs(DA_ON_STR, dafp);
70045916cd2Sjpk 	}
70145916cd2Sjpk 	tmp_str = head_devallocp;
70245916cd2Sjpk 	while (tmp_str) {
70345916cd2Sjpk 		(void) fputs(tmp_str->se_str, dafp);
70445916cd2Sjpk 		(void) fputs("\n", dafp);
70545916cd2Sjpk 		tmp_str = tmp_str->se_next;
70645916cd2Sjpk 	}
70745916cd2Sjpk }
70845916cd2Sjpk 
70945916cd2Sjpk /*
71045916cd2Sjpk  * _write_device_maps -
71145916cd2Sjpk  *	writes current entries in the list to device_maps.
71245916cd2Sjpk  */
71345916cd2Sjpk static void
71445916cd2Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
71545916cd2Sjpk {
71645916cd2Sjpk 	strentry_t	*tmp_str;
71745916cd2Sjpk 
71845916cd2Sjpk 	(void) fseek(dmfp, (off_t)0, SEEK_SET);
71945916cd2Sjpk 
72045916cd2Sjpk 	tmp_str = head_devmapp;
72145916cd2Sjpk 	while (tmp_str) {
72245916cd2Sjpk 		(void) fputs(tmp_str->se_str, dmfp);
72345916cd2Sjpk 		(void) fputs("\n", dmfp);
72445916cd2Sjpk 		tmp_str = tmp_str->se_next;
72545916cd2Sjpk 	}
72645916cd2Sjpk }
72745916cd2Sjpk 
72845916cd2Sjpk /*
72945916cd2Sjpk  * _write_new_defattrs
73045916cd2Sjpk  *	writes the new entry to devalloc_defaults.
73145916cd2Sjpk  *	returns 0 on success, -1 on error.
73245916cd2Sjpk  */
73345916cd2Sjpk static int
73445916cd2Sjpk _write_new_defattrs(FILE *fp, da_args *dargs)
73545916cd2Sjpk {
73645916cd2Sjpk 	int		count;
73745916cd2Sjpk 	char		*tok = NULL, *tokp = NULL;
73845916cd2Sjpk 	char		*lasts;
73945916cd2Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
74045916cd2Sjpk 
74145916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
74245916cd2Sjpk 		return (-1);
74345916cd2Sjpk 	if (!devinfo->devopts)
74445916cd2Sjpk 		return (0);
74545916cd2Sjpk 	(void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
74645916cd2Sjpk 	    KV_TOKEN_DELIMIT);
74745916cd2Sjpk 	if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) {
74845916cd2Sjpk 		(void) strcpy(tokp, devinfo->devopts);
74945916cd2Sjpk 		if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) {
75045916cd2Sjpk 			(void) fprintf(fp, "%s", tok);
75145916cd2Sjpk 			count = 1;
75245916cd2Sjpk 		}
75345916cd2Sjpk 		while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
75445916cd2Sjpk 			if (count)
75545916cd2Sjpk 				(void) fprintf(fp, "%s", KV_DELIMITER);
75645916cd2Sjpk 			(void) fprintf(fp, "%s", tok);
75745916cd2Sjpk 			count++;
75845916cd2Sjpk 		}
75945916cd2Sjpk 	} else {
76045916cd2Sjpk 		(void) fprintf(fp, "%s", devinfo->devopts);
76145916cd2Sjpk 	}
76245916cd2Sjpk 
76345916cd2Sjpk 	return (0);
76445916cd2Sjpk }
76545916cd2Sjpk 
76645916cd2Sjpk /*
76745916cd2Sjpk  * _write_new_entry -
76845916cd2Sjpk  *	writes the new devalloc_t to device_allocate or the new devmap_t to
76945916cd2Sjpk  *	device_maps.
77045916cd2Sjpk  *	returns 0 on success, -1 on error.
77145916cd2Sjpk  */
77245916cd2Sjpk static int
77345916cd2Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag)
77445916cd2Sjpk {
77545916cd2Sjpk 	int		count;
77645916cd2Sjpk 	char		*tok = NULL, *tokp = NULL;
77745916cd2Sjpk 	char		*lasts;
77845916cd2Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
77945916cd2Sjpk 
78045916cd2Sjpk 	if (flag & DA_MAPS_ONLY)
78145916cd2Sjpk 		goto dmap_only;
78245916cd2Sjpk 
78345916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
78445916cd2Sjpk 		return (-1);
78545916cd2Sjpk 
78645916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
78745916cd2Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
78845916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
78945916cd2Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
79045916cd2Sjpk 	if (devinfo->devopts == NULL) {
79145916cd2Sjpk 		(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
79245916cd2Sjpk 		    KV_DELIMITER);
79345916cd2Sjpk 	} else {
79445916cd2Sjpk 		if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) {
79545916cd2Sjpk 			(void) strcpy(tokp, devinfo->devopts);
79645916cd2Sjpk 			if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
79745916cd2Sjpk 			    NULL) {
79845916cd2Sjpk 				(void) fprintf(fp, "%s", tok);
79945916cd2Sjpk 				count = 1;
80045916cd2Sjpk 			}
80145916cd2Sjpk 			while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
80245916cd2Sjpk 			    &lasts)) != NULL) {
80345916cd2Sjpk 				if (count)
80445916cd2Sjpk 					(void) fprintf(fp, "%s",
80545916cd2Sjpk 					    KV_TOKEN_DELIMIT "\\\n\t");
80645916cd2Sjpk 				(void) fprintf(fp, "%s", tok);
80745916cd2Sjpk 				count++;
80845916cd2Sjpk 			}
80945916cd2Sjpk 			if (count)
81045916cd2Sjpk 				(void) fprintf(fp, "%s",
81145916cd2Sjpk 				    KV_DELIMITER "\\\n\t");
81245916cd2Sjpk 		} else {
81345916cd2Sjpk 			(void) fprintf(fp, "%s%s", devinfo->devopts,
81445916cd2Sjpk 			    KV_DELIMITER "\\\n\t");
81545916cd2Sjpk 		}
81645916cd2Sjpk 	}
81745916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
81845916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
81945916cd2Sjpk 	    (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
82045916cd2Sjpk 	    KV_DELIMITER);
82145916cd2Sjpk 	(void) fprintf(fp, "%s\n",
82245916cd2Sjpk 	    (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
82345916cd2Sjpk 
82445916cd2Sjpk dmap_only:
82545916cd2Sjpk 	if (flag & DA_ALLOC_ONLY)
82645916cd2Sjpk 		return (0);
82745916cd2Sjpk 
82845916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
82945916cd2Sjpk 		return (-1);
83045916cd2Sjpk 
83145916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n",
83245916cd2Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
83345916cd2Sjpk 	(void) fprintf(fp, "\t%s%s\\\n",
83445916cd2Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
83545916cd2Sjpk 	(void) fprintf(fp, "\t%s\n",
83645916cd2Sjpk 	    (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
83745916cd2Sjpk 
83845916cd2Sjpk 	return (0);
83945916cd2Sjpk }
84045916cd2Sjpk 
84145916cd2Sjpk /*
84245916cd2Sjpk  * _da_lock_devdb -
84345916cd2Sjpk  *	locks the database files; lock can be either broken explicitly by
84445916cd2Sjpk  *	closing the fd of the lock file, or it expires automatically at process
84545916cd2Sjpk  *	termination.
84645916cd2Sjpk  * 	returns fd of the lock file or -1 on error.
84745916cd2Sjpk  */
84845916cd2Sjpk int
84945916cd2Sjpk _da_lock_devdb(char *rootdir)
85045916cd2Sjpk {
85145916cd2Sjpk 	int		lockfd = -1;
852*10ddde3aSaj 	int		ret;
853*10ddde3aSaj 	int		count = 0;
854*10ddde3aSaj 	int		retry = 10;
855*10ddde3aSaj 	int		retry_sleep;
856*10ddde3aSaj 	uint_t		seed;
85745916cd2Sjpk 	char		*lockfile;
85845916cd2Sjpk 	char		path[MAXPATHLEN];
85945916cd2Sjpk 	int		size = sizeof (path);
86045916cd2Sjpk 
86145916cd2Sjpk 	if (rootdir == NULL) {
86245916cd2Sjpk 		lockfile = DA_DB_LOCK;
86345916cd2Sjpk 	} else {
86445916cd2Sjpk 		path[0] = '\0';
86545916cd2Sjpk 		if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
86645916cd2Sjpk 			return (-1);
86745916cd2Sjpk 		lockfile = path;
86845916cd2Sjpk 	}
86945916cd2Sjpk 
87045916cd2Sjpk 	if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
87145916cd2Sjpk 		/* cannot open lock file */
87245916cd2Sjpk 		return (-1);
87345916cd2Sjpk 
87445916cd2Sjpk 	(void) fchown(lockfd, DA_UID, DA_GID);
87545916cd2Sjpk 
87645916cd2Sjpk 	if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
87745916cd2Sjpk 		/* cannot position lock file */
87845916cd2Sjpk 		(void) close(lockfd);
87945916cd2Sjpk 		return (-1);
88045916cd2Sjpk 	}
881*10ddde3aSaj 	errno = 0;
882*10ddde3aSaj 	while (retry > 0) {
883*10ddde3aSaj 		count++;
884*10ddde3aSaj 		seed = (uint_t)gethrtime();
885*10ddde3aSaj 		ret = lockf(lockfd, F_TLOCK, 0);
886*10ddde3aSaj 		if (ret == 0) {
887*10ddde3aSaj 			(void) utime(lockfile, NULL);
888*10ddde3aSaj 			return (lockfd);
889*10ddde3aSaj 		}
890*10ddde3aSaj 		if ((errno != EACCES) && (errno != EAGAIN)) {
89145916cd2Sjpk 			/* cannot set lock */
89245916cd2Sjpk 			(void) close(lockfd);
89345916cd2Sjpk 			return (-1);
89445916cd2Sjpk 		}
895*10ddde3aSaj 		retry--;
896*10ddde3aSaj 		retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count;
897*10ddde3aSaj 		(void) sleep(retry_sleep);
898*10ddde3aSaj 		errno = 0;
899*10ddde3aSaj 	}
90045916cd2Sjpk 
901*10ddde3aSaj 	return (-1);
90245916cd2Sjpk }
90345916cd2Sjpk 
90445916cd2Sjpk /*
90545916cd2Sjpk  * da_open_devdb -
90645916cd2Sjpk  *	opens one or both database files - device_allocate, device_maps - in
90745916cd2Sjpk  *	the specified mode.
90845916cd2Sjpk  *	locks the database files; lock is either broken explicitly by the
90945916cd2Sjpk  *	caller by closing the lock file fd, or it expires automatically at
91045916cd2Sjpk  *	process termination.
91145916cd2Sjpk  *	writes the file pointer of opened file in the input args - dafp, dmfp.
91245916cd2Sjpk  *	returns fd of the lock file on success, -2 if database file does not
91345916cd2Sjpk  *	exist, -1 on other errors.
91445916cd2Sjpk  */
91545916cd2Sjpk int
91645916cd2Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
91745916cd2Sjpk {
91845916cd2Sjpk 	int	oflag = 0;
91945916cd2Sjpk 	int	fda = -1;
92045916cd2Sjpk 	int	fdm = -1;
92145916cd2Sjpk 	int	lockfd = -1;
92245916cd2Sjpk 	char	*fname;
92345916cd2Sjpk 	char	*fmode;
92445916cd2Sjpk 	char	path[MAXPATHLEN];
92545916cd2Sjpk 	FILE	*devfile;
92645916cd2Sjpk 
92745916cd2Sjpk 	if ((dafp == NULL) && (dmfp == NULL))
92845916cd2Sjpk 		return (-1);
92945916cd2Sjpk 
93045916cd2Sjpk 	if (flag & DA_RDWR) {
93145916cd2Sjpk 		oflag = DA_RDWR;
932004388ebScasper 		fmode = "r+F";
93345916cd2Sjpk 	} else if (flag & DA_RDONLY) {
93445916cd2Sjpk 		oflag = DA_RDONLY;
935004388ebScasper 		fmode = "rF";
93645916cd2Sjpk 	}
93745916cd2Sjpk 
93845916cd2Sjpk 	if ((lockfd = _da_lock_devdb(rootdir)) == -1)
93945916cd2Sjpk 		return (-1);
94045916cd2Sjpk 
94145916cd2Sjpk 	if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
94245916cd2Sjpk 		goto dmap_only;
94345916cd2Sjpk 
94445916cd2Sjpk 	path[0] = '\0';
94545916cd2Sjpk 
94645916cd2Sjpk 	/*
94745916cd2Sjpk 	 * open the device allocation file
94845916cd2Sjpk 	 */
94945916cd2Sjpk 	if (rootdir == NULL) {
95045916cd2Sjpk 		fname = DEVALLOC;
95145916cd2Sjpk 	} else {
95245916cd2Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
95345916cd2Sjpk 		    DEVALLOC) >= sizeof (path)) {
95445916cd2Sjpk 			if (lockfd != -1)
95545916cd2Sjpk 				(void) close(lockfd);
95645916cd2Sjpk 			return (-1);
95745916cd2Sjpk 		}
95845916cd2Sjpk 		fname = path;
95945916cd2Sjpk 	}
96045916cd2Sjpk 	if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
96145916cd2Sjpk 		if (lockfd != -1)
96245916cd2Sjpk 			(void) close(lockfd);
96345916cd2Sjpk 		return ((errno == ENOENT) ? -2 : -1);
96445916cd2Sjpk 	}
96545916cd2Sjpk 	if ((devfile = fdopen(fda, fmode)) == NULL) {
96645916cd2Sjpk 		(void) close(fda);
96745916cd2Sjpk 		if (lockfd != -1)
96845916cd2Sjpk 			(void) close(lockfd);
96945916cd2Sjpk 		return (-1);
97045916cd2Sjpk 	}
97145916cd2Sjpk 	*dafp = devfile;
97245916cd2Sjpk 	(void) fchmod(fda, DA_DBMODE);
97345916cd2Sjpk 
97445916cd2Sjpk 	if ((flag & DA_ALLOC_ONLY))
97545916cd2Sjpk 		goto out;
97645916cd2Sjpk 
97745916cd2Sjpk dmap_only:
97845916cd2Sjpk 	path[0] = '\0';
97945916cd2Sjpk 	/*
98045916cd2Sjpk 	 * open the device map file
98145916cd2Sjpk 	 */
98245916cd2Sjpk 	if (rootdir == NULL) {
98345916cd2Sjpk 		fname = DEVMAP;
98445916cd2Sjpk 	} else {
98545916cd2Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
98645916cd2Sjpk 		    DEVMAP) >= sizeof (path)) {
98745916cd2Sjpk 			(void) close(fda);
98845916cd2Sjpk 			if (lockfd != -1)
98945916cd2Sjpk 				(void) close(lockfd);
99045916cd2Sjpk 			return (-1);
99145916cd2Sjpk 		}
99245916cd2Sjpk 		fname = path;
99345916cd2Sjpk 	}
99445916cd2Sjpk 
99545916cd2Sjpk 	if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
99645916cd2Sjpk 		if (lockfd != -1)
99745916cd2Sjpk 			(void) close(lockfd);
99845916cd2Sjpk 		return ((errno == ENOENT) ? -2 : -1);
99945916cd2Sjpk 	}
100045916cd2Sjpk 
100145916cd2Sjpk 	if ((devfile = fdopen(fdm, fmode)) == NULL) {
100245916cd2Sjpk 		(void) close(fdm);
100345916cd2Sjpk 		(void) close(fda);
100445916cd2Sjpk 		if (lockfd != -1)
100545916cd2Sjpk 			(void) close(lockfd);
100645916cd2Sjpk 		return (-1);
100745916cd2Sjpk 	}
100845916cd2Sjpk 	*dmfp = devfile;
100945916cd2Sjpk 	(void) fchmod(fdm, DA_DBMODE);
101045916cd2Sjpk 
101145916cd2Sjpk out:
101245916cd2Sjpk 	return (lockfd);
101345916cd2Sjpk }
101445916cd2Sjpk 
101545916cd2Sjpk /*
101645916cd2Sjpk  * _record_on_off -
101745916cd2Sjpk  *	adds either DA_ON_STR or DA_OFF_STR to device_allocate
101845916cd2Sjpk  *	returns 0 on success, -1 on error.
101945916cd2Sjpk  */
102045916cd2Sjpk static int
102145916cd2Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
102245916cd2Sjpk {
102345916cd2Sjpk 	int		dafd;
102445916cd2Sjpk 	int		nsize;
102545916cd2Sjpk 	int		nitems = 1;
102645916cd2Sjpk 	int		actionlen;
102745916cd2Sjpk 	int		str_found = 0;
102845916cd2Sjpk 	int		len = 0, nlen = 0, plen = 0;
102945916cd2Sjpk 	char		*ptr = NULL;
103045916cd2Sjpk 	char		*actionstr;
103145916cd2Sjpk 	char		*nbuf = NULL;
103245916cd2Sjpk 	char		line[MAX_CANON];
103345916cd2Sjpk 	struct stat	dastat;
103445916cd2Sjpk 
103545916cd2Sjpk 	if (dargs->optflag & DA_ON)
103645916cd2Sjpk 		actionstr = DA_ON_STR;
103745916cd2Sjpk 	else
103845916cd2Sjpk 		actionstr = DA_OFF_STR;
103945916cd2Sjpk 	actionlen = strlen(actionstr);
104045916cd2Sjpk 	dafd = fileno(dafp);
104145916cd2Sjpk 	if (fstat(dafd, &dastat) == -1)
104245916cd2Sjpk 		return (-1);
104345916cd2Sjpk 
104445916cd2Sjpk 	/* check the old device_allocate for on/off string */
104545916cd2Sjpk 	ptr = fgets(line, MAX_CANON, dafp);
104645916cd2Sjpk 	if (ptr != NULL) {
104745916cd2Sjpk 		if ((strcmp(line, DA_ON_STR) == 0) ||
104845916cd2Sjpk 		    (strcmp(line, DA_OFF_STR) == 0)) {
104945916cd2Sjpk 			str_found = 1;
105045916cd2Sjpk 			nsize = dastat.st_size;
105145916cd2Sjpk 		}
105245916cd2Sjpk 	}
105345916cd2Sjpk 	if (!ptr || !str_found) {
105445916cd2Sjpk 		/*
105545916cd2Sjpk 		 * the file never had either the on or the off string;
105645916cd2Sjpk 		 * make room for it.
105745916cd2Sjpk 		 */
105845916cd2Sjpk 		str_found = 0;
105945916cd2Sjpk 		nsize = dastat.st_size + actionlen + 1;
106045916cd2Sjpk 	}
106145916cd2Sjpk 	if ((nbuf = (char *)malloc(nsize)) == NULL)
106245916cd2Sjpk 		return (-1);
106345916cd2Sjpk 	nbuf[0] = '\0';
106445916cd2Sjpk 	/* put the on/off string */
106545916cd2Sjpk 	(void) strcpy(nbuf, actionstr);
106645916cd2Sjpk 	nlen = strlen(nbuf);
106745916cd2Sjpk 	plen = nlen;
106845916cd2Sjpk 	if (ptr && !str_found) {
106945916cd2Sjpk 		/* now put the first line that we read in fgets */
107045916cd2Sjpk 		nlen = plen + strlen(line) + 1;
107145916cd2Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
107245916cd2Sjpk 		if (len >= nsize) {
107345916cd2Sjpk 			free(nbuf);
107445916cd2Sjpk 			return (-1);
107545916cd2Sjpk 		}
107645916cd2Sjpk 		plen += len;
107745916cd2Sjpk 	}
107845916cd2Sjpk 
107945916cd2Sjpk 	/* now get the rest of the old file */
108045916cd2Sjpk 	while (fgets(line, MAX_CANON, dafp) != NULL) {
108145916cd2Sjpk 		nlen = plen + strlen(line) + 1;
108245916cd2Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
108345916cd2Sjpk 		if (len >= nsize) {
108445916cd2Sjpk 			free(nbuf);
108545916cd2Sjpk 			return (-1);
108645916cd2Sjpk 		}
108745916cd2Sjpk 		plen += len;
108845916cd2Sjpk 	}
108945916cd2Sjpk 	len = strlen(nbuf) + 1;
109045916cd2Sjpk 	if (len < nsize)
109145916cd2Sjpk 		nbuf[len] = '\n';
109245916cd2Sjpk 
109345916cd2Sjpk 	/* write the on/off str + the old device_allocate to the temp file */
109445916cd2Sjpk 	if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
109545916cd2Sjpk 		free(nbuf);
109645916cd2Sjpk 		return (-1);
109745916cd2Sjpk 	}
109845916cd2Sjpk 
109945916cd2Sjpk 	free(nbuf);
110045916cd2Sjpk 
110145916cd2Sjpk 	return (0);
110245916cd2Sjpk }
110345916cd2Sjpk 
110445916cd2Sjpk /*
110545916cd2Sjpk  * da_update_defattrs -
110645916cd2Sjpk  *	writes default attributes to devalloc_defaults
110745916cd2Sjpk  *	returns 0 on success, -1 on error.
110845916cd2Sjpk  */
110945916cd2Sjpk int
111045916cd2Sjpk da_update_defattrs(da_args *dargs)
111145916cd2Sjpk {
111245916cd2Sjpk 	int		rc = 0, lockfd = 0, tmpfd = 0;
111345916cd2Sjpk 	char		*defpath = DEFATTRS;
111445916cd2Sjpk 	char		*tmpdefpath = TMPATTRS;
111545916cd2Sjpk 	FILE		*tmpfp = NULL;
111645916cd2Sjpk 	struct stat	dstat;
111745916cd2Sjpk 	strentry_t	*head_defent = NULL;
111845916cd2Sjpk 
111945916cd2Sjpk 	if (dargs == NULL)
112045916cd2Sjpk 		return (0);
112145916cd2Sjpk 	if ((lockfd = _da_lock_devdb(NULL)) == -1)
112245916cd2Sjpk 		return (-1);
112345916cd2Sjpk 	if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
112445916cd2Sjpk 		(void) close(lockfd);
112545916cd2Sjpk 		return (-1);
112645916cd2Sjpk 	}
112745916cd2Sjpk 	(void) fchown(tmpfd, DA_UID, DA_GID);
112845916cd2Sjpk 	if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) {
112945916cd2Sjpk 		(void) close(tmpfd);
113045916cd2Sjpk 		(void) unlink(tmpdefpath);
113145916cd2Sjpk 		(void) close(lockfd);
113245916cd2Sjpk 		return (-1);
113345916cd2Sjpk 	}
113445916cd2Sjpk 	/*
113545916cd2Sjpk 	 * examine all entries, remove an old one if required, check
113645916cd2Sjpk 	 * if a new one needs to be added.
113745916cd2Sjpk 	 */
113845916cd2Sjpk 	if (stat(defpath, &dstat) == 0) {
113945916cd2Sjpk 		if ((rc = _build_defattrs(dargs, &head_defent)) != 0) {
114045916cd2Sjpk 			if (rc == 1) {
114145916cd2Sjpk 				(void) close(tmpfd);
114245916cd2Sjpk 				(void) unlink(tmpdefpath);
114345916cd2Sjpk 				(void) close(lockfd);
114445916cd2Sjpk 				return (rc);
114545916cd2Sjpk 			}
114645916cd2Sjpk 		}
114745916cd2Sjpk 	}
114845916cd2Sjpk 	/*
114945916cd2Sjpk 	 * write back any existing entries.
115045916cd2Sjpk 	 */
115145916cd2Sjpk 	_write_defattrs(tmpfp, head_defent);
115245916cd2Sjpk 
115345916cd2Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
115445916cd2Sjpk 		/* add new entries */
115545916cd2Sjpk 		rc = _write_new_defattrs(tmpfp, dargs);
115645916cd2Sjpk 		(void) fclose(tmpfp);
115745916cd2Sjpk 	} else {
115845916cd2Sjpk 		(void) fclose(tmpfp);
115945916cd2Sjpk 	}
116045916cd2Sjpk 	if (rename(tmpdefpath, defpath) != 0) {
116145916cd2Sjpk 		rc = -1;
116245916cd2Sjpk 		(void) unlink(tmpdefpath);
116345916cd2Sjpk 	}
116445916cd2Sjpk 	(void) close(lockfd);
116545916cd2Sjpk 
116645916cd2Sjpk 	return (rc);
116745916cd2Sjpk }
116845916cd2Sjpk 
116945916cd2Sjpk /*
117045916cd2Sjpk  * da_update_device -
117145916cd2Sjpk  *	writes devices entries to device_allocate and device_maps.
117245916cd2Sjpk  * 	returns 0 on success, -1 on error.
117345916cd2Sjpk  */
117445916cd2Sjpk int
117545916cd2Sjpk da_update_device(da_args *dargs)
117645916cd2Sjpk {
117745916cd2Sjpk 	int		rc;
117845916cd2Sjpk 	int		tafd = -1, tmfd = -1;
117945916cd2Sjpk 	int		lockfd = -1;
118045916cd2Sjpk 	char		*rootdir = NULL;
1181*10ddde3aSaj 	char		*apathp = NULL, *mpathp = NULL;
1182*10ddde3aSaj 	char		*dapathp = NULL, *dmpathp = NULL;
1183*10ddde3aSaj 	char		apath[MAXPATHLEN], mpath[MAXPATHLEN];
1184*10ddde3aSaj 	char		dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
118545916cd2Sjpk 	FILE		*tafp = NULL, *tmfp = NULL, *dafp = NULL;
118645916cd2Sjpk 	struct stat	dastat;
118745916cd2Sjpk 	devinfo_t	*devinfo;
118845916cd2Sjpk 	strentry_t	*head_devmapp = NULL;
118945916cd2Sjpk 	strentry_t	*head_devallocp = NULL;
119045916cd2Sjpk 
119145916cd2Sjpk 	if (dargs == NULL)
119245916cd2Sjpk 		return (0);
119345916cd2Sjpk 
119445916cd2Sjpk 	rootdir = dargs->rootdir;
119545916cd2Sjpk 	devinfo = dargs->devinfo;
119645916cd2Sjpk 
119745916cd2Sjpk 	/*
119845916cd2Sjpk 	 * adding/removing entries should be done in both
119945916cd2Sjpk 	 * device_allocate and device_maps. updates can be
120045916cd2Sjpk 	 * done in both or either of the files.
120145916cd2Sjpk 	 */
120245916cd2Sjpk 	if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
120345916cd2Sjpk 		if (dargs->optflag & DA_ALLOC_ONLY ||
120445916cd2Sjpk 		    dargs->optflag & DA_MAPS_ONLY)
120545916cd2Sjpk 			return (0);
120645916cd2Sjpk 	}
120745916cd2Sjpk 
120845916cd2Sjpk 	/*
120945916cd2Sjpk 	 * name, type and list are required fields for adding a new
121045916cd2Sjpk 	 * device.
121145916cd2Sjpk 	 */
121245916cd2Sjpk 	if ((dargs->optflag & DA_ADD) &&
121345916cd2Sjpk 	    ((devinfo->devname == NULL) ||
121445916cd2Sjpk 	    (devinfo->devtype == NULL) ||
121545916cd2Sjpk 	    (devinfo->devlist == NULL))) {
121645916cd2Sjpk 		return (-1);
121745916cd2Sjpk 	}
121845916cd2Sjpk 
121945916cd2Sjpk 	if (rootdir != NULL) {
122045916cd2Sjpk 		if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
122145916cd2Sjpk 		    TMPALLOC) >= sizeof (apath))
122245916cd2Sjpk 			return (-1);
122345916cd2Sjpk 		apathp = apath;
122445916cd2Sjpk 		if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
122545916cd2Sjpk 		    DEVALLOC) >= sizeof (dapath))
122645916cd2Sjpk 			return (-1);
122745916cd2Sjpk 		dapathp = dapath;
122845916cd2Sjpk 		if (!(dargs->optflag & DA_ALLOC_ONLY)) {
122945916cd2Sjpk 			if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
123045916cd2Sjpk 			    TMPMAP) >= sizeof (mpath))
123145916cd2Sjpk 				return (-1);
123245916cd2Sjpk 			mpathp = mpath;
123345916cd2Sjpk 			if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
123445916cd2Sjpk 			    DEVMAP) >= sizeof (dmpath))
123545916cd2Sjpk 				return (-1);
123645916cd2Sjpk 			dmpathp = dmpath;
123745916cd2Sjpk 		}
123845916cd2Sjpk 	} else {
123945916cd2Sjpk 		apathp = TMPALLOC;
124045916cd2Sjpk 		dapathp = DEVALLOC;
124145916cd2Sjpk 		mpathp = TMPMAP;
124245916cd2Sjpk 		dmpathp = DEVMAP;
124345916cd2Sjpk 	}
124445916cd2Sjpk 
124545916cd2Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
124645916cd2Sjpk 		goto dmap_only;
124745916cd2Sjpk 
124845916cd2Sjpk 	/*
124945916cd2Sjpk 	 * Check if we are here just to record on/off status of
125045916cd2Sjpk 	 * device_allocation.
125145916cd2Sjpk 	 */
125245916cd2Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
125345916cd2Sjpk 		lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
125445916cd2Sjpk 		    DA_RDONLY|DA_ALLOC_ONLY);
125545916cd2Sjpk 	else
125645916cd2Sjpk 		lockfd = _da_lock_devdb(rootdir);
125745916cd2Sjpk 	if (lockfd == -1)
125845916cd2Sjpk 		return (-1);
125945916cd2Sjpk 
126045916cd2Sjpk 	if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
126145916cd2Sjpk 		(void) close(lockfd);
126245916cd2Sjpk 		(void) fclose(dafp);
126345916cd2Sjpk 		return (-1);
126445916cd2Sjpk 	}
126545916cd2Sjpk 	(void) fchown(tafd, DA_UID, DA_GID);
126645916cd2Sjpk 	if ((tafp = fdopen(tafd, "r+")) == NULL) {
126745916cd2Sjpk 		(void) close(tafd);
126845916cd2Sjpk 		(void) unlink(apathp);
126945916cd2Sjpk 		(void) fclose(dafp);
127045916cd2Sjpk 		(void) close(lockfd);
127145916cd2Sjpk 		return (-1);
127245916cd2Sjpk 	}
127345916cd2Sjpk 
127445916cd2Sjpk 	/*
127545916cd2Sjpk 	 * We don't need to parse the file if we are here just to record
127645916cd2Sjpk 	 * on/off status of device_allocation.
127745916cd2Sjpk 	 */
127845916cd2Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
127945916cd2Sjpk 		if (_record_on_off(dargs, tafp, dafp) == -1) {
128045916cd2Sjpk 			(void) close(tafd);
128145916cd2Sjpk 			(void) unlink(apathp);
128245916cd2Sjpk 			(void) fclose(dafp);
128345916cd2Sjpk 			(void) close(lockfd);
128445916cd2Sjpk 			return (-1);
128545916cd2Sjpk 		}
128645916cd2Sjpk 		(void) fclose(dafp);
128745916cd2Sjpk 		goto out;
128845916cd2Sjpk 	}
128945916cd2Sjpk 
129045916cd2Sjpk 	/*
129145916cd2Sjpk 	 * examine all the entries, remove an old one if forced to,
129245916cd2Sjpk 	 * and check that they are suitable for updating.
129345916cd2Sjpk 	 *  we need to do this only if the file exists already.
129445916cd2Sjpk 	 */
129545916cd2Sjpk 	if (stat(dapathp, &dastat) == 0) {
129645916cd2Sjpk 		if ((rc = _build_lists(dargs, &head_devallocp,
129745916cd2Sjpk 		    &head_devmapp)) != 0) {
129845916cd2Sjpk 			if (rc != 1) {
129945916cd2Sjpk 				(void) close(tafd);
130045916cd2Sjpk 				(void) unlink(apathp);
130145916cd2Sjpk 				(void) close(lockfd);
130245916cd2Sjpk 				return (rc);
130345916cd2Sjpk 			}
130445916cd2Sjpk 		}
130545916cd2Sjpk 	}
130645916cd2Sjpk 
130745916cd2Sjpk 	/*
130845916cd2Sjpk 	 * write back any existing devalloc entries, along with
130945916cd2Sjpk 	 * the devalloc on/off string.
131045916cd2Sjpk 	 */
131145916cd2Sjpk 	_write_device_allocate(dapathp, tafp, head_devallocp);
131245916cd2Sjpk 
131345916cd2Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
131445916cd2Sjpk 		goto out;
131545916cd2Sjpk 
131645916cd2Sjpk dmap_only:
131745916cd2Sjpk 	if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
131845916cd2Sjpk 		(void) close(tafd);
131945916cd2Sjpk 		(void) unlink(apathp);
132045916cd2Sjpk 		(void) close(lockfd);
132145916cd2Sjpk 		return (-1);
132245916cd2Sjpk 	}
132345916cd2Sjpk 	(void) fchown(tmfd, DA_UID, DA_GID);
132445916cd2Sjpk 	if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
132545916cd2Sjpk 		(void) close(tafd);
132645916cd2Sjpk 		(void) unlink(apathp);
132745916cd2Sjpk 		(void) close(tmfd);
132845916cd2Sjpk 		(void) unlink(mpathp);
132945916cd2Sjpk 		(void) close(lockfd);
133045916cd2Sjpk 		return (-1);
133145916cd2Sjpk 	}
133245916cd2Sjpk 
133345916cd2Sjpk 	/* write back any existing devmap entries */
133445916cd2Sjpk 	if (head_devmapp != NULL)
133545916cd2Sjpk 		_write_device_maps(tmfp, head_devmapp);
133645916cd2Sjpk 
133745916cd2Sjpk out:
133845916cd2Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
133945916cd2Sjpk 		/* add any new entries */
134045916cd2Sjpk 		rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
134145916cd2Sjpk 		(void) fclose(tafp);
134245916cd2Sjpk 
134345916cd2Sjpk 		if (rc == 0)
134445916cd2Sjpk 			rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
134545916cd2Sjpk 		(void) fclose(tmfp);
134645916cd2Sjpk 	} else {
134745916cd2Sjpk 		if (tafp)
134845916cd2Sjpk 			(void) fclose(tafp);
134945916cd2Sjpk 		if (tmfp)
135045916cd2Sjpk 			(void) fclose(tmfp);
135145916cd2Sjpk 	}
135245916cd2Sjpk 
135345916cd2Sjpk 	rc = 0;
135445916cd2Sjpk 	if (!(dargs->optflag & DA_MAPS_ONLY)) {
135545916cd2Sjpk 		if (rename(apathp, dapathp) != 0) {
135645916cd2Sjpk 			rc = -1;
135745916cd2Sjpk 			(void) unlink(apathp);
135845916cd2Sjpk 		}
135945916cd2Sjpk 	}
136045916cd2Sjpk 	if (!(dargs->optflag & DA_ALLOC_ONLY)) {
136145916cd2Sjpk 		if (rename(mpathp, dmpathp) != 0) {
136245916cd2Sjpk 			rc = -1;
136345916cd2Sjpk 			(void) unlink(mpathp);
136445916cd2Sjpk 		}
136545916cd2Sjpk 	}
136645916cd2Sjpk 
136745916cd2Sjpk 	(void) close(lockfd);
136845916cd2Sjpk 
136945916cd2Sjpk 	return (rc);
137045916cd2Sjpk }
137145916cd2Sjpk 
137245916cd2Sjpk /*
137345916cd2Sjpk  * da_add_list -
137445916cd2Sjpk  *	adds new /dev link name to the linked list of devices.
137545916cd2Sjpk  *	returns 0 if link added successfully, -1 on error.
137645916cd2Sjpk  */
137745916cd2Sjpk int
137845916cd2Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
137945916cd2Sjpk {
138045916cd2Sjpk 	int		instance;
138145916cd2Sjpk 	int		nlen, plen;
138245916cd2Sjpk 	int		new_entry = 0;
138345916cd2Sjpk 	char		*dtype, *dexec, *tname, *kval;
138445916cd2Sjpk 	char		*minstr = NULL, *maxstr = NULL;
138545916cd2Sjpk 	char		dname[DA_MAXNAME];
138645916cd2Sjpk 	kva_t		*kva;
138745916cd2Sjpk 	deventry_t	*dentry = NULL, *nentry = NULL, *pentry = NULL;
138845916cd2Sjpk 	da_defs_t	*da_defs;
138945916cd2Sjpk 
139045916cd2Sjpk 	if (dlist == NULL || link == NULL)
139145916cd2Sjpk 		return (-1);
139245916cd2Sjpk 
139345916cd2Sjpk 	dname[0] = '\0';
139445916cd2Sjpk 	if (flag & DA_AUDIO) {
139545916cd2Sjpk 		dentry = dlist->audio;
139645916cd2Sjpk 		tname = DA_AUDIO_NAME;
139745916cd2Sjpk 		dtype = DA_AUDIO_TYPE;
139845916cd2Sjpk 		dexec = DA_DEFAULT_AUDIO_CLEAN;
139945916cd2Sjpk 	} else if (flag & DA_CD) {
140045916cd2Sjpk 		dentry = dlist->cd;
140145916cd2Sjpk 		tname = DA_CD_NAME;
140245916cd2Sjpk 		dtype = DA_CD_TYPE;
140345916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
140445916cd2Sjpk 	} else if (flag & DA_FLOPPY) {
140545916cd2Sjpk 		dentry = dlist->floppy;
140645916cd2Sjpk 		tname = DA_FLOPPY_NAME;
140745916cd2Sjpk 		dtype = DA_FLOPPY_TYPE;
140845916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
140945916cd2Sjpk 	} else if (flag & DA_TAPE) {
141045916cd2Sjpk 		dentry = dlist->tape;
141145916cd2Sjpk 		tname = DA_TAPE_NAME;
141245916cd2Sjpk 		dtype = DA_TAPE_TYPE;
141345916cd2Sjpk 		dexec = DA_DEFAULT_TAPE_CLEAN;
141445916cd2Sjpk 	} else if (flag & DA_RMDISK) {
141545916cd2Sjpk 		dentry = dlist->rmdisk;
141645916cd2Sjpk 		tname = DA_RMDISK_NAME;
141745916cd2Sjpk 		dtype = DA_RMDISK_TYPE;
141845916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
141945916cd2Sjpk 	} else {
142045916cd2Sjpk 		return (-1);
142145916cd2Sjpk 	}
142245916cd2Sjpk 
142345916cd2Sjpk 	for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
142445916cd2Sjpk 		pentry = nentry;
142545916cd2Sjpk 		(void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
142645916cd2Sjpk 		if (nentry->devinfo.instance == new_instance)
142745916cd2Sjpk 			/*
142845916cd2Sjpk 			 * Add the new link name to the list of links
142945916cd2Sjpk 			 * that the device 'dname' has.
143045916cd2Sjpk 			 */
143145916cd2Sjpk 			break;
143245916cd2Sjpk 	}
143345916cd2Sjpk 
143445916cd2Sjpk 	if (nentry == NULL) {
143545916cd2Sjpk 		/*
143645916cd2Sjpk 		 * Either this is the first entry ever, or no matching entry
143745916cd2Sjpk 		 * was found. Create a new one and add to the list.
143845916cd2Sjpk 		 */
143945916cd2Sjpk 		if (dentry == NULL)		/* first entry ever */
144045916cd2Sjpk 			instance = 0;
144145916cd2Sjpk 		else				/* no matching entry */
144245916cd2Sjpk 			instance++;
144345916cd2Sjpk 		(void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
144445916cd2Sjpk 		if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
144545916cd2Sjpk 		    NULL)
144645916cd2Sjpk 			return (-1);
144745916cd2Sjpk 		if (pentry != NULL)
144845916cd2Sjpk 			pentry->next = nentry;
144945916cd2Sjpk 		new_entry = 1;
145045916cd2Sjpk 		nentry->devinfo.devname = strdup(dname);
145145916cd2Sjpk 		nentry->devinfo.devtype = dtype;
145245916cd2Sjpk 		nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
145345916cd2Sjpk 		nentry->devinfo.devexec = dexec;
145445916cd2Sjpk 		nentry->devinfo.instance = new_instance;
145545916cd2Sjpk 		/*
145645916cd2Sjpk 		 * Look for default label range, authorizations and cleaning
145745916cd2Sjpk 		 * program in devalloc_defaults. If label range is not
145845916cd2Sjpk 		 * specified in devalloc_defaults, assume it to be admin_low
145945916cd2Sjpk 		 * to admin_high.
146045916cd2Sjpk 		 */
146145916cd2Sjpk 		minstr = DA_DEFAULT_MIN;
146245916cd2Sjpk 		maxstr = DA_DEFAULT_MAX;
146345916cd2Sjpk 		setdadefent();
146445916cd2Sjpk 		if (da_defs = getdadeftype(nentry->devinfo.devtype)) {
146545916cd2Sjpk 			kva = da_defs->devopts;
146645916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
146745916cd2Sjpk 				minstr = strdup(kval);
146845916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
146945916cd2Sjpk 				maxstr = strdup(kval);
147045916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
147145916cd2Sjpk 				nentry->devinfo.devauths = strdup(kval);
147245916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
147345916cd2Sjpk 				nentry->devinfo.devexec = strdup(kval);
147445916cd2Sjpk 			freedadefent(da_defs);
147545916cd2Sjpk 		}
147645916cd2Sjpk 		enddadefent();
147745916cd2Sjpk 		kval = NULL;
147845916cd2Sjpk 		nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
147945916cd2Sjpk 		    strlen(minstr) + strlen(KV_TOKEN_DELIMIT) +
148045916cd2Sjpk 		    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr)
148145916cd2Sjpk 		    + 1;			/* +1 for terminator */
148245916cd2Sjpk 		if (kval = (char *)malloc(nlen))
148345916cd2Sjpk 			(void) snprintf(kval, nlen, "%s%s%s%s%s%s%s",
148445916cd2Sjpk 			    DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT,
148545916cd2Sjpk 			    DAOPT_MAXLABEL, KV_ASSIGN, maxstr);
148645916cd2Sjpk 		nentry->devinfo.devopts = kval;
148745916cd2Sjpk 
148845916cd2Sjpk 		nentry->devinfo.devlist = NULL;
148945916cd2Sjpk 		nentry->next = NULL;
149045916cd2Sjpk 	}
149145916cd2Sjpk 
149245916cd2Sjpk 	nlen = strlen(link) + 1;		/* +1 terminator */
149345916cd2Sjpk 	if (nentry->devinfo.devlist) {
149445916cd2Sjpk 		plen = strlen(nentry->devinfo.devlist);
149545916cd2Sjpk 		nlen = nlen + plen + 1;	/* +1 for blank to separate entries */
149645916cd2Sjpk 	} else {
149745916cd2Sjpk 		plen = 0;
149845916cd2Sjpk 	}
149945916cd2Sjpk 
150045916cd2Sjpk 	if ((nentry->devinfo.devlist =
150145916cd2Sjpk 	    (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
150245916cd2Sjpk 		if (new_entry) {
150345916cd2Sjpk 			nentry->devinfo.devname = NULL;
150445916cd2Sjpk 			free(nentry->devinfo.devname);
150545916cd2Sjpk 			nentry = NULL;
150645916cd2Sjpk 			free(nentry);
150745916cd2Sjpk 			if (pentry != NULL)
150845916cd2Sjpk 				pentry->next = NULL;
150945916cd2Sjpk 		}
151045916cd2Sjpk 		return (-1);
151145916cd2Sjpk 	}
151245916cd2Sjpk 
151345916cd2Sjpk 	if (plen == 0)
151445916cd2Sjpk 		(void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
151545916cd2Sjpk 	else
151645916cd2Sjpk 		(void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
151745916cd2Sjpk 		    " %s", link);
151845916cd2Sjpk 
151945916cd2Sjpk 	if (pentry == NULL) {
152045916cd2Sjpk 		/*
152145916cd2Sjpk 		 * This is the first entry of this device type.
152245916cd2Sjpk 		 */
152345916cd2Sjpk 		if (flag & DA_AUDIO)
152445916cd2Sjpk 			dlist->audio = nentry;
152545916cd2Sjpk 		else if (flag & DA_CD)
152645916cd2Sjpk 			dlist->cd = nentry;
152745916cd2Sjpk 		else if (flag & DA_FLOPPY)
152845916cd2Sjpk 			dlist->floppy = nentry;
152945916cd2Sjpk 		else if (flag & DA_TAPE)
153045916cd2Sjpk 			dlist->tape = nentry;
153145916cd2Sjpk 		else if (flag & DA_RMDISK)
153245916cd2Sjpk 			dlist->rmdisk = nentry;
153345916cd2Sjpk 	}
153445916cd2Sjpk 
153545916cd2Sjpk 	return (0);
153645916cd2Sjpk }
153745916cd2Sjpk 
153845916cd2Sjpk /*
153945916cd2Sjpk  * da_remove_list -
154045916cd2Sjpk  *	removes a /dev link name from the linked list of devices.
154145916cd2Sjpk  *	returns type of device if link for that device removed
154245916cd2Sjpk  *	successfully, else returns -1 on error.
154345916cd2Sjpk  *	if all links for a device are removed, stores that device
154445916cd2Sjpk  *	name in devname.
154545916cd2Sjpk  */
154645916cd2Sjpk int
154745916cd2Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
154845916cd2Sjpk {
154945916cd2Sjpk 	int		flag;
155045916cd2Sjpk 	int		remove_dev = 0;
155145916cd2Sjpk 	int		nlen, plen, slen;
155245916cd2Sjpk 	char		*lasts, *lname, *oldlist;
155345916cd2Sjpk 	struct stat	rmstat;
155445916cd2Sjpk 	deventry_t	*dentry, *current, *prev;
155545916cd2Sjpk 
155645916cd2Sjpk 	if (type != NULL)
155745916cd2Sjpk 		flag = type;
155845916cd2Sjpk 	else if (link == NULL)
155945916cd2Sjpk 		return (-1);
156045916cd2Sjpk 	else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
156145916cd2Sjpk 		flag = DA_AUDIO;
156245916cd2Sjpk 	else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
156345916cd2Sjpk 	    strstr(link, "sr") || strstr(link, "rsr"))
156445916cd2Sjpk 		flag = DA_CD;
156545916cd2Sjpk 	else if (strstr(link, "fd") || strstr(link, "rfd") ||
156645916cd2Sjpk 	    strstr(link, "diskette") || strstr(link, "rdiskette"))
156745916cd2Sjpk 		flag = DA_FLOPPY;
156845916cd2Sjpk 	else if (strstr(link, DA_TAPE_NAME))
156945916cd2Sjpk 		flag = DA_TAPE;
157045916cd2Sjpk 	else
157145916cd2Sjpk 		flag = DA_RMDISK;
157245916cd2Sjpk 
157345916cd2Sjpk 	switch (type) {
157445916cd2Sjpk 	case DA_AUDIO:
157545916cd2Sjpk 		dentry = dlist->audio;
157645916cd2Sjpk 		break;
157745916cd2Sjpk 	case DA_CD:
157845916cd2Sjpk 		dentry = dlist->cd;
157945916cd2Sjpk 		break;
158045916cd2Sjpk 	case DA_FLOPPY:
158145916cd2Sjpk 		dentry = dlist->floppy;
158245916cd2Sjpk 		break;
158345916cd2Sjpk 	case DA_TAPE:
158445916cd2Sjpk 		dentry = dlist->tape;
158545916cd2Sjpk 		break;
158645916cd2Sjpk 	case DA_RMDISK:
158745916cd2Sjpk 		dentry = dlist->rmdisk;
158845916cd2Sjpk 		break;
158945916cd2Sjpk 	default:
159045916cd2Sjpk 		return (-1);
159145916cd2Sjpk 	}
159245916cd2Sjpk 
159345916cd2Sjpk 	if ((type != NULL) && (link == NULL)) {
159445916cd2Sjpk 		for (current = dentry, prev = dentry; current != NULL;
159545916cd2Sjpk 		    current = current->next) {
159645916cd2Sjpk 			oldlist = strdup(current->devinfo.devlist);
159745916cd2Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
159845916cd2Sjpk 			    lname != NULL;
159945916cd2Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
160045916cd2Sjpk 				if (stat(lname, &rmstat) != 0) {
160145916cd2Sjpk 					remove_dev = 1;
160245916cd2Sjpk 					goto remove_dev;
160345916cd2Sjpk 				}
160445916cd2Sjpk 			}
160545916cd2Sjpk 			prev = current;
160645916cd2Sjpk 		}
160745916cd2Sjpk 		return (-1);
160845916cd2Sjpk 	}
160945916cd2Sjpk 
161045916cd2Sjpk 	for (current = dentry, prev = dentry; current != NULL;
161145916cd2Sjpk 	    current = current->next) {
161245916cd2Sjpk 		plen = strlen(current->devinfo.devlist);
161345916cd2Sjpk 		nlen = strlen(link);
161445916cd2Sjpk 		if (plen == nlen) {
161545916cd2Sjpk 			if (strcmp(current->devinfo.devlist, link) == 0) {
161645916cd2Sjpk 				/* last name in the list */
161745916cd2Sjpk 				remove_dev = 1;
161845916cd2Sjpk 				break;
161945916cd2Sjpk 			}
162045916cd2Sjpk 		}
162145916cd2Sjpk 		if (strstr(current->devinfo.devlist, link)) {
162245916cd2Sjpk 			nlen = plen - nlen + 1;
162345916cd2Sjpk 			oldlist = strdup(current->devinfo.devlist);
162445916cd2Sjpk 			if ((current->devinfo.devlist =
162545916cd2Sjpk 			    (char *)realloc(current->devinfo.devlist,
162645916cd2Sjpk 			    nlen)) == NULL) {
162745916cd2Sjpk 				free(oldlist);
162845916cd2Sjpk 				return (-1);
162945916cd2Sjpk 			}
163045916cd2Sjpk 			current->devinfo.devlist[0] = '\0';
163145916cd2Sjpk 			nlen = plen = slen = 0;
163245916cd2Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
163345916cd2Sjpk 			    lname != NULL;
163445916cd2Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
163545916cd2Sjpk 				if (strcmp(lname, link) == 0)
163645916cd2Sjpk 					continue;
163745916cd2Sjpk 				nlen = strlen(lname) + plen + 1;
163845916cd2Sjpk 				if (plen == 0) {
163945916cd2Sjpk 					slen =
164045916cd2Sjpk 					    snprintf(current->devinfo.devlist,
164145916cd2Sjpk 					    nlen, "%s", lname);
164245916cd2Sjpk 				} else {
164345916cd2Sjpk 					slen =
164445916cd2Sjpk 					    snprintf(current->devinfo.devlist +
1645*10ddde3aSaj 					    plen, nlen - plen, " %s", lname);
164645916cd2Sjpk 				}
164745916cd2Sjpk 				plen = plen + slen + 1;
164845916cd2Sjpk 			}
164945916cd2Sjpk 			free(oldlist);
165045916cd2Sjpk 			break;
165145916cd2Sjpk 		}
165245916cd2Sjpk 		prev = current;
165345916cd2Sjpk 	}
165445916cd2Sjpk 
165545916cd2Sjpk remove_dev:
165645916cd2Sjpk 	if (remove_dev == 1) {
165745916cd2Sjpk 		(void) strlcpy(devname, current->devinfo.devname, size);
165845916cd2Sjpk 		free(current->devinfo.devname);
165945916cd2Sjpk 		free(current->devinfo.devlist);
166045916cd2Sjpk 		current->devinfo.devname = current->devinfo.devlist = NULL;
166145916cd2Sjpk 		prev->next = current->next;
166245916cd2Sjpk 		free(current);
166345916cd2Sjpk 		current = NULL;
166445916cd2Sjpk 	}
166545916cd2Sjpk 	if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
166645916cd2Sjpk 		if (prev->next) {
166745916cd2Sjpk 			/*
166845916cd2Sjpk 			 * what we removed above was the first entry
166945916cd2Sjpk 			 * in the list. make the next entry to be the
167045916cd2Sjpk 			 * first.
167145916cd2Sjpk 			 */
167245916cd2Sjpk 			current = prev->next;
167345916cd2Sjpk 		} else {
167445916cd2Sjpk 			/*
167545916cd2Sjpk 			 * the matching entry was the only entry in the list
167645916cd2Sjpk 			 * for this type.
167745916cd2Sjpk 			 */
167845916cd2Sjpk 			current = NULL;
167945916cd2Sjpk 		}
168045916cd2Sjpk 		if (flag & DA_AUDIO)
168145916cd2Sjpk 			dlist->audio = current;
168245916cd2Sjpk 		else if (flag & DA_CD)
168345916cd2Sjpk 			dlist->cd = current;
168445916cd2Sjpk 		else if (flag & DA_FLOPPY)
168545916cd2Sjpk 			dlist->floppy = current;
168645916cd2Sjpk 		else if (flag & DA_TAPE)
168745916cd2Sjpk 			dlist->tape = current;
168845916cd2Sjpk 		else if (flag & DA_RMDISK)
168945916cd2Sjpk 			dlist->rmdisk = current;
169045916cd2Sjpk 	}
169145916cd2Sjpk 
169245916cd2Sjpk 	return (flag);
169345916cd2Sjpk }
169445916cd2Sjpk 
169545916cd2Sjpk /*
169645916cd2Sjpk  * da_is_on -
169745916cd2Sjpk  *	checks if device allocation feature is turned on.
169845916cd2Sjpk  *	returns 1 if on, 0 if off, -1 if status string not
169945916cd2Sjpk  *	found in device_allocate.
170045916cd2Sjpk  */
170145916cd2Sjpk int
170245916cd2Sjpk da_is_on()
170345916cd2Sjpk {
170445916cd2Sjpk 	return (getdaon());
170545916cd2Sjpk }
170645916cd2Sjpk 
170745916cd2Sjpk /*
170845916cd2Sjpk  * da_print_device -
170945916cd2Sjpk  *	debug routine to print device entries.
171045916cd2Sjpk  */
171145916cd2Sjpk void
171245916cd2Sjpk da_print_device(int flag, devlist_t *devlist)
171345916cd2Sjpk {
171445916cd2Sjpk 	deventry_t	*entry, *dentry;
171545916cd2Sjpk 	devinfo_t	*devinfo;
171645916cd2Sjpk 
171745916cd2Sjpk 	if (flag & DA_AUDIO)
171845916cd2Sjpk 		dentry = devlist->audio;
171945916cd2Sjpk 	else if (flag & DA_CD)
172045916cd2Sjpk 		dentry = devlist->cd;
172145916cd2Sjpk 	else if (flag & DA_FLOPPY)
172245916cd2Sjpk 		dentry = devlist->floppy;
172345916cd2Sjpk 	else if (flag & DA_TAPE)
172445916cd2Sjpk 		dentry = devlist->tape;
172545916cd2Sjpk 	else if (flag & DA_RMDISK)
172645916cd2Sjpk 		dentry = devlist->rmdisk;
172745916cd2Sjpk 	else
172845916cd2Sjpk 		return;
172945916cd2Sjpk 
173045916cd2Sjpk 	for (entry = dentry; entry != NULL; entry = entry->next) {
173145916cd2Sjpk 		devinfo = &(entry->devinfo);
173245916cd2Sjpk 		(void) fprintf(stdout, "name: %s\n", devinfo->devname);
173345916cd2Sjpk 		(void) fprintf(stdout, "type: %s\n", devinfo->devtype);
173445916cd2Sjpk 		(void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
173545916cd2Sjpk 		(void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
173645916cd2Sjpk 		(void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);
173745916cd2Sjpk 	}
173845916cd2Sjpk }
1739