xref: /titanic_51/usr/src/lib/libbsm/common/devalloc.c (revision 399f067736e659e2754e97190952abea40f1d0d6)
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*399f0677SJan Parcel  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
2445916cd2Sjpk  */
2545916cd2Sjpk 
2645916cd2Sjpk #include <stdlib.h>
2745916cd2Sjpk #include <ctype.h>
2845916cd2Sjpk #include <unistd.h>
2945916cd2Sjpk #include <limits.h>
3045916cd2Sjpk #include <fcntl.h>
3145916cd2Sjpk #include <sys/types.h>
3245916cd2Sjpk #include <sys/stat.h>
3345916cd2Sjpk #include <utime.h>
3445916cd2Sjpk #include <synch.h>
3545916cd2Sjpk #include <strings.h>
3645916cd2Sjpk #include <string.h>
3745916cd2Sjpk #include <libintl.h>
3845916cd2Sjpk #include <errno.h>
3945916cd2Sjpk #include <auth_list.h>
407e3e5701SJan Parcel #include <syslog.h>
4145916cd2Sjpk #include <bsm/devices.h>
4245916cd2Sjpk #include <bsm/devalloc.h>
43*399f0677SJan Parcel #include <tsol/label.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 *);
557e3e5701SJan Parcel extern int dmap_matchtype(devmap_t *dmap, char *type);
567e3e5701SJan Parcel extern int dmap_matchdev(devmap_t *dmap, char *dev);
577e3e5701SJan Parcel extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num);
587e3e5701SJan 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
3387e3e5701SJan 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 *
3627e3e5701SJan Parcel _dmap2strentry(devmap_t *devmapp)
36345916cd2Sjpk {
36445916cd2Sjpk 	strentry_t	*sep;
36545916cd2Sjpk 
36645916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
36745916cd2Sjpk 		return (NULL);
3687e3e5701SJan 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*399f0677SJan Parcel  * We have to handle the "standard" types in devlist differently than
569*399f0677SJan Parcel  * other devices, which are not covered by our auto-naming conventions.
570*399f0677SJan Parcel  *
571*399f0677SJan Parcel  * buf must be a buffer of size DA_MAX_NAME + 1
572*399f0677SJan Parcel  */
573*399f0677SJan Parcel int
574*399f0677SJan Parcel da_std_type(da_args *dargs, char *namebuf)
575*399f0677SJan Parcel {
576*399f0677SJan Parcel 	char *type = dargs->devinfo->devtype;
577*399f0677SJan Parcel 	int system_labeled;
578*399f0677SJan Parcel 
579*399f0677SJan Parcel 	system_labeled = is_system_labeled();
580*399f0677SJan Parcel 
581*399f0677SJan Parcel 	/* check safely for sizes */
582*399f0677SJan Parcel 	if (strcmp(DA_AUDIO_TYPE, type) == 0) {
583*399f0677SJan Parcel 		(void) strlcpy(namebuf, DA_AUDIO_NAME, DA_MAXNAME);
584*399f0677SJan Parcel 		return (1);
585*399f0677SJan Parcel 	}
586*399f0677SJan Parcel 	if (strcmp(DA_CD_TYPE, type) == 0) {
587*399f0677SJan Parcel 		if (system_labeled)
588*399f0677SJan Parcel 			(void) strlcpy(namebuf, DA_CD_NAME, DA_MAXNAME);
589*399f0677SJan Parcel 		else
590*399f0677SJan Parcel 			(void) strlcpy(namebuf, DA_CD_TYPE, DA_MAXNAME);
591*399f0677SJan Parcel 		return (1);
592*399f0677SJan Parcel 	}
593*399f0677SJan Parcel 	if (strcmp(DA_FLOPPY_TYPE, type) == 0) {
594*399f0677SJan Parcel 		if (system_labeled)
595*399f0677SJan Parcel 			(void) strlcpy(namebuf, DA_FLOPPY_NAME, DA_MAXNAME);
596*399f0677SJan Parcel 		else
597*399f0677SJan Parcel 			(void) strlcpy(namebuf, DA_FLOPPY_TYPE, DA_MAXNAME);
598*399f0677SJan Parcel 		return (1);
599*399f0677SJan Parcel 	}
600*399f0677SJan Parcel 	if (strcmp(DA_TAPE_TYPE, type) == 0) {
601*399f0677SJan Parcel 		if (system_labeled)
602*399f0677SJan Parcel 			(void) strlcpy(namebuf, DA_TAPE_NAME, DA_MAXNAME);
603*399f0677SJan Parcel 		else
604*399f0677SJan Parcel 			(void) strlcpy(namebuf, DA_TAPE_TYPE, DA_MAXNAME);
605*399f0677SJan Parcel 		return (1);
606*399f0677SJan Parcel 	}
607*399f0677SJan Parcel 	if (strcmp(DA_RMDISK_TYPE, type) == 0) {
608*399f0677SJan Parcel 		(void) strlcpy(namebuf, DA_RMDISK_NAME, DA_MAXNAME);
609*399f0677SJan Parcel 		return (1);
610*399f0677SJan Parcel 	}
611*399f0677SJan Parcel 	namebuf[0] = '\0';
612*399f0677SJan Parcel 	return (0);
613*399f0677SJan Parcel }
614*399f0677SJan Parcel 
615*399f0677SJan Parcel /*
616*399f0677SJan Parcel  * allocatable: returns
617*399f0677SJan Parcel  * -1 if no auths field,
618*399f0677SJan Parcel  * 0 if not allocatable (marked '*')
619*399f0677SJan Parcel  * 1 if not marked '*'
620*399f0677SJan Parcel  */
621*399f0677SJan Parcel static int
622*399f0677SJan Parcel allocatable(da_args *dargs)
623*399f0677SJan Parcel {
624*399f0677SJan Parcel 
625*399f0677SJan Parcel 	if (!dargs->devinfo->devauths)
626*399f0677SJan Parcel 		return (-1);
627*399f0677SJan Parcel 	if (strcmp("*", dargs->devinfo->devauths) == 0)
628*399f0677SJan Parcel 		return (0);
629*399f0677SJan Parcel 	return (1);
630*399f0677SJan Parcel }
631*399f0677SJan Parcel 
632*399f0677SJan Parcel /*
6337e3e5701SJan Parcel  * _rebuild_lists -
6347e3e5701SJan Parcel  *
6357e3e5701SJan Parcel  *	If dargs->optflag & DA_EVENT, does not assume the dargs list is
6367e3e5701SJan Parcel  *	complete or completely believable, since devfsadm caches
6377e3e5701SJan Parcel  *	ONLY what it has been exposed to via syseventd.
6387e3e5701SJan Parcel  *
6397e3e5701SJan Parcel  *	Cycles through all the entries in the /etc files, stores them
640*399f0677SJan Parcel  *	in memory, takes note of device->dname numbers (e.g. rmdisk0,
6417e3e5701SJan Parcel  *	rmdisk12)
6427e3e5701SJan Parcel  *
6437e3e5701SJan Parcel  *	Cycles through again, adds dargs entry
6447e3e5701SJan Parcel  *	with the name tname%d (lowest unused number for the device type)
6457e3e5701SJan Parcel  *	to the list of things for the caller to write out to a file,
6467e3e5701SJan Parcel  *	IFF it is a new entry.
6477e3e5701SJan Parcel  *
648*399f0677SJan Parcel  *	It is an error for it to already be there, if it is allocatable.
6497e3e5701SJan Parcel  *
6507e3e5701SJan Parcel  *	Add:
6517e3e5701SJan Parcel  *	    Returns 0 if successful and 2 on error.
6527e3e5701SJan Parcel  *	Remove:
6537e3e5701SJan Parcel  *	    Returns 0 if not found, 1 if found,  2 on error.
6547e3e5701SJan Parcel  */
6557e3e5701SJan Parcel static int
6567e3e5701SJan Parcel _rebuild_lists(da_args *dargs, strentry_t **head_devallocp,
6577e3e5701SJan Parcel     strentry_t **head_devmapp)
6587e3e5701SJan Parcel {
6597e3e5701SJan Parcel 	int		rc = 0;
6607e3e5701SJan Parcel 	devalloc_t	*devallocp;
6617e3e5701SJan Parcel 	devmap_t	*devmapp;
6627e3e5701SJan Parcel 	strentry_t	*tail_str;
6637e3e5701SJan Parcel 	strentry_t	*tmp_str;
6647e3e5701SJan Parcel 	uint64_t	tmp_bitmap = 0;
665*399f0677SJan Parcel 	uint_t		tmp = 0;
6667e3e5701SJan Parcel 	char		*realname;
667*399f0677SJan Parcel 	int		suffix;
6687e3e5701SJan Parcel 	int		found = 0;
669*399f0677SJan Parcel 	int		stdtype = 1;
670*399f0677SJan Parcel 	int		is_allocatable = 1;
671*399f0677SJan Parcel 	char		new_devname[DA_MAXNAME + 1];
672*399f0677SJan Parcel 	char		defname[DA_MAXNAME + 1]; /* default name for type */
673*399f0677SJan Parcel 	char		errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80];
6747e3e5701SJan Parcel 
6757e3e5701SJan Parcel 	if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY))
6767e3e5701SJan Parcel 		return (2);
6777e3e5701SJan Parcel 
6787e3e5701SJan Parcel 	if (dargs->optflag & DA_FORCE)
6797e3e5701SJan Parcel 		return (2);
6807e3e5701SJan Parcel 
681*399f0677SJan Parcel 	if (dargs->optflag & DA_ADD) {
682*399f0677SJan Parcel 		stdtype = da_std_type(dargs, defname);
683*399f0677SJan Parcel 		is_allocatable = allocatable(dargs);
684*399f0677SJan Parcel 	}
685*399f0677SJan Parcel 
6867e3e5701SJan Parcel 	/* read both files, maps first so we can compare actual devices */
6877e3e5701SJan Parcel 
6887e3e5701SJan Parcel 	/* build device_maps */
6897e3e5701SJan Parcel 	setdmapent();
6907e3e5701SJan Parcel 	while ((devmapp = getdmapent()) != NULL) {
691*399f0677SJan Parcel 		suffix = DA_MAX_DEVNO + 1;
6927e3e5701SJan Parcel 		if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype))
6937e3e5701SJan Parcel 		    == 1) {
6947e3e5701SJan Parcel 			if (dargs->optflag & DA_REMOVE) {
6957e3e5701SJan Parcel 				if ((devmapp->dmap_devarray == NULL) ||
6967e3e5701SJan Parcel 				    (devmapp->dmap_devarray[0] == NULL)) {
6977e3e5701SJan Parcel 					freedmapent(devmapp);
6987e3e5701SJan Parcel 					enddmapent();
6997e3e5701SJan Parcel 					return (2);
7007e3e5701SJan Parcel 				}
7017e3e5701SJan Parcel 				realname = dmap_physname(devmapp);
7027e3e5701SJan Parcel 				if (realname == NULL) {
7037e3e5701SJan Parcel 					freedmapent(devmapp);
7047e3e5701SJan Parcel 					enddmapent();
7057e3e5701SJan Parcel 					return (2);
7067e3e5701SJan Parcel 				}
7077e3e5701SJan Parcel 				if (strstr(realname, dargs->devinfo->devlist)
7087e3e5701SJan Parcel 				    != NULL) {
709*399f0677SJan Parcel 					/* if need to free and safe to free */
710*399f0677SJan Parcel 					if (dargs->devinfo->devname != NULL &&
711*399f0677SJan Parcel 					    (dargs->optflag & DA_EVENT) != 0)
7127e3e5701SJan Parcel 						free(dargs->devinfo->devname);
7137e3e5701SJan Parcel 					dargs->devinfo->devname =
7147e3e5701SJan Parcel 					    strdup(devmapp->dmap_devname);
7157e3e5701SJan Parcel 					found = 1;
7167e3e5701SJan Parcel 					freedmapent(devmapp);
7177e3e5701SJan Parcel 					continue; /* don't retain */
7187e3e5701SJan Parcel 				}
7197e3e5701SJan Parcel 			} else if (dargs->optflag & DA_ADD) {
7207e3e5701SJan Parcel 				/*
7217e3e5701SJan Parcel 				 * Need to know which suffixes are in use
7227e3e5701SJan Parcel 				 */
7237e3e5701SJan Parcel 				rc = (dmap_exact_dev(devmapp,
7247e3e5701SJan Parcel 				    dargs->devinfo->devlist, &suffix));
7257e3e5701SJan Parcel 
7267e3e5701SJan Parcel 				if (rc == 0) {
7277e3e5701SJan Parcel 					/*
7287e3e5701SJan Parcel 					 * Same type, different device.  Record
729*399f0677SJan Parcel 					 * device suffix already in use, if
730*399f0677SJan Parcel 					 * applicable.
7317e3e5701SJan Parcel 					 */
732*399f0677SJan Parcel 					if ((suffix < DA_MAX_DEVNO &&
733*399f0677SJan Parcel 					    suffix != -1) && stdtype)
734*399f0677SJan Parcel 						tmp_bitmap |=
735*399f0677SJan Parcel 						    (uint64_t)(1LL << suffix);
736*399f0677SJan Parcel 				} else if ((rc == 1) && !is_allocatable) {
737*399f0677SJan Parcel 					rc = 0;
7387e3e5701SJan Parcel 				} else {
7397e3e5701SJan Parcel 					/*
740*399f0677SJan Parcel 					 * Match allocatable on add is an error
7417e3e5701SJan Parcel 					 * or mapping attempt returned error
7427e3e5701SJan Parcel 					 */
743*399f0677SJan Parcel 					(void) snprintf(errmsg, sizeof (errmsg),
744*399f0677SJan Parcel 					    "Cannot add %s on node %s",
745*399f0677SJan Parcel 					    dargs->devinfo->devtype,
746*399f0677SJan Parcel 					    devmapp->dmap_devname);
747*399f0677SJan Parcel 					syslog(LOG_ERR, "%s", errmsg);
7487e3e5701SJan Parcel 					freedmapent(devmapp);
7497e3e5701SJan Parcel 					enddmapent();
7507e3e5701SJan Parcel 					return (2);
7517e3e5701SJan Parcel 				}
7527e3e5701SJan Parcel 			} else
7537e3e5701SJan Parcel 				/* add other transaction types as needed */
7547e3e5701SJan Parcel 				return (2);
755*399f0677SJan Parcel 		} else if ((dargs->optflag & DA_ADD) &&
756*399f0677SJan Parcel 		    (stdtype || is_allocatable) &&
757*399f0677SJan Parcel 		    dmap_exact_dev(devmapp, dargs->devinfo->devlist,
758*399f0677SJan Parcel 		    &suffix)) {
759*399f0677SJan Parcel 			/*
760*399f0677SJan Parcel 			 * no dups w/o DA_FORCE, even if type differs,
761*399f0677SJan Parcel 			 * if there is a chance this operation is
762*399f0677SJan Parcel 			 * machine-driven.  The 5 "standard types"
763*399f0677SJan Parcel 			 * can be machine-driven adds, and tend to
764*399f0677SJan Parcel 			 * be allocatable.
765*399f0677SJan Parcel 			 */
766*399f0677SJan Parcel 			(void) snprintf(errmsg, sizeof (errmsg),
767*399f0677SJan Parcel 			    "Cannot add %s on node %s type %s",
768*399f0677SJan Parcel 			    dargs->devinfo->devtype,
769*399f0677SJan Parcel 			    devmapp->dmap_devname,
770*399f0677SJan Parcel 			    devmapp->dmap_devtype);
771*399f0677SJan Parcel 			syslog(LOG_ERR, "%s", errmsg);
772*399f0677SJan Parcel 			freedmapent(devmapp);
773*399f0677SJan Parcel 			enddmapent();
774*399f0677SJan Parcel 			return (2);
775*399f0677SJan Parcel 		}
7767e3e5701SJan Parcel 
7777e3e5701SJan Parcel 		tmp_str = _dmap2strentry(devmapp);
7787e3e5701SJan Parcel 		if (tmp_str == NULL) {
7797e3e5701SJan Parcel 			freedmapent(devmapp);
7807e3e5701SJan Parcel 			enddmapent();
7817e3e5701SJan Parcel 			return (2);
7827e3e5701SJan Parcel 		}
7837e3e5701SJan Parcel 		/* retaining devmap entry: tmp_str->se_str */
7847e3e5701SJan Parcel 		tmp_str->se_next = NULL;
7857e3e5701SJan Parcel 		if (*head_devmapp == NULL) {
7867e3e5701SJan Parcel 			*head_devmapp = tail_str = tmp_str;
7877e3e5701SJan Parcel 		} else {
7887e3e5701SJan Parcel 			tail_str->se_next = tmp_str;
7897e3e5701SJan Parcel 			tail_str = tmp_str;
7907e3e5701SJan Parcel 		}
7917e3e5701SJan Parcel 		freedmapent(devmapp);
7927e3e5701SJan Parcel 	}
7937e3e5701SJan Parcel 	enddmapent();
7947e3e5701SJan Parcel 
7957e3e5701SJan Parcel 	/*
7967e3e5701SJan Parcel 	 * No need to rewrite the files if the item to be removed is not
7977e3e5701SJan Parcel 	 * in the files -- wait for another call on another darg.
7987e3e5701SJan Parcel 	 */
7997e3e5701SJan Parcel 	if ((dargs->optflag & DA_REMOVE) && !found)
8007e3e5701SJan Parcel 		return (0);
8017e3e5701SJan Parcel 
8027e3e5701SJan Parcel 
8037e3e5701SJan Parcel 	if (dargs->optflag & DA_ADD) {
804*399f0677SJan Parcel 		int len;
8057e3e5701SJan Parcel 		/*
806*399f0677SJan Parcel 		 * If we got here from an event, or from devfsadm,
807*399f0677SJan Parcel 		 * we know the stored devname is a useless guess,
808*399f0677SJan Parcel 		 * since the files had not been read when the name
809*399f0677SJan Parcel 		 * was chosen, and we don't keep them anywhere else
810*399f0677SJan Parcel 		 * that is sufficiently definitive.
8117e3e5701SJan Parcel 		 */
8127e3e5701SJan Parcel 
8137e3e5701SJan Parcel 		for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++)
8147e3e5701SJan Parcel 			if (!(tmp_bitmap & (1LL << tmp)))
8157e3e5701SJan Parcel 				break;
8167e3e5701SJan Parcel 		/* Future: support more than 64 hotplug devices per type? */
8177e3e5701SJan Parcel 		if (tmp > DA_MAX_DEVNO)
8187e3e5701SJan Parcel 			return (2);
8197e3e5701SJan Parcel 
820*399f0677SJan Parcel 		/*
821*399f0677SJan Parcel 		 * Let the caller choose the name unless BOTH the name and
822*399f0677SJan Parcel 		 * device type one of: cdrom, floppy, audio, rmdisk, or tape.
823*399f0677SJan Parcel 		 * (or sr, fd for unlabeled)
824*399f0677SJan Parcel 		 */
825*399f0677SJan Parcel 		len = strlen(defname);
826*399f0677SJan Parcel 		if (stdtype &&
827*399f0677SJan Parcel 		    (strncmp(dargs->devinfo->devname, defname, len) == 0)) {
8287e3e5701SJan Parcel 			(void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u",
829*399f0677SJan Parcel 			    defname, tmp);
830*399f0677SJan Parcel 			/* if need to free and safe to free */
831*399f0677SJan Parcel 			if (dargs->devinfo->devname != NULL &&
832*399f0677SJan Parcel 			    (dargs->optflag & DA_EVENT) != 0)
8337e3e5701SJan Parcel 				free(dargs->devinfo->devname);
8347e3e5701SJan Parcel 			dargs->devinfo->devname = strdup(new_devname);
8357e3e5701SJan Parcel 		}
836*399f0677SJan Parcel 	}
8377e3e5701SJan Parcel 
8387e3e5701SJan Parcel 	/*
8397e3e5701SJan Parcel 	 * Now adjust devalloc list to match devmaps
8407e3e5701SJan Parcel 	 * Note we now have the correct devname for da_match to use.
8417e3e5701SJan Parcel 	 */
8427e3e5701SJan Parcel 	setdaent();
8437e3e5701SJan Parcel 	while ((devallocp = getdaent()) != NULL) {
8447e3e5701SJan Parcel 		rc = da_match(devallocp, dargs);
8457e3e5701SJan Parcel 		if (rc == 1) {
8467e3e5701SJan Parcel 			if (dargs->optflag & DA_ADD) {
8477e3e5701SJan Parcel 				/* logging is on if DA_EVENT is set */
8487e3e5701SJan Parcel 				if (dargs->optflag & DA_EVENT) {
8497e3e5701SJan Parcel 					(void) snprintf(errmsg, sizeof (errmsg),
8507e3e5701SJan Parcel 					    "%s and %s out of sync,"
8517e3e5701SJan Parcel 					    "%s only in %s.",
8527e3e5701SJan Parcel 					    DEVALLOC, DEVMAP,
8537e3e5701SJan Parcel 					    devallocp->da_devname, DEVALLOC);
8547e3e5701SJan Parcel 					syslog(LOG_ERR, "%s", errmsg);
8557e3e5701SJan Parcel 				}
8567e3e5701SJan Parcel 				freedaent(devallocp);
8577e3e5701SJan Parcel 				enddaent();
8587e3e5701SJan Parcel 				return (2);
8597e3e5701SJan Parcel 			} else if (dargs->optflag & DA_REMOVE) {
8607e3e5701SJan Parcel 				/* make list w/o this entry */
8617e3e5701SJan Parcel 				freedaent(devallocp);
8627e3e5701SJan Parcel 				continue;
8637e3e5701SJan Parcel 			}
8647e3e5701SJan Parcel 		}
8657e3e5701SJan Parcel 		tmp_str = _da2strentry(dargs, devallocp);
8667e3e5701SJan Parcel 		if (tmp_str == NULL) {
8677e3e5701SJan Parcel 			freedaent(devallocp);
8687e3e5701SJan Parcel 			enddaent();
8697e3e5701SJan Parcel 			return (2);
8707e3e5701SJan Parcel 		}
8717e3e5701SJan Parcel 		/* retaining devalloc entry: tmp_str->se_str */
8727e3e5701SJan Parcel 		tmp_str->se_next = NULL;
8737e3e5701SJan Parcel 		if (*head_devallocp == NULL) {
8747e3e5701SJan Parcel 			*head_devallocp = tail_str = tmp_str;
8757e3e5701SJan Parcel 		} else {
8767e3e5701SJan Parcel 			tail_str->se_next = tmp_str;
8777e3e5701SJan Parcel 			tail_str = tmp_str;
8787e3e5701SJan Parcel 		}
8797e3e5701SJan Parcel 		freedaent(devallocp);
8807e3e5701SJan Parcel 	}
8817e3e5701SJan Parcel 	enddaent();
8827e3e5701SJan Parcel 
8837e3e5701SJan Parcel 	/* the caller needs to know if a remove needs to rewrite files */
8847e3e5701SJan Parcel 	if (dargs->optflag & DA_REMOVE)
8857e3e5701SJan Parcel 		return (1);  /* 0 and 2 cases returned earlier */
8867e3e5701SJan Parcel 
8877e3e5701SJan Parcel 	return (0);  /* Successful DA_ADD */
8887e3e5701SJan Parcel }
889*399f0677SJan Parcel 
8907e3e5701SJan Parcel /*
89145916cd2Sjpk  * _build_lists -
8927e3e5701SJan Parcel  *	Cycles through all the entries, stores them in memory. removes entries
89345916cd2Sjpk  *	with the given search_key (device name or type).
89445916cd2Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
89545916cd2Sjpk  *	error.
89645916cd2Sjpk  */
89745916cd2Sjpk static int
89845916cd2Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp,
89945916cd2Sjpk     strentry_t **head_devmapp)
90045916cd2Sjpk {
90145916cd2Sjpk 	int		rc = 0;
902*399f0677SJan Parcel 	int		found = 0;
90345916cd2Sjpk 	devalloc_t	*devallocp;
90445916cd2Sjpk 	devmap_t	*devmapp;
90545916cd2Sjpk 	strentry_t	*tail_str;
90645916cd2Sjpk 	strentry_t	*tmp_str;
90745916cd2Sjpk 
90845916cd2Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
90945916cd2Sjpk 		goto dmap_only;
91045916cd2Sjpk 
91145916cd2Sjpk 	/* build device_allocate */
91245916cd2Sjpk 	setdaent();
91345916cd2Sjpk 	while ((devallocp = getdaent()) != NULL) {
91445916cd2Sjpk 		rc = da_match(devallocp, dargs);
915*399f0677SJan Parcel 		/* if in _build_lists and DA_ADD is set, so is DA_FORCE */
91645916cd2Sjpk 		if (rc == 0) {
91745916cd2Sjpk 			tmp_str = _da2strentry(dargs, devallocp);
91845916cd2Sjpk 			if (tmp_str == NULL) {
91945916cd2Sjpk 				freedaent(devallocp);
92045916cd2Sjpk 				enddaent();
92145916cd2Sjpk 				return (2);
92245916cd2Sjpk 			}
92345916cd2Sjpk 			/* retaining devalloc entry: tmp_str->se_str */
92445916cd2Sjpk 			tmp_str->se_next = NULL;
92545916cd2Sjpk 			if (*head_devallocp == NULL) {
92645916cd2Sjpk 				*head_devallocp = tail_str = tmp_str;
92745916cd2Sjpk 			} else {
92845916cd2Sjpk 				tail_str->se_next = tmp_str;
92945916cd2Sjpk 				tail_str = tmp_str;
93045916cd2Sjpk 			}
931*399f0677SJan Parcel 		} else if (rc == 1)
932*399f0677SJan Parcel 			found = 1;
933*399f0677SJan Parcel 
93445916cd2Sjpk 		freedaent(devallocp);
93545916cd2Sjpk 	}
93645916cd2Sjpk 	enddaent();
93745916cd2Sjpk 
93845916cd2Sjpk dmap_only:
93945916cd2Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
94045916cd2Sjpk 		return (rc);
94145916cd2Sjpk 
94245916cd2Sjpk 	/* build device_maps */
94345916cd2Sjpk 	rc = 0;
94445916cd2Sjpk 	setdmapent();
94545916cd2Sjpk 	while ((devmapp = getdmapent()) != NULL) {
94645916cd2Sjpk 		rc = dm_match(devmapp, dargs);
94745916cd2Sjpk 		if (rc == 0) {
9487e3e5701SJan Parcel 			tmp_str = _dmap2strentry(devmapp);
94945916cd2Sjpk 			if (tmp_str == NULL) {
95045916cd2Sjpk 				freedmapent(devmapp);
95145916cd2Sjpk 				enddmapent();
95245916cd2Sjpk 				return (2);
95345916cd2Sjpk 			}
95445916cd2Sjpk 			/* retaining devmap entry: tmp_str->se_str */
95545916cd2Sjpk 			tmp_str->se_next = NULL;
95645916cd2Sjpk 			if (*head_devmapp == NULL) {
95745916cd2Sjpk 				*head_devmapp = tail_str = tmp_str;
95845916cd2Sjpk 			} else {
95945916cd2Sjpk 				tail_str->se_next = tmp_str;
96045916cd2Sjpk 				tail_str = tmp_str;
96145916cd2Sjpk 			}
96245916cd2Sjpk 		}
96345916cd2Sjpk 		freedmapent(devmapp);
96445916cd2Sjpk 	}
96545916cd2Sjpk 	enddmapent();
96645916cd2Sjpk 
967*399f0677SJan Parcel 	/* later code cleanup may cause the use of "found" in other cases */
968*399f0677SJan Parcel 	if (dargs->optflag & DA_REMOVE)
969*399f0677SJan Parcel 		return (found);
97045916cd2Sjpk 	return (rc);
97145916cd2Sjpk }
97245916cd2Sjpk 
97345916cd2Sjpk /*
97445916cd2Sjpk  * _write_defattrs
97545916cd2Sjpk  *	writes current entries to devalloc_defaults.
97645916cd2Sjpk  */
97745916cd2Sjpk static void
97845916cd2Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent)
97945916cd2Sjpk {
98045916cd2Sjpk 	strentry_t *tmp_str;
98145916cd2Sjpk 
98245916cd2Sjpk 	for (tmp_str = head_defent; tmp_str != NULL;
98345916cd2Sjpk 	    tmp_str = tmp_str->se_next) {
98445916cd2Sjpk 		(void) fputs(tmp_str->se_str, fp);
98545916cd2Sjpk 		(void) fputs("\n", fp);
98645916cd2Sjpk 	}
98745916cd2Sjpk 
98845916cd2Sjpk }
98945916cd2Sjpk 
99045916cd2Sjpk /*
99145916cd2Sjpk  * _write_device_allocate -
99245916cd2Sjpk  *	writes current entries in the list to device_allocate.
9937e3e5701SJan Parcel  *	frees the strings
99445916cd2Sjpk  */
99545916cd2Sjpk static void
99645916cd2Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
99745916cd2Sjpk {
99845916cd2Sjpk 	int		is_on = -1;
9997e3e5701SJan Parcel 	strentry_t	*tmp_str, *old_str;
100045916cd2Sjpk 	struct stat	dastat;
100145916cd2Sjpk 
100245916cd2Sjpk 	(void) fseek(dafp, (off_t)0, SEEK_SET);
100345916cd2Sjpk 
100445916cd2Sjpk 	/*
100545916cd2Sjpk 	 * if the devalloc on/off string existed before,
100645916cd2Sjpk 	 * put it back before anything else.
100745916cd2Sjpk 	 * we need to check for the string only if the file
100845916cd2Sjpk 	 * exists.
100945916cd2Sjpk 	 */
101045916cd2Sjpk 	if (stat(odevalloc, &dastat) == 0) {
101145916cd2Sjpk 		is_on = da_is_on();
101245916cd2Sjpk 		if (is_on == 0)
101345916cd2Sjpk 			(void) fputs(DA_OFF_STR, dafp);
101445916cd2Sjpk 		else if (is_on == 1)
101545916cd2Sjpk 			(void) fputs(DA_ON_STR, dafp);
101645916cd2Sjpk 	}
101745916cd2Sjpk 	tmp_str = head_devallocp;
101845916cd2Sjpk 	while (tmp_str) {
101945916cd2Sjpk 		(void) fputs(tmp_str->se_str, dafp);
102045916cd2Sjpk 		(void) fputs("\n", dafp);
10217e3e5701SJan Parcel 		old_str = tmp_str;
102245916cd2Sjpk 		tmp_str = tmp_str->se_next;
10237e3e5701SJan Parcel 		free(old_str);
102445916cd2Sjpk 	}
102545916cd2Sjpk }
102645916cd2Sjpk 
102745916cd2Sjpk /*
102845916cd2Sjpk  * _write_device_maps -
102945916cd2Sjpk  *	writes current entries in the list to device_maps.
10307e3e5701SJan Parcel  *	and frees the strings
103145916cd2Sjpk  */
103245916cd2Sjpk static void
103345916cd2Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
103445916cd2Sjpk {
10357e3e5701SJan Parcel 	strentry_t	*tmp_str, *old_str;
103645916cd2Sjpk 
103745916cd2Sjpk 	(void) fseek(dmfp, (off_t)0, SEEK_SET);
103845916cd2Sjpk 
103945916cd2Sjpk 	tmp_str = head_devmapp;
104045916cd2Sjpk 	while (tmp_str) {
104145916cd2Sjpk 		(void) fputs(tmp_str->se_str, dmfp);
104245916cd2Sjpk 		(void) fputs("\n", dmfp);
10437e3e5701SJan Parcel 		old_str = tmp_str;
104445916cd2Sjpk 		tmp_str = tmp_str->se_next;
10457e3e5701SJan Parcel 		free(old_str);
104645916cd2Sjpk 	}
104745916cd2Sjpk }
104845916cd2Sjpk 
104945916cd2Sjpk /*
105045916cd2Sjpk  * _write_new_defattrs
105145916cd2Sjpk  *	writes the new entry to devalloc_defaults.
105245916cd2Sjpk  *	returns 0 on success, -1 on error.
105345916cd2Sjpk  */
105445916cd2Sjpk static int
105545916cd2Sjpk _write_new_defattrs(FILE *fp, da_args *dargs)
105645916cd2Sjpk {
105745916cd2Sjpk 	int		count;
105845916cd2Sjpk 	char		*tok = NULL, *tokp = NULL;
105945916cd2Sjpk 	char		*lasts;
106045916cd2Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
106145916cd2Sjpk 
106245916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
106345916cd2Sjpk 		return (-1);
106445916cd2Sjpk 	if (!devinfo->devopts)
106545916cd2Sjpk 		return (0);
106645916cd2Sjpk 	(void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
106745916cd2Sjpk 	    KV_TOKEN_DELIMIT);
10687e3e5701SJan Parcel 	if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) {
106945916cd2Sjpk 		(void) strcpy(tokp, devinfo->devopts);
107045916cd2Sjpk 		if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) {
107145916cd2Sjpk 			(void) fprintf(fp, "%s", tok);
107245916cd2Sjpk 			count = 1;
107345916cd2Sjpk 		}
107445916cd2Sjpk 		while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
107545916cd2Sjpk 			if (count)
107645916cd2Sjpk 				(void) fprintf(fp, "%s", KV_DELIMITER);
107745916cd2Sjpk 			(void) fprintf(fp, "%s", tok);
107845916cd2Sjpk 			count++;
107945916cd2Sjpk 		}
108045916cd2Sjpk 	} else {
108145916cd2Sjpk 		(void) fprintf(fp, "%s", devinfo->devopts);
108245916cd2Sjpk 	}
108345916cd2Sjpk 
108445916cd2Sjpk 	return (0);
108545916cd2Sjpk }
108645916cd2Sjpk 
108745916cd2Sjpk /*
108845916cd2Sjpk  * _write_new_entry -
108945916cd2Sjpk  *	writes the new devalloc_t to device_allocate or the new devmap_t to
109045916cd2Sjpk  *	device_maps.
109145916cd2Sjpk  *	returns 0 on success, -1 on error.
109245916cd2Sjpk  */
109345916cd2Sjpk static int
109445916cd2Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag)
109545916cd2Sjpk {
109645916cd2Sjpk 	int		count;
109745916cd2Sjpk 	char		*tok = NULL, *tokp = NULL;
109845916cd2Sjpk 	char		*lasts;
109945916cd2Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
110045916cd2Sjpk 
110145916cd2Sjpk 	if (flag & DA_MAPS_ONLY)
110245916cd2Sjpk 		goto dmap_only;
110345916cd2Sjpk 
110445916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
110545916cd2Sjpk 		return (-1);
110645916cd2Sjpk 
110745916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
110845916cd2Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
110945916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
111045916cd2Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
111145916cd2Sjpk 	if (devinfo->devopts == NULL) {
111245916cd2Sjpk 		(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
111345916cd2Sjpk 		    KV_DELIMITER);
111445916cd2Sjpk 	} else {
11157e3e5701SJan Parcel 		if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1))
11167e3e5701SJan Parcel 		    != NULL) {
111745916cd2Sjpk 			(void) strcpy(tokp, devinfo->devopts);
111845916cd2Sjpk 			if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
111945916cd2Sjpk 			    NULL) {
112045916cd2Sjpk 				(void) fprintf(fp, "%s", tok);
112145916cd2Sjpk 				count = 1;
112245916cd2Sjpk 			}
112345916cd2Sjpk 			while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
112445916cd2Sjpk 			    &lasts)) != NULL) {
112545916cd2Sjpk 				if (count)
112645916cd2Sjpk 					(void) fprintf(fp, "%s",
112745916cd2Sjpk 					    KV_TOKEN_DELIMIT "\\\n\t");
112845916cd2Sjpk 				(void) fprintf(fp, "%s", tok);
112945916cd2Sjpk 				count++;
113045916cd2Sjpk 			}
113145916cd2Sjpk 			if (count)
113245916cd2Sjpk 				(void) fprintf(fp, "%s",
113345916cd2Sjpk 				    KV_DELIMITER "\\\n\t");
113445916cd2Sjpk 		} else {
113545916cd2Sjpk 			(void) fprintf(fp, "%s%s", devinfo->devopts,
113645916cd2Sjpk 			    KV_DELIMITER "\\\n\t");
113745916cd2Sjpk 		}
113845916cd2Sjpk 	}
113945916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
114045916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
114145916cd2Sjpk 	    (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
114245916cd2Sjpk 	    KV_DELIMITER);
114345916cd2Sjpk 	(void) fprintf(fp, "%s\n",
114445916cd2Sjpk 	    (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
114545916cd2Sjpk 
114645916cd2Sjpk dmap_only:
114745916cd2Sjpk 	if (flag & DA_ALLOC_ONLY)
114845916cd2Sjpk 		return (0);
114945916cd2Sjpk 
115045916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
115145916cd2Sjpk 		return (-1);
115245916cd2Sjpk 
115345916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n",
115445916cd2Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
115545916cd2Sjpk 	(void) fprintf(fp, "\t%s%s\\\n",
115645916cd2Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
115745916cd2Sjpk 	(void) fprintf(fp, "\t%s\n",
115845916cd2Sjpk 	    (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
115945916cd2Sjpk 
116045916cd2Sjpk 	return (0);
116145916cd2Sjpk }
116245916cd2Sjpk 
116345916cd2Sjpk /*
116445916cd2Sjpk  * _da_lock_devdb -
116545916cd2Sjpk  *	locks the database files; lock can be either broken explicitly by
116645916cd2Sjpk  *	closing the fd of the lock file, or it expires automatically at process
116745916cd2Sjpk  *	termination.
116845916cd2Sjpk  * 	returns fd of the lock file or -1 on error.
116945916cd2Sjpk  */
117045916cd2Sjpk int
117145916cd2Sjpk _da_lock_devdb(char *rootdir)
117245916cd2Sjpk {
117345916cd2Sjpk 	int		lockfd = -1;
117410ddde3aSaj 	int		ret;
117510ddde3aSaj 	int		count = 0;
117610ddde3aSaj 	int		retry = 10;
117710ddde3aSaj 	int		retry_sleep;
117810ddde3aSaj 	uint_t		seed;
117945916cd2Sjpk 	char		*lockfile;
118045916cd2Sjpk 	char		path[MAXPATHLEN];
118145916cd2Sjpk 	int		size = sizeof (path);
118245916cd2Sjpk 
118345916cd2Sjpk 	if (rootdir == NULL) {
118445916cd2Sjpk 		lockfile = DA_DB_LOCK;
118545916cd2Sjpk 	} else {
118645916cd2Sjpk 		path[0] = '\0';
118745916cd2Sjpk 		if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
118845916cd2Sjpk 			return (-1);
118945916cd2Sjpk 		lockfile = path;
119045916cd2Sjpk 	}
119145916cd2Sjpk 
119245916cd2Sjpk 	if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
119345916cd2Sjpk 		/* cannot open lock file */
119445916cd2Sjpk 		return (-1);
119545916cd2Sjpk 
119645916cd2Sjpk 	(void) fchown(lockfd, DA_UID, DA_GID);
119745916cd2Sjpk 
119845916cd2Sjpk 	if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
119945916cd2Sjpk 		/* cannot position lock file */
120045916cd2Sjpk 		(void) close(lockfd);
120145916cd2Sjpk 		return (-1);
120245916cd2Sjpk 	}
120310ddde3aSaj 	errno = 0;
120410ddde3aSaj 	while (retry > 0) {
120510ddde3aSaj 		count++;
120610ddde3aSaj 		seed = (uint_t)gethrtime();
120710ddde3aSaj 		ret = lockf(lockfd, F_TLOCK, 0);
120810ddde3aSaj 		if (ret == 0) {
120910ddde3aSaj 			(void) utime(lockfile, NULL);
121010ddde3aSaj 			return (lockfd);
121110ddde3aSaj 		}
121210ddde3aSaj 		if ((errno != EACCES) && (errno != EAGAIN)) {
121345916cd2Sjpk 			/* cannot set lock */
121445916cd2Sjpk 			(void) close(lockfd);
121545916cd2Sjpk 			return (-1);
121645916cd2Sjpk 		}
121710ddde3aSaj 		retry--;
121810ddde3aSaj 		retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count;
121910ddde3aSaj 		(void) sleep(retry_sleep);
122010ddde3aSaj 		errno = 0;
122110ddde3aSaj 	}
122245916cd2Sjpk 
122310ddde3aSaj 	return (-1);
122445916cd2Sjpk }
122545916cd2Sjpk 
122645916cd2Sjpk /*
122745916cd2Sjpk  * da_open_devdb -
122845916cd2Sjpk  *	opens one or both database files - device_allocate, device_maps - in
122945916cd2Sjpk  *	the specified mode.
123045916cd2Sjpk  *	locks the database files; lock is either broken explicitly by the
123145916cd2Sjpk  *	caller by closing the lock file fd, or it expires automatically at
123245916cd2Sjpk  *	process termination.
123345916cd2Sjpk  *	writes the file pointer of opened file in the input args - dafp, dmfp.
123445916cd2Sjpk  *	returns fd of the lock file on success, -2 if database file does not
123545916cd2Sjpk  *	exist, -1 on other errors.
123645916cd2Sjpk  */
123745916cd2Sjpk int
123845916cd2Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
123945916cd2Sjpk {
124045916cd2Sjpk 	int	oflag = 0;
124145916cd2Sjpk 	int	fda = -1;
124245916cd2Sjpk 	int	fdm = -1;
124345916cd2Sjpk 	int	lockfd = -1;
124445916cd2Sjpk 	char	*fname;
124545916cd2Sjpk 	char	*fmode;
124645916cd2Sjpk 	char	path[MAXPATHLEN];
124745916cd2Sjpk 	FILE	*devfile;
124845916cd2Sjpk 
124945916cd2Sjpk 	if ((dafp == NULL) && (dmfp == NULL))
125045916cd2Sjpk 		return (-1);
125145916cd2Sjpk 
125245916cd2Sjpk 	if (flag & DA_RDWR) {
125345916cd2Sjpk 		oflag = DA_RDWR;
1254004388ebScasper 		fmode = "r+F";
125545916cd2Sjpk 	} else if (flag & DA_RDONLY) {
125645916cd2Sjpk 		oflag = DA_RDONLY;
1257004388ebScasper 		fmode = "rF";
125845916cd2Sjpk 	}
125945916cd2Sjpk 
126045916cd2Sjpk 	if ((lockfd = _da_lock_devdb(rootdir)) == -1)
126145916cd2Sjpk 		return (-1);
126245916cd2Sjpk 
126345916cd2Sjpk 	if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
126445916cd2Sjpk 		goto dmap_only;
126545916cd2Sjpk 
126645916cd2Sjpk 	path[0] = '\0';
126745916cd2Sjpk 
126845916cd2Sjpk 	/*
126945916cd2Sjpk 	 * open the device allocation file
127045916cd2Sjpk 	 */
127145916cd2Sjpk 	if (rootdir == NULL) {
127245916cd2Sjpk 		fname = DEVALLOC;
127345916cd2Sjpk 	} else {
127445916cd2Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
127545916cd2Sjpk 		    DEVALLOC) >= sizeof (path)) {
127645916cd2Sjpk 			if (lockfd != -1)
127745916cd2Sjpk 				(void) close(lockfd);
127845916cd2Sjpk 			return (-1);
127945916cd2Sjpk 		}
128045916cd2Sjpk 		fname = path;
128145916cd2Sjpk 	}
128245916cd2Sjpk 	if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
128345916cd2Sjpk 		if (lockfd != -1)
128445916cd2Sjpk 			(void) close(lockfd);
128545916cd2Sjpk 		return ((errno == ENOENT) ? -2 : -1);
128645916cd2Sjpk 	}
128745916cd2Sjpk 	if ((devfile = fdopen(fda, fmode)) == NULL) {
128845916cd2Sjpk 		(void) close(fda);
128945916cd2Sjpk 		if (lockfd != -1)
129045916cd2Sjpk 			(void) close(lockfd);
129145916cd2Sjpk 		return (-1);
129245916cd2Sjpk 	}
129345916cd2Sjpk 	*dafp = devfile;
129445916cd2Sjpk 	(void) fchmod(fda, DA_DBMODE);
129545916cd2Sjpk 
129645916cd2Sjpk 	if ((flag & DA_ALLOC_ONLY))
129745916cd2Sjpk 		goto out;
129845916cd2Sjpk 
129945916cd2Sjpk dmap_only:
130045916cd2Sjpk 	path[0] = '\0';
130145916cd2Sjpk 	/*
130245916cd2Sjpk 	 * open the device map file
130345916cd2Sjpk 	 */
130445916cd2Sjpk 	if (rootdir == NULL) {
130545916cd2Sjpk 		fname = DEVMAP;
130645916cd2Sjpk 	} else {
130745916cd2Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
130845916cd2Sjpk 		    DEVMAP) >= sizeof (path)) {
130945916cd2Sjpk 			(void) close(fda);
131045916cd2Sjpk 			if (lockfd != -1)
131145916cd2Sjpk 				(void) close(lockfd);
131245916cd2Sjpk 			return (-1);
131345916cd2Sjpk 		}
131445916cd2Sjpk 		fname = path;
131545916cd2Sjpk 	}
131645916cd2Sjpk 
131745916cd2Sjpk 	if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
131845916cd2Sjpk 		if (lockfd != -1)
131945916cd2Sjpk 			(void) close(lockfd);
132045916cd2Sjpk 		return ((errno == ENOENT) ? -2 : -1);
132145916cd2Sjpk 	}
132245916cd2Sjpk 
132345916cd2Sjpk 	if ((devfile = fdopen(fdm, fmode)) == NULL) {
132445916cd2Sjpk 		(void) close(fdm);
132545916cd2Sjpk 		(void) close(fda);
132645916cd2Sjpk 		if (lockfd != -1)
132745916cd2Sjpk 			(void) close(lockfd);
132845916cd2Sjpk 		return (-1);
132945916cd2Sjpk 	}
133045916cd2Sjpk 	*dmfp = devfile;
133145916cd2Sjpk 	(void) fchmod(fdm, DA_DBMODE);
133245916cd2Sjpk 
133345916cd2Sjpk out:
133445916cd2Sjpk 	return (lockfd);
133545916cd2Sjpk }
133645916cd2Sjpk 
133745916cd2Sjpk /*
133845916cd2Sjpk  * _record_on_off -
133945916cd2Sjpk  *	adds either DA_ON_STR or DA_OFF_STR to device_allocate
134045916cd2Sjpk  *	returns 0 on success, -1 on error.
134145916cd2Sjpk  */
134245916cd2Sjpk static int
134345916cd2Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
134445916cd2Sjpk {
134545916cd2Sjpk 	int		dafd;
134645916cd2Sjpk 	int		nsize;
134745916cd2Sjpk 	int		nitems = 1;
134845916cd2Sjpk 	int		actionlen;
134945916cd2Sjpk 	int		str_found = 0;
135045916cd2Sjpk 	int		len = 0, nlen = 0, plen = 0;
135145916cd2Sjpk 	char		*ptr = NULL;
135245916cd2Sjpk 	char		*actionstr;
135345916cd2Sjpk 	char		*nbuf = NULL;
135445916cd2Sjpk 	char		line[MAX_CANON];
135545916cd2Sjpk 	struct stat	dastat;
135645916cd2Sjpk 
135745916cd2Sjpk 	if (dargs->optflag & DA_ON)
135845916cd2Sjpk 		actionstr = DA_ON_STR;
135945916cd2Sjpk 	else
136045916cd2Sjpk 		actionstr = DA_OFF_STR;
136145916cd2Sjpk 	actionlen = strlen(actionstr);
136245916cd2Sjpk 	dafd = fileno(dafp);
136345916cd2Sjpk 	if (fstat(dafd, &dastat) == -1)
136445916cd2Sjpk 		return (-1);
136545916cd2Sjpk 
136645916cd2Sjpk 	/* check the old device_allocate for on/off string */
136745916cd2Sjpk 	ptr = fgets(line, MAX_CANON, dafp);
136845916cd2Sjpk 	if (ptr != NULL) {
136945916cd2Sjpk 		if ((strcmp(line, DA_ON_STR) == 0) ||
137045916cd2Sjpk 		    (strcmp(line, DA_OFF_STR) == 0)) {
137145916cd2Sjpk 			str_found = 1;
137245916cd2Sjpk 			nsize = dastat.st_size;
137345916cd2Sjpk 		}
137445916cd2Sjpk 	}
137545916cd2Sjpk 	if (!ptr || !str_found) {
137645916cd2Sjpk 		/*
137745916cd2Sjpk 		 * the file never had either the on or the off string;
137845916cd2Sjpk 		 * make room for it.
137945916cd2Sjpk 		 */
138045916cd2Sjpk 		str_found = 0;
138145916cd2Sjpk 		nsize = dastat.st_size + actionlen + 1;
138245916cd2Sjpk 	}
13837e3e5701SJan Parcel 	if ((nbuf = (char *)malloc(nsize + 1)) == NULL)
138445916cd2Sjpk 		return (-1);
138545916cd2Sjpk 	nbuf[0] = '\0';
138645916cd2Sjpk 	/* put the on/off string */
138745916cd2Sjpk 	(void) strcpy(nbuf, actionstr);
138845916cd2Sjpk 	nlen = strlen(nbuf);
138945916cd2Sjpk 	plen = nlen;
139045916cd2Sjpk 	if (ptr && !str_found) {
139145916cd2Sjpk 		/* now put the first line that we read in fgets */
139245916cd2Sjpk 		nlen = plen + strlen(line) + 1;
139345916cd2Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
139445916cd2Sjpk 		if (len >= nsize) {
139545916cd2Sjpk 			free(nbuf);
139645916cd2Sjpk 			return (-1);
139745916cd2Sjpk 		}
139845916cd2Sjpk 		plen += len;
139945916cd2Sjpk 	}
140045916cd2Sjpk 
140145916cd2Sjpk 	/* now get the rest of the old file */
140245916cd2Sjpk 	while (fgets(line, MAX_CANON, dafp) != NULL) {
140345916cd2Sjpk 		nlen = plen + strlen(line) + 1;
140445916cd2Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
140545916cd2Sjpk 		if (len >= nsize) {
140645916cd2Sjpk 			free(nbuf);
140745916cd2Sjpk 			return (-1);
140845916cd2Sjpk 		}
140945916cd2Sjpk 		plen += len;
141045916cd2Sjpk 	}
141145916cd2Sjpk 	len = strlen(nbuf) + 1;
141245916cd2Sjpk 	if (len < nsize)
141345916cd2Sjpk 		nbuf[len] = '\n';
141445916cd2Sjpk 
141545916cd2Sjpk 	/* write the on/off str + the old device_allocate to the temp file */
141645916cd2Sjpk 	if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
141745916cd2Sjpk 		free(nbuf);
141845916cd2Sjpk 		return (-1);
141945916cd2Sjpk 	}
142045916cd2Sjpk 
142145916cd2Sjpk 	free(nbuf);
142245916cd2Sjpk 
142345916cd2Sjpk 	return (0);
142445916cd2Sjpk }
142545916cd2Sjpk 
142645916cd2Sjpk /*
142745916cd2Sjpk  * da_update_defattrs -
142845916cd2Sjpk  *	writes default attributes to devalloc_defaults
142945916cd2Sjpk  *	returns 0 on success, -1 on error.
143045916cd2Sjpk  */
143145916cd2Sjpk int
143245916cd2Sjpk da_update_defattrs(da_args *dargs)
143345916cd2Sjpk {
143445916cd2Sjpk 	int		rc = 0, lockfd = 0, tmpfd = 0;
143545916cd2Sjpk 	char		*defpath = DEFATTRS;
143645916cd2Sjpk 	char		*tmpdefpath = TMPATTRS;
143745916cd2Sjpk 	FILE		*tmpfp = NULL;
143845916cd2Sjpk 	struct stat	dstat;
143945916cd2Sjpk 	strentry_t	*head_defent = NULL;
144045916cd2Sjpk 
144145916cd2Sjpk 	if (dargs == NULL)
144245916cd2Sjpk 		return (0);
144345916cd2Sjpk 	if ((lockfd = _da_lock_devdb(NULL)) == -1)
144445916cd2Sjpk 		return (-1);
144545916cd2Sjpk 	if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
144645916cd2Sjpk 		(void) close(lockfd);
144745916cd2Sjpk 		return (-1);
144845916cd2Sjpk 	}
144945916cd2Sjpk 	(void) fchown(tmpfd, DA_UID, DA_GID);
145045916cd2Sjpk 	if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) {
145145916cd2Sjpk 		(void) close(tmpfd);
145245916cd2Sjpk 		(void) unlink(tmpdefpath);
145345916cd2Sjpk 		(void) close(lockfd);
145445916cd2Sjpk 		return (-1);
145545916cd2Sjpk 	}
145645916cd2Sjpk 	/*
145745916cd2Sjpk 	 * examine all entries, remove an old one if required, check
145845916cd2Sjpk 	 * if a new one needs to be added.
145945916cd2Sjpk 	 */
146045916cd2Sjpk 	if (stat(defpath, &dstat) == 0) {
146145916cd2Sjpk 		if ((rc = _build_defattrs(dargs, &head_defent)) != 0) {
146245916cd2Sjpk 			if (rc == 1) {
146345916cd2Sjpk 				(void) close(tmpfd);
146445916cd2Sjpk 				(void) unlink(tmpdefpath);
146545916cd2Sjpk 				(void) close(lockfd);
146645916cd2Sjpk 				return (rc);
146745916cd2Sjpk 			}
146845916cd2Sjpk 		}
146945916cd2Sjpk 	}
147045916cd2Sjpk 	/*
147145916cd2Sjpk 	 * write back any existing entries.
147245916cd2Sjpk 	 */
147345916cd2Sjpk 	_write_defattrs(tmpfp, head_defent);
147445916cd2Sjpk 
147545916cd2Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
147645916cd2Sjpk 		/* add new entries */
147745916cd2Sjpk 		rc = _write_new_defattrs(tmpfp, dargs);
147845916cd2Sjpk 		(void) fclose(tmpfp);
147945916cd2Sjpk 	} else {
148045916cd2Sjpk 		(void) fclose(tmpfp);
148145916cd2Sjpk 	}
148245916cd2Sjpk 	if (rename(tmpdefpath, defpath) != 0) {
148345916cd2Sjpk 		rc = -1;
148445916cd2Sjpk 		(void) unlink(tmpdefpath);
148545916cd2Sjpk 	}
148645916cd2Sjpk 	(void) close(lockfd);
148745916cd2Sjpk 
148845916cd2Sjpk 	return (rc);
148945916cd2Sjpk }
149045916cd2Sjpk 
149145916cd2Sjpk /*
149245916cd2Sjpk  * da_update_device -
14937e3e5701SJan Parcel  *	Writes existing entries and the SINGLE change requested by da_args,
14947e3e5701SJan Parcel  *	to device_allocate and device_maps.
14957e3e5701SJan Parcel  *	Returns 0 on success, -1 on error.
149645916cd2Sjpk  */
149745916cd2Sjpk int
149845916cd2Sjpk da_update_device(da_args *dargs)
149945916cd2Sjpk {
150045916cd2Sjpk 	int		rc;
150145916cd2Sjpk 	int		tafd = -1, tmfd = -1;
150245916cd2Sjpk 	int		lockfd = -1;
150345916cd2Sjpk 	char		*rootdir = NULL;
150410ddde3aSaj 	char		*apathp = NULL, *mpathp = NULL;
150510ddde3aSaj 	char		*dapathp = NULL, *dmpathp = NULL;
150610ddde3aSaj 	char		apath[MAXPATHLEN], mpath[MAXPATHLEN];
150710ddde3aSaj 	char		dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
150845916cd2Sjpk 	FILE		*tafp = NULL, *tmfp = NULL, *dafp = NULL;
150945916cd2Sjpk 	struct stat	dastat;
151045916cd2Sjpk 	devinfo_t	*devinfo;
151145916cd2Sjpk 	strentry_t	*head_devmapp = NULL;
151245916cd2Sjpk 	strentry_t	*head_devallocp = NULL;
151345916cd2Sjpk 
151445916cd2Sjpk 	if (dargs == NULL)
151545916cd2Sjpk 		return (0);
151645916cd2Sjpk 
151745916cd2Sjpk 	rootdir = dargs->rootdir;
151845916cd2Sjpk 	devinfo = dargs->devinfo;
151945916cd2Sjpk 
152045916cd2Sjpk 	/*
152145916cd2Sjpk 	 * adding/removing entries should be done in both
152245916cd2Sjpk 	 * device_allocate and device_maps. updates can be
152345916cd2Sjpk 	 * done in both or either of the files.
152445916cd2Sjpk 	 */
152545916cd2Sjpk 	if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
152645916cd2Sjpk 		if (dargs->optflag & DA_ALLOC_ONLY ||
152745916cd2Sjpk 		    dargs->optflag & DA_MAPS_ONLY)
152845916cd2Sjpk 			return (0);
152945916cd2Sjpk 	}
153045916cd2Sjpk 
153145916cd2Sjpk 	/*
153245916cd2Sjpk 	 * name, type and list are required fields for adding a new
153345916cd2Sjpk 	 * device.
153445916cd2Sjpk 	 */
153545916cd2Sjpk 	if ((dargs->optflag & DA_ADD) &&
153645916cd2Sjpk 	    ((devinfo->devname == NULL) ||
153745916cd2Sjpk 	    (devinfo->devtype == NULL) ||
153845916cd2Sjpk 	    (devinfo->devlist == NULL))) {
153945916cd2Sjpk 		return (-1);
154045916cd2Sjpk 	}
154145916cd2Sjpk 
154245916cd2Sjpk 	if (rootdir != NULL) {
154345916cd2Sjpk 		if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
154445916cd2Sjpk 		    TMPALLOC) >= sizeof (apath))
154545916cd2Sjpk 			return (-1);
154645916cd2Sjpk 		apathp = apath;
154745916cd2Sjpk 		if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
154845916cd2Sjpk 		    DEVALLOC) >= sizeof (dapath))
154945916cd2Sjpk 			return (-1);
155045916cd2Sjpk 		dapathp = dapath;
155145916cd2Sjpk 		if (!(dargs->optflag & DA_ALLOC_ONLY)) {
155245916cd2Sjpk 			if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
155345916cd2Sjpk 			    TMPMAP) >= sizeof (mpath))
155445916cd2Sjpk 				return (-1);
155545916cd2Sjpk 			mpathp = mpath;
155645916cd2Sjpk 			if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
155745916cd2Sjpk 			    DEVMAP) >= sizeof (dmpath))
155845916cd2Sjpk 				return (-1);
155945916cd2Sjpk 			dmpathp = dmpath;
156045916cd2Sjpk 		}
156145916cd2Sjpk 	} else {
156245916cd2Sjpk 		apathp = TMPALLOC;
156345916cd2Sjpk 		dapathp = DEVALLOC;
156445916cd2Sjpk 		mpathp = TMPMAP;
156545916cd2Sjpk 		dmpathp = DEVMAP;
156645916cd2Sjpk 	}
156745916cd2Sjpk 
156845916cd2Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
156945916cd2Sjpk 		goto dmap_only;
157045916cd2Sjpk 
157145916cd2Sjpk 	/*
157245916cd2Sjpk 	 * Check if we are here just to record on/off status of
157345916cd2Sjpk 	 * device_allocation.
157445916cd2Sjpk 	 */
157545916cd2Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
157645916cd2Sjpk 		lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
157745916cd2Sjpk 		    DA_RDONLY|DA_ALLOC_ONLY);
157845916cd2Sjpk 	else
157945916cd2Sjpk 		lockfd = _da_lock_devdb(rootdir);
158045916cd2Sjpk 	if (lockfd == -1)
158145916cd2Sjpk 		return (-1);
158245916cd2Sjpk 
158345916cd2Sjpk 	if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
158445916cd2Sjpk 		(void) close(lockfd);
158545916cd2Sjpk 		(void) fclose(dafp);
158645916cd2Sjpk 		return (-1);
158745916cd2Sjpk 	}
158845916cd2Sjpk 	(void) fchown(tafd, DA_UID, DA_GID);
158945916cd2Sjpk 	if ((tafp = fdopen(tafd, "r+")) == NULL) {
159045916cd2Sjpk 		(void) close(tafd);
159145916cd2Sjpk 		(void) unlink(apathp);
159245916cd2Sjpk 		(void) fclose(dafp);
159345916cd2Sjpk 		(void) close(lockfd);
159445916cd2Sjpk 		return (-1);
159545916cd2Sjpk 	}
159645916cd2Sjpk 
159745916cd2Sjpk 	/*
159845916cd2Sjpk 	 * We don't need to parse the file if we are here just to record
159945916cd2Sjpk 	 * on/off status of device_allocation.
160045916cd2Sjpk 	 */
160145916cd2Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
160245916cd2Sjpk 		if (_record_on_off(dargs, tafp, dafp) == -1) {
160345916cd2Sjpk 			(void) close(tafd);
160445916cd2Sjpk 			(void) unlink(apathp);
160545916cd2Sjpk 			(void) fclose(dafp);
160645916cd2Sjpk 			(void) close(lockfd);
160745916cd2Sjpk 			return (-1);
160845916cd2Sjpk 		}
160945916cd2Sjpk 		(void) fclose(dafp);
161045916cd2Sjpk 		goto out;
161145916cd2Sjpk 	}
161245916cd2Sjpk 
161345916cd2Sjpk 	/*
16147e3e5701SJan Parcel 	 * If reacting to a hotplug, read the file entries,
16157e3e5701SJan Parcel 	 * figure out what dname (tname + a new number) goes to the
16167e3e5701SJan Parcel 	 * device being added/removed, and create a good head_devallocp and
16177e3e5701SJan Parcel 	 * head_devmapp with everything good still in it (_rebuild_lists)
16187e3e5701SJan Parcel 	 *
16197e3e5701SJan Parcel 	 * Else examine all the entries, remove an old one if it is
16207e3e5701SJan Parcel 	 * a duplicate with a device being added, returning the
16217e3e5701SJan Parcel 	 * remaining list (_build_lists.)
16227e3e5701SJan Parcel 	 *
16237e3e5701SJan Parcel 	 * We need to do this only if the file exists already.
16247e3e5701SJan Parcel 	 *
16257e3e5701SJan Parcel 	 * Once we have built these lists, we need to free the strings
16267e3e5701SJan Parcel 	 * in the head_* arrays before returning.
162745916cd2Sjpk 	 */
162845916cd2Sjpk 	if (stat(dapathp, &dastat) == 0) {
16297e3e5701SJan Parcel 		/* for device allocation, the /etc files are the "master" */
16307e3e5701SJan Parcel 		if ((dargs->optflag & (DA_ADD| DA_EVENT)) &&
16317e3e5701SJan Parcel 		    (!(dargs->optflag & DA_FORCE)))
16327e3e5701SJan Parcel 			rc = _rebuild_lists(dargs, &head_devallocp,
16337e3e5701SJan Parcel 			    &head_devmapp);
16347e3e5701SJan Parcel 		else
16357e3e5701SJan Parcel 			rc = _build_lists(dargs, &head_devallocp,
16367e3e5701SJan Parcel 			    &head_devmapp);
16377e3e5701SJan Parcel 
16387e3e5701SJan Parcel 		if (rc != 0 && rc != 1) {
163945916cd2Sjpk 			(void) close(tafd);
164045916cd2Sjpk 			(void) unlink(apathp);
164145916cd2Sjpk 			(void) close(lockfd);
16427e3e5701SJan Parcel 			return (-1);
164345916cd2Sjpk 		}
16447e3e5701SJan Parcel 	} else
16457e3e5701SJan Parcel 		rc = 0;
16467e3e5701SJan Parcel 
16477e3e5701SJan Parcel 	if ((dargs->optflag & DA_REMOVE) && (rc == 0)) {
16487e3e5701SJan Parcel 		(void) close(tafd);
16497e3e5701SJan Parcel 		(void) unlink(apathp);
16507e3e5701SJan Parcel 		(void) close(lockfd);
16517e3e5701SJan Parcel 		return (0);
165245916cd2Sjpk 	}
16537e3e5701SJan Parcel 	/*
16547e3e5701SJan Parcel 	 * TODO: clean up the workings of DA_UPDATE.
16557e3e5701SJan Parcel 	 * Due to da_match looking at fields that are missing
16567e3e5701SJan Parcel 	 * in dargs for DA_UPDATE, the da_match call returns no match,
16577e3e5701SJan Parcel 	 * but due to the way _da2str combines the devalloc_t info with
16587e3e5701SJan Parcel 	 * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work.
16597e3e5701SJan Parcel 	 *
16607e3e5701SJan Parcel 	 * This would not scale if any type of update was ever needed
16617e3e5701SJan Parcel 	 * from the daemon.
16627e3e5701SJan Parcel 	 */
166345916cd2Sjpk 
166445916cd2Sjpk 	/*
16657e3e5701SJan Parcel 	 * Write out devallocp along with the devalloc on/off string.
166645916cd2Sjpk 	 */
166745916cd2Sjpk 	_write_device_allocate(dapathp, tafp, head_devallocp);
166845916cd2Sjpk 
166945916cd2Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
167045916cd2Sjpk 		goto out;
167145916cd2Sjpk 
167245916cd2Sjpk dmap_only:
167345916cd2Sjpk 	if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
167445916cd2Sjpk 		(void) close(tafd);
167545916cd2Sjpk 		(void) unlink(apathp);
167645916cd2Sjpk 		(void) close(lockfd);
167745916cd2Sjpk 		return (-1);
167845916cd2Sjpk 	}
167945916cd2Sjpk 	(void) fchown(tmfd, DA_UID, DA_GID);
168045916cd2Sjpk 	if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
168145916cd2Sjpk 		(void) close(tafd);
168245916cd2Sjpk 		(void) unlink(apathp);
168345916cd2Sjpk 		(void) close(tmfd);
168445916cd2Sjpk 		(void) unlink(mpathp);
168545916cd2Sjpk 		(void) close(lockfd);
168645916cd2Sjpk 		return (-1);
168745916cd2Sjpk 	}
168845916cd2Sjpk 
16897e3e5701SJan Parcel 	/*
16907e3e5701SJan Parcel 	 * Write back any non-removed pre-existing entries.
16917e3e5701SJan Parcel 	 */
169245916cd2Sjpk 	if (head_devmapp != NULL)
169345916cd2Sjpk 		_write_device_maps(tmfp, head_devmapp);
169445916cd2Sjpk 
169545916cd2Sjpk out:
16967e3e5701SJan Parcel 	/*
16977e3e5701SJan Parcel 	 * Add any new entries here.
16987e3e5701SJan Parcel 	 */
169945916cd2Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
170045916cd2Sjpk 		/* add any new entries */
170145916cd2Sjpk 		rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
170245916cd2Sjpk 		(void) fclose(tafp);
170345916cd2Sjpk 
170445916cd2Sjpk 		if (rc == 0)
170545916cd2Sjpk 			rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
170645916cd2Sjpk 		(void) fclose(tmfp);
170745916cd2Sjpk 	} else {
170845916cd2Sjpk 		if (tafp)
170945916cd2Sjpk 			(void) fclose(tafp);
171045916cd2Sjpk 		if (tmfp)
171145916cd2Sjpk 			(void) fclose(tmfp);
171245916cd2Sjpk 	}
171345916cd2Sjpk 
171445916cd2Sjpk 	rc = 0;
171545916cd2Sjpk 	if (!(dargs->optflag & DA_MAPS_ONLY)) {
171645916cd2Sjpk 		if (rename(apathp, dapathp) != 0) {
171745916cd2Sjpk 			rc = -1;
171845916cd2Sjpk 			(void) unlink(apathp);
171945916cd2Sjpk 		}
172045916cd2Sjpk 	}
172145916cd2Sjpk 	if (!(dargs->optflag & DA_ALLOC_ONLY)) {
172245916cd2Sjpk 		if (rename(mpathp, dmpathp) != 0) {
172345916cd2Sjpk 			rc = -1;
172445916cd2Sjpk 			(void) unlink(mpathp);
172545916cd2Sjpk 		}
172645916cd2Sjpk 	}
172745916cd2Sjpk 
172845916cd2Sjpk 	(void) close(lockfd);
172945916cd2Sjpk 
173045916cd2Sjpk 	return (rc);
173145916cd2Sjpk }
173245916cd2Sjpk 
173345916cd2Sjpk /*
173445916cd2Sjpk  * da_add_list -
173545916cd2Sjpk  *	adds new /dev link name to the linked list of devices.
173645916cd2Sjpk  *	returns 0 if link added successfully, -1 on error.
173745916cd2Sjpk  */
173845916cd2Sjpk int
173945916cd2Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
174045916cd2Sjpk {
174145916cd2Sjpk 	int		instance;
174245916cd2Sjpk 	int		nlen, plen;
174345916cd2Sjpk 	int		new_entry = 0;
174445916cd2Sjpk 	char		*dtype, *dexec, *tname, *kval;
174545916cd2Sjpk 	char		*minstr = NULL, *maxstr = NULL;
17467e3e5701SJan Parcel 	char		dname[DA_MAXNAME + 1];
174745916cd2Sjpk 	kva_t		*kva;
174845916cd2Sjpk 	deventry_t	*dentry = NULL, *nentry = NULL, *pentry = NULL;
174945916cd2Sjpk 	da_defs_t	*da_defs;
175045916cd2Sjpk 
175145916cd2Sjpk 	if (dlist == NULL || link == NULL)
175245916cd2Sjpk 		return (-1);
175345916cd2Sjpk 
175445916cd2Sjpk 	dname[0] = '\0';
175545916cd2Sjpk 	if (flag & DA_AUDIO) {
175645916cd2Sjpk 		dentry = dlist->audio;
175745916cd2Sjpk 		tname = DA_AUDIO_NAME;
175845916cd2Sjpk 		dtype = DA_AUDIO_TYPE;
175945916cd2Sjpk 		dexec = DA_DEFAULT_AUDIO_CLEAN;
176045916cd2Sjpk 	} else if (flag & DA_CD) {
176145916cd2Sjpk 		dentry = dlist->cd;
176245916cd2Sjpk 		tname = DA_CD_NAME;
176345916cd2Sjpk 		dtype = DA_CD_TYPE;
176445916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
176545916cd2Sjpk 	} else if (flag & DA_FLOPPY) {
176645916cd2Sjpk 		dentry = dlist->floppy;
176745916cd2Sjpk 		tname = DA_FLOPPY_NAME;
176845916cd2Sjpk 		dtype = DA_FLOPPY_TYPE;
176945916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
177045916cd2Sjpk 	} else if (flag & DA_TAPE) {
177145916cd2Sjpk 		dentry = dlist->tape;
177245916cd2Sjpk 		tname = DA_TAPE_NAME;
177345916cd2Sjpk 		dtype = DA_TAPE_TYPE;
177445916cd2Sjpk 		dexec = DA_DEFAULT_TAPE_CLEAN;
177545916cd2Sjpk 	} else if (flag & DA_RMDISK) {
177645916cd2Sjpk 		dentry = dlist->rmdisk;
177745916cd2Sjpk 		tname = DA_RMDISK_NAME;
177845916cd2Sjpk 		dtype = DA_RMDISK_TYPE;
177945916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
178045916cd2Sjpk 	} else {
178145916cd2Sjpk 		return (-1);
178245916cd2Sjpk 	}
178345916cd2Sjpk 
178445916cd2Sjpk 	for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
178545916cd2Sjpk 		pentry = nentry;
178645916cd2Sjpk 		(void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
178745916cd2Sjpk 		if (nentry->devinfo.instance == new_instance)
178845916cd2Sjpk 			/*
178945916cd2Sjpk 			 * Add the new link name to the list of links
179045916cd2Sjpk 			 * that the device 'dname' has.
179145916cd2Sjpk 			 */
179245916cd2Sjpk 			break;
179345916cd2Sjpk 	}
179445916cd2Sjpk 
179545916cd2Sjpk 	if (nentry == NULL) {
179645916cd2Sjpk 		/*
179745916cd2Sjpk 		 * Either this is the first entry ever, or no matching entry
179845916cd2Sjpk 		 * was found. Create a new one and add to the list.
179945916cd2Sjpk 		 */
180045916cd2Sjpk 		if (dentry == NULL)		/* first entry ever */
180145916cd2Sjpk 			instance = 0;
180245916cd2Sjpk 		else				/* no matching entry */
180345916cd2Sjpk 			instance++;
180445916cd2Sjpk 		(void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
180545916cd2Sjpk 		if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
180645916cd2Sjpk 		    NULL)
180745916cd2Sjpk 			return (-1);
180845916cd2Sjpk 		if (pentry != NULL)
180945916cd2Sjpk 			pentry->next = nentry;
181045916cd2Sjpk 		new_entry = 1;
181145916cd2Sjpk 		nentry->devinfo.devname = strdup(dname);
181245916cd2Sjpk 		nentry->devinfo.devtype = dtype;
181345916cd2Sjpk 		nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
181445916cd2Sjpk 		nentry->devinfo.devexec = dexec;
181545916cd2Sjpk 		nentry->devinfo.instance = new_instance;
181645916cd2Sjpk 		/*
181745916cd2Sjpk 		 * Look for default label range, authorizations and cleaning
181845916cd2Sjpk 		 * program in devalloc_defaults. If label range is not
181945916cd2Sjpk 		 * specified in devalloc_defaults, assume it to be admin_low
182045916cd2Sjpk 		 * to admin_high.
182145916cd2Sjpk 		 */
182245916cd2Sjpk 		minstr = DA_DEFAULT_MIN;
182345916cd2Sjpk 		maxstr = DA_DEFAULT_MAX;
182445916cd2Sjpk 		setdadefent();
182545916cd2Sjpk 		if (da_defs = getdadeftype(nentry->devinfo.devtype)) {
182645916cd2Sjpk 			kva = da_defs->devopts;
182745916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
182845916cd2Sjpk 				minstr = strdup(kval);
182945916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
183045916cd2Sjpk 				maxstr = strdup(kval);
183145916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
183245916cd2Sjpk 				nentry->devinfo.devauths = strdup(kval);
183345916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
183445916cd2Sjpk 				nentry->devinfo.devexec = strdup(kval);
183545916cd2Sjpk 			freedadefent(da_defs);
183645916cd2Sjpk 		}
183745916cd2Sjpk 		enddadefent();
183845916cd2Sjpk 		kval = NULL;
183945916cd2Sjpk 		nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
184045916cd2Sjpk 		    strlen(minstr) + strlen(KV_TOKEN_DELIMIT) +
184145916cd2Sjpk 		    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr)
184245916cd2Sjpk 		    + 1;			/* +1 for terminator */
184345916cd2Sjpk 		if (kval = (char *)malloc(nlen))
184445916cd2Sjpk 			(void) snprintf(kval, nlen, "%s%s%s%s%s%s%s",
184545916cd2Sjpk 			    DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT,
184645916cd2Sjpk 			    DAOPT_MAXLABEL, KV_ASSIGN, maxstr);
184745916cd2Sjpk 		nentry->devinfo.devopts = kval;
184845916cd2Sjpk 
184945916cd2Sjpk 		nentry->devinfo.devlist = NULL;
185045916cd2Sjpk 		nentry->next = NULL;
185145916cd2Sjpk 	}
185245916cd2Sjpk 
185345916cd2Sjpk 	nlen = strlen(link) + 1;		/* +1 terminator */
185445916cd2Sjpk 	if (nentry->devinfo.devlist) {
185545916cd2Sjpk 		plen = strlen(nentry->devinfo.devlist);
185645916cd2Sjpk 		nlen = nlen + plen + 1;	/* +1 for blank to separate entries */
185745916cd2Sjpk 	} else {
185845916cd2Sjpk 		plen = 0;
185945916cd2Sjpk 	}
186045916cd2Sjpk 
186145916cd2Sjpk 	if ((nentry->devinfo.devlist =
186245916cd2Sjpk 	    (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
186345916cd2Sjpk 		if (new_entry) {
186445916cd2Sjpk 			free(nentry->devinfo.devname);
186545916cd2Sjpk 			free(nentry);
186645916cd2Sjpk 			if (pentry != NULL)
186745916cd2Sjpk 				pentry->next = NULL;
186845916cd2Sjpk 		}
186945916cd2Sjpk 		return (-1);
187045916cd2Sjpk 	}
187145916cd2Sjpk 
187245916cd2Sjpk 	if (plen == 0)
187345916cd2Sjpk 		(void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
187445916cd2Sjpk 	else
187545916cd2Sjpk 		(void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
187645916cd2Sjpk 		    " %s", link);
187745916cd2Sjpk 
187845916cd2Sjpk 	if (pentry == NULL) {
187945916cd2Sjpk 		/*
188045916cd2Sjpk 		 * This is the first entry of this device type.
188145916cd2Sjpk 		 */
188245916cd2Sjpk 		if (flag & DA_AUDIO)
188345916cd2Sjpk 			dlist->audio = nentry;
188445916cd2Sjpk 		else if (flag & DA_CD)
188545916cd2Sjpk 			dlist->cd = nentry;
188645916cd2Sjpk 		else if (flag & DA_FLOPPY)
188745916cd2Sjpk 			dlist->floppy = nentry;
188845916cd2Sjpk 		else if (flag & DA_TAPE)
188945916cd2Sjpk 			dlist->tape = nentry;
189045916cd2Sjpk 		else if (flag & DA_RMDISK)
189145916cd2Sjpk 			dlist->rmdisk = nentry;
189245916cd2Sjpk 	}
189345916cd2Sjpk 
189445916cd2Sjpk 	return (0);
189545916cd2Sjpk }
189645916cd2Sjpk 
189745916cd2Sjpk /*
189845916cd2Sjpk  * da_remove_list -
189945916cd2Sjpk  *	removes a /dev link name from the linked list of devices.
190045916cd2Sjpk  *	returns type of device if link for that device removed
190145916cd2Sjpk  *	successfully, else returns -1 on error.
190245916cd2Sjpk  *	if all links for a device are removed, stores that device
190345916cd2Sjpk  *	name in devname.
190445916cd2Sjpk  */
190545916cd2Sjpk int
190645916cd2Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
190745916cd2Sjpk {
190845916cd2Sjpk 	int		flag;
190945916cd2Sjpk 	int		remove_dev = 0;
191045916cd2Sjpk 	int		nlen, plen, slen;
191145916cd2Sjpk 	char		*lasts, *lname, *oldlist;
191245916cd2Sjpk 	struct stat	rmstat;
191345916cd2Sjpk 	deventry_t	*dentry, *current, *prev;
191445916cd2Sjpk 
191545916cd2Sjpk 	if (type != NULL)
191645916cd2Sjpk 		flag = type;
191745916cd2Sjpk 	else if (link == NULL)
191845916cd2Sjpk 		return (-1);
191945916cd2Sjpk 	else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
192045916cd2Sjpk 		flag = DA_AUDIO;
192145916cd2Sjpk 	else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
192245916cd2Sjpk 	    strstr(link, "sr") || strstr(link, "rsr"))
192345916cd2Sjpk 		flag = DA_CD;
192445916cd2Sjpk 	else if (strstr(link, "fd") || strstr(link, "rfd") ||
192545916cd2Sjpk 	    strstr(link, "diskette") || strstr(link, "rdiskette"))
192645916cd2Sjpk 		flag = DA_FLOPPY;
192745916cd2Sjpk 	else if (strstr(link, DA_TAPE_NAME))
192845916cd2Sjpk 		flag = DA_TAPE;
192945916cd2Sjpk 	else
193045916cd2Sjpk 		flag = DA_RMDISK;
193145916cd2Sjpk 
193245916cd2Sjpk 	switch (type) {
193345916cd2Sjpk 	case DA_AUDIO:
193445916cd2Sjpk 		dentry = dlist->audio;
193545916cd2Sjpk 		break;
193645916cd2Sjpk 	case DA_CD:
193745916cd2Sjpk 		dentry = dlist->cd;
193845916cd2Sjpk 		break;
193945916cd2Sjpk 	case DA_FLOPPY:
194045916cd2Sjpk 		dentry = dlist->floppy;
194145916cd2Sjpk 		break;
194245916cd2Sjpk 	case DA_TAPE:
194345916cd2Sjpk 		dentry = dlist->tape;
194445916cd2Sjpk 		break;
194545916cd2Sjpk 	case DA_RMDISK:
194645916cd2Sjpk 		dentry = dlist->rmdisk;
194745916cd2Sjpk 		break;
194845916cd2Sjpk 	default:
194945916cd2Sjpk 		return (-1);
195045916cd2Sjpk 	}
195145916cd2Sjpk 
195245916cd2Sjpk 	if ((type != NULL) && (link == NULL)) {
195345916cd2Sjpk 		for (current = dentry, prev = dentry; current != NULL;
195445916cd2Sjpk 		    current = current->next) {
195545916cd2Sjpk 			oldlist = strdup(current->devinfo.devlist);
195645916cd2Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
195745916cd2Sjpk 			    lname != NULL;
195845916cd2Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
195945916cd2Sjpk 				if (stat(lname, &rmstat) != 0) {
196045916cd2Sjpk 					remove_dev = 1;
196145916cd2Sjpk 					goto remove_dev;
196245916cd2Sjpk 				}
196345916cd2Sjpk 			}
196445916cd2Sjpk 			prev = current;
196545916cd2Sjpk 		}
196645916cd2Sjpk 		return (-1);
196745916cd2Sjpk 	}
196845916cd2Sjpk 
196945916cd2Sjpk 	for (current = dentry, prev = dentry; current != NULL;
197045916cd2Sjpk 	    current = current->next) {
197145916cd2Sjpk 		plen = strlen(current->devinfo.devlist);
197245916cd2Sjpk 		nlen = strlen(link);
197345916cd2Sjpk 		if (plen == nlen) {
197445916cd2Sjpk 			if (strcmp(current->devinfo.devlist, link) == 0) {
197545916cd2Sjpk 				/* last name in the list */
197645916cd2Sjpk 				remove_dev = 1;
197745916cd2Sjpk 				break;
197845916cd2Sjpk 			}
197945916cd2Sjpk 		}
198045916cd2Sjpk 		if (strstr(current->devinfo.devlist, link)) {
198145916cd2Sjpk 			nlen = plen - nlen + 1;
198245916cd2Sjpk 			oldlist = strdup(current->devinfo.devlist);
198345916cd2Sjpk 			if ((current->devinfo.devlist =
198445916cd2Sjpk 			    (char *)realloc(current->devinfo.devlist,
198545916cd2Sjpk 			    nlen)) == NULL) {
198645916cd2Sjpk 				free(oldlist);
198745916cd2Sjpk 				return (-1);
198845916cd2Sjpk 			}
198945916cd2Sjpk 			current->devinfo.devlist[0] = '\0';
199045916cd2Sjpk 			nlen = plen = slen = 0;
199145916cd2Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
199245916cd2Sjpk 			    lname != NULL;
199345916cd2Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
199445916cd2Sjpk 				if (strcmp(lname, link) == 0)
199545916cd2Sjpk 					continue;
199645916cd2Sjpk 				nlen = strlen(lname) + plen + 1;
199745916cd2Sjpk 				if (plen == 0) {
199845916cd2Sjpk 					slen =
199945916cd2Sjpk 					    snprintf(current->devinfo.devlist,
200045916cd2Sjpk 					    nlen, "%s", lname);
200145916cd2Sjpk 				} else {
200245916cd2Sjpk 					slen =
200345916cd2Sjpk 					    snprintf(current->devinfo.devlist +
200410ddde3aSaj 					    plen, nlen - plen, " %s", lname);
200545916cd2Sjpk 				}
200645916cd2Sjpk 				plen = plen + slen + 1;
200745916cd2Sjpk 			}
200845916cd2Sjpk 			free(oldlist);
200945916cd2Sjpk 			break;
201045916cd2Sjpk 		}
201145916cd2Sjpk 		prev = current;
201245916cd2Sjpk 	}
201345916cd2Sjpk 
201445916cd2Sjpk remove_dev:
201545916cd2Sjpk 	if (remove_dev == 1) {
201645916cd2Sjpk 		(void) strlcpy(devname, current->devinfo.devname, size);
201745916cd2Sjpk 		free(current->devinfo.devname);
201845916cd2Sjpk 		free(current->devinfo.devlist);
201945916cd2Sjpk 		current->devinfo.devname = current->devinfo.devlist = NULL;
202045916cd2Sjpk 		prev->next = current->next;
202145916cd2Sjpk 		free(current);
202245916cd2Sjpk 		current = NULL;
202345916cd2Sjpk 	}
202445916cd2Sjpk 	if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
202545916cd2Sjpk 		if (prev->next) {
202645916cd2Sjpk 			/*
202745916cd2Sjpk 			 * what we removed above was the first entry
202845916cd2Sjpk 			 * in the list. make the next entry to be the
202945916cd2Sjpk 			 * first.
203045916cd2Sjpk 			 */
203145916cd2Sjpk 			current = prev->next;
203245916cd2Sjpk 		} else {
203345916cd2Sjpk 			/*
203445916cd2Sjpk 			 * the matching entry was the only entry in the list
203545916cd2Sjpk 			 * for this type.
203645916cd2Sjpk 			 */
203745916cd2Sjpk 			current = NULL;
203845916cd2Sjpk 		}
203945916cd2Sjpk 		if (flag & DA_AUDIO)
204045916cd2Sjpk 			dlist->audio = current;
204145916cd2Sjpk 		else if (flag & DA_CD)
204245916cd2Sjpk 			dlist->cd = current;
204345916cd2Sjpk 		else if (flag & DA_FLOPPY)
204445916cd2Sjpk 			dlist->floppy = current;
204545916cd2Sjpk 		else if (flag & DA_TAPE)
204645916cd2Sjpk 			dlist->tape = current;
204745916cd2Sjpk 		else if (flag & DA_RMDISK)
204845916cd2Sjpk 			dlist->rmdisk = current;
204945916cd2Sjpk 	}
205045916cd2Sjpk 
205145916cd2Sjpk 	return (flag);
205245916cd2Sjpk }
205345916cd2Sjpk 
205445916cd2Sjpk /*
20557e3e5701SJan Parcel  * da_rm_list_entry -
20567e3e5701SJan Parcel  *
20577e3e5701SJan Parcel  *	The adding of devnames to a devlist and the removal of a
20587e3e5701SJan Parcel  *	device are not symmetrical -- hot_cleanup gives a /devices
20597e3e5701SJan Parcel  *	name which is used to remove the dentry whose links all point to
20607e3e5701SJan Parcel  *	that /devices entry.
20617e3e5701SJan Parcel  *
20627e3e5701SJan Parcel  *	The link argument is present if available to make debugging
20637e3e5701SJan Parcel  *	easier.
20647e3e5701SJan Parcel  *
20657e3e5701SJan Parcel  *	da_rm_list_entry removes an entry from the linked list of devices.
20667e3e5701SJan Parcel  *
20677e3e5701SJan Parcel  *	Returns 1 if the devname was removed successfully,
20687e3e5701SJan Parcel  *	0 if not found, -1 for error.
20697e3e5701SJan Parcel  */
20707e3e5701SJan Parcel /*ARGSUSED*/
20717e3e5701SJan Parcel int
20727e3e5701SJan Parcel da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname)
20737e3e5701SJan Parcel {
20747e3e5701SJan Parcel 	int		retval = 0;
20757e3e5701SJan Parcel 	deventry_t	**dentry, *current, *prev;
20767e3e5701SJan Parcel 
20777e3e5701SJan Parcel 	switch (type) {
20787e3e5701SJan Parcel 	case DA_AUDIO:
20797e3e5701SJan Parcel 		dentry = &(dlist->audio);
20807e3e5701SJan Parcel 		break;
20817e3e5701SJan Parcel 	case DA_CD:
20827e3e5701SJan Parcel 		dentry = &(dlist->cd);
20837e3e5701SJan Parcel 		break;
20847e3e5701SJan Parcel 	case DA_FLOPPY:
20857e3e5701SJan Parcel 		dentry = &(dlist->floppy);
20867e3e5701SJan Parcel 		break;
20877e3e5701SJan Parcel 	case DA_TAPE:
20887e3e5701SJan Parcel 		dentry = &(dlist->tape);
20897e3e5701SJan Parcel 		break;
20907e3e5701SJan Parcel 	case DA_RMDISK:
20917e3e5701SJan Parcel 		dentry = &(dlist->rmdisk);
20927e3e5701SJan Parcel 		break;
20937e3e5701SJan Parcel 	default:
20947e3e5701SJan Parcel 		return (-1);
20957e3e5701SJan Parcel 	}
20967e3e5701SJan Parcel 
20977e3e5701SJan Parcel 	/* Presumably in daemon mode, no need to remove entry, list is empty */
20987e3e5701SJan Parcel 	if (*dentry == (deventry_t *)NULL)
20997e3e5701SJan Parcel 		return (0);
21007e3e5701SJan Parcel 
21017e3e5701SJan Parcel 	prev = NULL;
21027e3e5701SJan Parcel 	for (current = *dentry; current != NULL;
21037e3e5701SJan Parcel 	    prev = current, current = current->next) {
21047e3e5701SJan Parcel 		if (strcmp(devname, current->devinfo.devname))
21057e3e5701SJan Parcel 			continue;
21067e3e5701SJan Parcel 		retval = 1;
21077e3e5701SJan Parcel 		break;
21087e3e5701SJan Parcel 	}
21097e3e5701SJan Parcel 	if (retval == 0)
21107e3e5701SJan Parcel 		return (0);
21117e3e5701SJan Parcel 	free(current->devinfo.devname);
21127e3e5701SJan Parcel 	if (current->devinfo.devlist != NULL)
21137e3e5701SJan Parcel 		free(current->devinfo.devlist);
21147e3e5701SJan Parcel 	if (current->devinfo.devopts != NULL)
21157e3e5701SJan Parcel 		free(current->devinfo.devopts);
21167e3e5701SJan Parcel 
21177e3e5701SJan Parcel 	if (prev == NULL)
21187e3e5701SJan Parcel 		*dentry = current->next;
21197e3e5701SJan Parcel 	else
21207e3e5701SJan Parcel 		prev->next = current->next;
21217e3e5701SJan Parcel 
21227e3e5701SJan Parcel 	free(current);
21237e3e5701SJan Parcel 	return (retval);
21247e3e5701SJan Parcel }
21257e3e5701SJan Parcel 
21267e3e5701SJan Parcel /*
212745916cd2Sjpk  * da_is_on -
212845916cd2Sjpk  *	checks if device allocation feature is turned on.
212945916cd2Sjpk  *	returns 1 if on, 0 if off, -1 if status string not
213045916cd2Sjpk  *	found in device_allocate.
213145916cd2Sjpk  */
213245916cd2Sjpk int
213345916cd2Sjpk da_is_on()
213445916cd2Sjpk {
213545916cd2Sjpk 	return (getdaon());
213645916cd2Sjpk }
213745916cd2Sjpk 
213845916cd2Sjpk /*
213945916cd2Sjpk  * da_print_device -
214045916cd2Sjpk  *	debug routine to print device entries.
214145916cd2Sjpk  */
214245916cd2Sjpk void
214345916cd2Sjpk da_print_device(int flag, devlist_t *devlist)
214445916cd2Sjpk {
214545916cd2Sjpk 	deventry_t	*entry, *dentry;
214645916cd2Sjpk 	devinfo_t	*devinfo;
214745916cd2Sjpk 
214845916cd2Sjpk 	if (flag & DA_AUDIO)
214945916cd2Sjpk 		dentry = devlist->audio;
215045916cd2Sjpk 	else if (flag & DA_CD)
215145916cd2Sjpk 		dentry = devlist->cd;
215245916cd2Sjpk 	else if (flag & DA_FLOPPY)
215345916cd2Sjpk 		dentry = devlist->floppy;
215445916cd2Sjpk 	else if (flag & DA_TAPE)
215545916cd2Sjpk 		dentry = devlist->tape;
215645916cd2Sjpk 	else if (flag & DA_RMDISK)
215745916cd2Sjpk 		dentry = devlist->rmdisk;
215845916cd2Sjpk 	else
215945916cd2Sjpk 		return;
216045916cd2Sjpk 
216145916cd2Sjpk 	for (entry = dentry; entry != NULL; entry = entry->next) {
216245916cd2Sjpk 		devinfo = &(entry->devinfo);
216345916cd2Sjpk 		(void) fprintf(stdout, "name: %s\n", devinfo->devname);
216445916cd2Sjpk 		(void) fprintf(stdout, "type: %s\n", devinfo->devtype);
216545916cd2Sjpk 		(void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
216645916cd2Sjpk 		(void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
216745916cd2Sjpk 		(void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);
216845916cd2Sjpk 	}
216945916cd2Sjpk }
2170