xref: /titanic_50/usr/src/lib/libbsm/common/devalloc.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
1*45916cd2Sjpk /*
2*45916cd2Sjpk  * CDDL HEADER START
3*45916cd2Sjpk  *
4*45916cd2Sjpk  * The contents of this file are subject to the terms of the
5*45916cd2Sjpk  * Common Development and Distribution License (the "License").
6*45916cd2Sjpk  * You may not use this file except in compliance with the License.
7*45916cd2Sjpk  *
8*45916cd2Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*45916cd2Sjpk  * or http://www.opensolaris.org/os/licensing.
10*45916cd2Sjpk  * See the License for the specific language governing permissions
11*45916cd2Sjpk  * and limitations under the License.
12*45916cd2Sjpk  *
13*45916cd2Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
14*45916cd2Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*45916cd2Sjpk  * If applicable, add the following below this CDDL HEADER, with the
16*45916cd2Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
17*45916cd2Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
18*45916cd2Sjpk  *
19*45916cd2Sjpk  * CDDL HEADER END
20*45916cd2Sjpk  */
21*45916cd2Sjpk 
22*45916cd2Sjpk /*
23*45916cd2Sjpk  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*45916cd2Sjpk  * Use is subject to license terms.
25*45916cd2Sjpk  */
26*45916cd2Sjpk 
27*45916cd2Sjpk #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*45916cd2Sjpk 
29*45916cd2Sjpk #include <stdlib.h>
30*45916cd2Sjpk #include <ctype.h>
31*45916cd2Sjpk #include <unistd.h>
32*45916cd2Sjpk #include <limits.h>
33*45916cd2Sjpk #include <fcntl.h>
34*45916cd2Sjpk #include <sys/types.h>
35*45916cd2Sjpk #include <sys/stat.h>
36*45916cd2Sjpk #include <utime.h>
37*45916cd2Sjpk #include <synch.h>
38*45916cd2Sjpk #include <strings.h>
39*45916cd2Sjpk #include <string.h>
40*45916cd2Sjpk #include <libintl.h>
41*45916cd2Sjpk #include <errno.h>
42*45916cd2Sjpk #include <auth_list.h>
43*45916cd2Sjpk #include <bsm/devices.h>
44*45916cd2Sjpk #include <bsm/devalloc.h>
45*45916cd2Sjpk 
46*45916cd2Sjpk #define	DA_DEFS	"/etc/security/tsol/devalloc_defaults"
47*45916cd2Sjpk 
48*45916cd2Sjpk extern int _readbufline(char *, int, char *, int, int *);
49*45916cd2Sjpk extern char *strtok_r(char *, const char *, char **);
50*45916cd2Sjpk extern char *_strtok_escape(char *, char *, char **);
51*45916cd2Sjpk extern int getdaon(void);
52*45916cd2Sjpk extern int da_matchname(devalloc_t *, char *);
53*45916cd2Sjpk extern int da_match(devalloc_t *, da_args *);
54*45916cd2Sjpk extern int dmap_matchname(devmap_t *, char *);
55*45916cd2Sjpk extern int dm_match(devmap_t *, da_args *);
56*45916cd2Sjpk 
57*45916cd2Sjpk /*
58*45916cd2Sjpk  * The following structure is for recording old entries to be retained.
59*45916cd2Sjpk  * We read the entries from the database into a linked list in memory,
60*45916cd2Sjpk  * then turn around and write them out again.
61*45916cd2Sjpk  */
62*45916cd2Sjpk typedef struct strentry {
63*45916cd2Sjpk 	struct strentry	*se_next;
64*45916cd2Sjpk 	char		se_str[4096 + 1];
65*45916cd2Sjpk } strentry_t;
66*45916cd2Sjpk 
67*45916cd2Sjpk /*
68*45916cd2Sjpk  * da_check_longindevperm -
69*45916cd2Sjpk  *	reads /etc/logindevperm and checks if specified device is in the file.
70*45916cd2Sjpk  *	returns 1 if specified device found in /etc/logindevperm, else returns 0
71*45916cd2Sjpk  */
72*45916cd2Sjpk int
73*45916cd2Sjpk da_check_logindevperm(char *devname)
74*45916cd2Sjpk {
75*45916cd2Sjpk 	int		ret = 0;
76*45916cd2Sjpk 	int		fd = -1;
77*45916cd2Sjpk 	int		nlen, plen, slen, lineno, fsize;
78*45916cd2Sjpk 	char		line[MAX_CANON];
79*45916cd2Sjpk 	char		*field_delims = " \t\n";
80*45916cd2Sjpk 	char		*fbuf = NULL;
81*45916cd2Sjpk 	char		*ptr, *device;
82*45916cd2Sjpk 	char		*lasts = NULL;
83*45916cd2Sjpk 	FILE		*fp;
84*45916cd2Sjpk 	struct stat	f_stat;
85*45916cd2Sjpk 
86*45916cd2Sjpk 	/*
87*45916cd2Sjpk 	 * check if /etc/logindevperm exists and get its size
88*45916cd2Sjpk 	 */
89*45916cd2Sjpk 	if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1)
90*45916cd2Sjpk 		return (0);
91*45916cd2Sjpk 	if (fstat(fd, &f_stat) != 0) {
92*45916cd2Sjpk 		(void) close(fd);
93*45916cd2Sjpk 		return (0);
94*45916cd2Sjpk 	}
95*45916cd2Sjpk 	fsize = f_stat.st_size;
96*45916cd2Sjpk 	if ((fbuf = (char *)malloc(fsize)) == NULL) {
97*45916cd2Sjpk 		(void) close(fd);
98*45916cd2Sjpk 		return (0);
99*45916cd2Sjpk 	}
100*45916cd2Sjpk 	if ((fp = fdopen(fd, "r")) == NULL) {
101*45916cd2Sjpk 		free(fbuf);
102*45916cd2Sjpk 		(void) close(fd);
103*45916cd2Sjpk 		return (0);
104*45916cd2Sjpk 	}
105*45916cd2Sjpk 
106*45916cd2Sjpk 	/*
107*45916cd2Sjpk 	 * read and parse /etc/logindevperm
108*45916cd2Sjpk 	 */
109*45916cd2Sjpk 	plen = nlen = lineno = 0;
110*45916cd2Sjpk 	while (fgets(line, MAX_CANON, fp) != NULL) {
111*45916cd2Sjpk 		lineno++;
112*45916cd2Sjpk 		if ((ptr = strchr(line, '#')) != NULL)
113*45916cd2Sjpk 			*ptr = '\0';	/* handle comments */
114*45916cd2Sjpk 		if (strtok_r(line, field_delims, &lasts) == NULL)
115*45916cd2Sjpk 			continue;	/* ignore blank lines */
116*45916cd2Sjpk 		if (strtok_r(NULL, field_delims, &lasts) == NULL)
117*45916cd2Sjpk 			/* invalid entry */
118*45916cd2Sjpk 			continue;
119*45916cd2Sjpk 		if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL)
120*45916cd2Sjpk 			/* empty device list */
121*45916cd2Sjpk 			continue;
122*45916cd2Sjpk 		nlen = strlen(ptr) + 1;		/* +1 terminator */
123*45916cd2Sjpk 		nlen += (plen + 1);
124*45916cd2Sjpk 		if (plen == 0)
125*45916cd2Sjpk 			slen = snprintf(fbuf, nlen, "%s", ptr);
126*45916cd2Sjpk 		else
127*45916cd2Sjpk 			slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr);
128*45916cd2Sjpk 		if (slen >= fsize) {
129*45916cd2Sjpk 			fbuf[0] = '\0';
130*45916cd2Sjpk 			(void) fclose(fp);
131*45916cd2Sjpk 			return (slen);
132*45916cd2Sjpk 		}
133*45916cd2Sjpk 		plen += slen;
134*45916cd2Sjpk 	}
135*45916cd2Sjpk 	(void) fclose(fp);
136*45916cd2Sjpk 
137*45916cd2Sjpk 	/*
138*45916cd2Sjpk 	 * check if devname exists in /etc/logindevperm
139*45916cd2Sjpk 	 */
140*45916cd2Sjpk 	device = strtok_r(fbuf, ":", &lasts);
141*45916cd2Sjpk 	while (device != NULL) {
142*45916cd2Sjpk 		/*
143*45916cd2Sjpk 		 * device and devname may be one of these types -
144*45916cd2Sjpk 		 *    /dev/xx
145*45916cd2Sjpk 		 *    /dev/xx*
146*45916cd2Sjpk 		 *    /dev/dir/xx
147*45916cd2Sjpk 		 *    /dev/dir/xx*
148*45916cd2Sjpk 		 *    /dev/dir/"*"
149*45916cd2Sjpk 		 */
150*45916cd2Sjpk 		if (strcmp(device, devname) == 0) {
151*45916cd2Sjpk 			/* /dev/xx, /dev/dir/xx */
152*45916cd2Sjpk 			free(fbuf);
153*45916cd2Sjpk 			return (1);
154*45916cd2Sjpk 		}
155*45916cd2Sjpk 		if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) {
156*45916cd2Sjpk 			/* all wildcard types */
157*45916cd2Sjpk 			*ptr = '\0';
158*45916cd2Sjpk 			if (strncmp(device, devname, strlen(device)) == 0) {
159*45916cd2Sjpk 				free(fbuf);
160*45916cd2Sjpk 				return (1);
161*45916cd2Sjpk 			}
162*45916cd2Sjpk 		}
163*45916cd2Sjpk 		device = strtok_r(NULL, ":", &lasts);
164*45916cd2Sjpk 	}
165*45916cd2Sjpk 
166*45916cd2Sjpk 	return (ret);
167*45916cd2Sjpk }
168*45916cd2Sjpk 
169*45916cd2Sjpk /*
170*45916cd2Sjpk  * _da_read_file -
171*45916cd2Sjpk  *	establishes readers/writer lock on fname; reads in the file if its
172*45916cd2Sjpk  *	contents changed since the last time we read it.
173*45916cd2Sjpk  *	returns size of buffer read, or -1 on failure.
174*45916cd2Sjpk  */
175*45916cd2Sjpk int
176*45916cd2Sjpk _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock,
177*45916cd2Sjpk     int flag)
178*45916cd2Sjpk {
179*45916cd2Sjpk 	int		fd = -1;
180*45916cd2Sjpk 	int		fsize = 0;
181*45916cd2Sjpk 	time_t		newtime;
182*45916cd2Sjpk 	FILE		*fp = NULL;
183*45916cd2Sjpk 	struct stat	f_stat;
184*45916cd2Sjpk 
185*45916cd2Sjpk 	if (flag & DA_FORCE)
186*45916cd2Sjpk 		*ftime = 0;
187*45916cd2Sjpk 
188*45916cd2Sjpk 	/* check the size and the time stamp on the file */
189*45916cd2Sjpk 	if (rw_rdlock(flock) != 0)
190*45916cd2Sjpk 		return (-1);
191*45916cd2Sjpk 	if (stat(fname, &f_stat) != 0) {
192*45916cd2Sjpk 		(void) rw_unlock(flock);
193*45916cd2Sjpk 		return (-1);
194*45916cd2Sjpk 	}
195*45916cd2Sjpk 	fsize = f_stat.st_size;
196*45916cd2Sjpk 	newtime = f_stat.st_mtime;
197*45916cd2Sjpk 	(void) rw_unlock(flock);
198*45916cd2Sjpk 
199*45916cd2Sjpk 	while (newtime > *ftime) {
200*45916cd2Sjpk 		/*
201*45916cd2Sjpk 		 * file has been modified since we last read it; or this
202*45916cd2Sjpk 		 * is a forced read.
203*45916cd2Sjpk 		 * read file into the buffer with rw lock.
204*45916cd2Sjpk 		 */
205*45916cd2Sjpk 		if (rw_wrlock(flock) != 0)
206*45916cd2Sjpk 			return (-1);
207*45916cd2Sjpk 		if ((fp = fopen(fname, "r")) == NULL) {
208*45916cd2Sjpk 			(void) rw_unlock(flock);
209*45916cd2Sjpk 			return (-1);
210*45916cd2Sjpk 		}
211*45916cd2Sjpk 		fd = fileno(fp);
212*45916cd2Sjpk 		if (*fbuf != NULL) {
213*45916cd2Sjpk 			free(*fbuf);
214*45916cd2Sjpk 			*fbuf = NULL;
215*45916cd2Sjpk 		}
216*45916cd2Sjpk 		if ((*fbuf = malloc(fsize)) == NULL) {
217*45916cd2Sjpk 			(void) rw_unlock(flock);
218*45916cd2Sjpk 			(void) close(fd);
219*45916cd2Sjpk 			return (-1);
220*45916cd2Sjpk 		}
221*45916cd2Sjpk 		if (read(fd, *fbuf, fsize) < fsize) {
222*45916cd2Sjpk 			free(*fbuf);
223*45916cd2Sjpk 			(void) rw_unlock(flock);
224*45916cd2Sjpk 			(void) close(fd);
225*45916cd2Sjpk 			return (-1);
226*45916cd2Sjpk 		}
227*45916cd2Sjpk 		(void) rw_unlock(flock);
228*45916cd2Sjpk 		/*
229*45916cd2Sjpk 		 * verify that the file did not change just after we read it.
230*45916cd2Sjpk 		 */
231*45916cd2Sjpk 		if (rw_rdlock(flock) != 0) {
232*45916cd2Sjpk 			free(*fbuf);
233*45916cd2Sjpk 			(void) close(fd);
234*45916cd2Sjpk 			return (-1);
235*45916cd2Sjpk 		}
236*45916cd2Sjpk 		if (stat(fname, &f_stat) != 0) {
237*45916cd2Sjpk 			free(*fbuf);
238*45916cd2Sjpk 			(void) rw_unlock(flock);
239*45916cd2Sjpk 			(void) close(fd);
240*45916cd2Sjpk 			return (-1);
241*45916cd2Sjpk 		}
242*45916cd2Sjpk 		fsize = f_stat.st_size;
243*45916cd2Sjpk 		newtime = f_stat.st_mtime;
244*45916cd2Sjpk 		(void) rw_unlock(flock);
245*45916cd2Sjpk 		(void) close(fd);
246*45916cd2Sjpk 		*ftime = newtime;
247*45916cd2Sjpk 	}
248*45916cd2Sjpk 
249*45916cd2Sjpk 	return (fsize);
250*45916cd2Sjpk }
251*45916cd2Sjpk 
252*45916cd2Sjpk /*
253*45916cd2Sjpk  * _update_zonename -
254*45916cd2Sjpk  *	add/remove current zone's name to the given devalloc_t.
255*45916cd2Sjpk  */
256*45916cd2Sjpk void
257*45916cd2Sjpk _update_zonename(da_args *dargs, devalloc_t *dap)
258*45916cd2Sjpk {
259*45916cd2Sjpk 	int		i, j;
260*45916cd2Sjpk 	int		oldsize, newsize;
261*45916cd2Sjpk 	int		has_zonename = 0;
262*45916cd2Sjpk 	char		*zonename;
263*45916cd2Sjpk 	kva_t		*newkva, *oldkva;
264*45916cd2Sjpk 	kv_t		*newdata, *olddata;
265*45916cd2Sjpk 	devinfo_t	*devinfo;
266*45916cd2Sjpk 
267*45916cd2Sjpk 	devinfo = dargs->devinfo;
268*45916cd2Sjpk 	oldkva = dap->da_devopts;
269*45916cd2Sjpk 	if (oldkva == NULL) {
270*45916cd2Sjpk 		if (dargs->optflag & DA_REMOVE_ZONE)
271*45916cd2Sjpk 			return;
272*45916cd2Sjpk 		if (dargs->optflag & DA_ADD_ZONE) {
273*45916cd2Sjpk 			newkva = _str2kva(devinfo->devopts, KV_ASSIGN,
274*45916cd2Sjpk 			    KV_TOKEN_DELIMIT);
275*45916cd2Sjpk 			if (newkva != NULL)
276*45916cd2Sjpk 				dap->da_devopts = newkva;
277*45916cd2Sjpk 			return;
278*45916cd2Sjpk 		}
279*45916cd2Sjpk 	}
280*45916cd2Sjpk 	newsize = oldsize = oldkva->length;
281*45916cd2Sjpk 	if (kva_match(oldkva, DAOPT_ZONE))
282*45916cd2Sjpk 		has_zonename = 1;
283*45916cd2Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
284*45916cd2Sjpk 		if ((zonename = index(devinfo->devopts, '=')) == NULL)
285*45916cd2Sjpk 			return;
286*45916cd2Sjpk 		zonename++;
287*45916cd2Sjpk 		if (has_zonename) {
288*45916cd2Sjpk 			(void) _insert2kva(oldkva, DAOPT_ZONE, zonename);
289*45916cd2Sjpk 			return;
290*45916cd2Sjpk 		}
291*45916cd2Sjpk 		newsize += 1;
292*45916cd2Sjpk 	} else if (dargs->optflag & DA_REMOVE_ZONE) {
293*45916cd2Sjpk 		if (has_zonename) {
294*45916cd2Sjpk 			newsize -= 1;
295*45916cd2Sjpk 			if (newsize == 0) {
296*45916cd2Sjpk 				/*
297*45916cd2Sjpk 				 * If zone name was the only key/value pair,
298*45916cd2Sjpk 				 * put 'reserved' in the empty slot.
299*45916cd2Sjpk 				 */
300*45916cd2Sjpk 				_kva_free(oldkva);
301*45916cd2Sjpk 				dap->da_devopts = NULL;
302*45916cd2Sjpk 				return;
303*45916cd2Sjpk 			}
304*45916cd2Sjpk 		} else {
305*45916cd2Sjpk 			return;
306*45916cd2Sjpk 		}
307*45916cd2Sjpk 	}
308*45916cd2Sjpk 	newkva = _new_kva(newsize);
309*45916cd2Sjpk 	newkva->length = 0;
310*45916cd2Sjpk 	newdata = newkva->data;
311*45916cd2Sjpk 	olddata = oldkva->data;
312*45916cd2Sjpk 	for (i = 0, j = 0; i < oldsize; i++) {
313*45916cd2Sjpk 		if ((dargs->optflag & DA_REMOVE_ZONE) &&
314*45916cd2Sjpk 		    (strcmp(olddata[i].key, DAOPT_ZONE) == 0))
315*45916cd2Sjpk 			continue;
316*45916cd2Sjpk 		newdata[j].key = strdup(olddata[i].key);
317*45916cd2Sjpk 		newdata[j].value = strdup(olddata[i].value);
318*45916cd2Sjpk 		newkva->length++;
319*45916cd2Sjpk 		j++;
320*45916cd2Sjpk 	}
321*45916cd2Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
322*45916cd2Sjpk 		newdata[j].key = strdup(DAOPT_ZONE);
323*45916cd2Sjpk 		newdata[j].value = strdup(zonename);
324*45916cd2Sjpk 		newkva->length++;
325*45916cd2Sjpk 	}
326*45916cd2Sjpk 	_kva_free(oldkva);
327*45916cd2Sjpk 	dap->da_devopts = newkva;
328*45916cd2Sjpk }
329*45916cd2Sjpk 
330*45916cd2Sjpk /*
331*45916cd2Sjpk  * _dmap2str -
332*45916cd2Sjpk  *	converts a device_map entry into a printable string
333*45916cd2Sjpk  *	returns 0 on success, -1 on error.
334*45916cd2Sjpk  */
335*45916cd2Sjpk /*ARGSUSED*/
336*45916cd2Sjpk static int
337*45916cd2Sjpk _dmap2str(da_args *dargs, devmap_t *dmp, char *buf, int size, const char *sep)
338*45916cd2Sjpk {
339*45916cd2Sjpk 	int	length;
340*45916cd2Sjpk 
341*45916cd2Sjpk 	length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep);
342*45916cd2Sjpk 	if (length >= size)
343*45916cd2Sjpk 		return (-1);
344*45916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
345*45916cd2Sjpk 	    dmp->dmap_devtype, sep);
346*45916cd2Sjpk 	if (length >= size)
347*45916cd2Sjpk 		return (-1);
348*45916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
349*45916cd2Sjpk 	    dmp->dmap_devlist);
350*45916cd2Sjpk 	if (length >= size)
351*45916cd2Sjpk 		return (-1);
352*45916cd2Sjpk 	return (0);
353*45916cd2Sjpk }
354*45916cd2Sjpk 
355*45916cd2Sjpk /*
356*45916cd2Sjpk  * _dmap2strentry -
357*45916cd2Sjpk  *	calls dmap2str to break given devmap_t into printable entry.
358*45916cd2Sjpk  *	returns pointer to decoded entry, NULL on error.
359*45916cd2Sjpk  */
360*45916cd2Sjpk static strentry_t *
361*45916cd2Sjpk _dmap2strentry(da_args *dargs, devmap_t *devmapp)
362*45916cd2Sjpk {
363*45916cd2Sjpk 	strentry_t	*sep;
364*45916cd2Sjpk 
365*45916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
366*45916cd2Sjpk 		return (NULL);
367*45916cd2Sjpk 	if (_dmap2str(dargs, devmapp, sep->se_str, sizeof (sep->se_str),
368*45916cd2Sjpk 	    KV_TOKEN_DELIMIT"\\\n\t") != 0) {
369*45916cd2Sjpk 		free(sep);
370*45916cd2Sjpk 		return (NULL);
371*45916cd2Sjpk 	}
372*45916cd2Sjpk 	return (sep);
373*45916cd2Sjpk }
374*45916cd2Sjpk 
375*45916cd2Sjpk /*
376*45916cd2Sjpk  * fix_optstr -
377*45916cd2Sjpk  * 	removes trailing ':' from buf.
378*45916cd2Sjpk  */
379*45916cd2Sjpk void
380*45916cd2Sjpk fix_optstr(char *buf)
381*45916cd2Sjpk {
382*45916cd2Sjpk 	char	*p = NULL;
383*45916cd2Sjpk 
384*45916cd2Sjpk 	if (p = rindex(buf, ':'))
385*45916cd2Sjpk 		*p = ';';
386*45916cd2Sjpk }
387*45916cd2Sjpk 
388*45916cd2Sjpk /*
389*45916cd2Sjpk  * _da2str -
390*45916cd2Sjpk  *	converts a device_allocate entry into a printable string
391*45916cd2Sjpk  *	returns 0 on success, -1 on error.
392*45916cd2Sjpk  */
393*45916cd2Sjpk static int
394*45916cd2Sjpk _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep,
395*45916cd2Sjpk     const char *osep)
396*45916cd2Sjpk {
397*45916cd2Sjpk 	int	length;
398*45916cd2Sjpk 	int	matching_entry = 0;
399*45916cd2Sjpk 	char	**dnames;
400*45916cd2Sjpk 
401*45916cd2Sjpk 	if (dargs->optflag & DA_UPDATE &&
402*45916cd2Sjpk 	    (dargs->optflag & DA_ADD_ZONE ||
403*45916cd2Sjpk 	    dargs->optflag & DA_REMOVE_ZONE) &&
404*45916cd2Sjpk 	    dargs->devnames) {
405*45916cd2Sjpk 		for (dnames = dargs->devnames; *dnames != NULL; dnames++) {
406*45916cd2Sjpk 			if (da_matchname(dap, *dnames)) {
407*45916cd2Sjpk 				matching_entry = 1;
408*45916cd2Sjpk 				break;
409*45916cd2Sjpk 			}
410*45916cd2Sjpk 		}
411*45916cd2Sjpk 	}
412*45916cd2Sjpk 	length = snprintf(buf, size, "%s%s", dap->da_devname, sep);
413*45916cd2Sjpk 	if (length >= size)
414*45916cd2Sjpk 		return (-1);
415*45916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
416*45916cd2Sjpk 	    dap->da_devtype, sep);
417*45916cd2Sjpk 	if (length >= size)
418*45916cd2Sjpk 		return (-1);
419*45916cd2Sjpk 	if (matching_entry)
420*45916cd2Sjpk 		_update_zonename(dargs, dap);
421*45916cd2Sjpk 	if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) &&
422*45916cd2Sjpk 	    (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) {
423*45916cd2Sjpk 		length += snprintf(buf + length, size - length, "%s%s",
424*45916cd2Sjpk 		    DA_RESERVED, sep);
425*45916cd2Sjpk 	} else {
426*45916cd2Sjpk 		if (_kva2str(dap->da_devopts, buf + length, size - length,
427*45916cd2Sjpk 		    KV_ASSIGN, (char *)osep) != 0)
428*45916cd2Sjpk 			return (-1);
429*45916cd2Sjpk 		length = strlen(buf);
430*45916cd2Sjpk 	}
431*45916cd2Sjpk 	if (dap->da_devopts)
432*45916cd2Sjpk 		fix_optstr(buf);
433*45916cd2Sjpk 	if (length >= size)
434*45916cd2Sjpk 		return (-1);
435*45916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
436*45916cd2Sjpk 	    DA_RESERVED, sep);
437*45916cd2Sjpk 	if (length >= size)
438*45916cd2Sjpk 		return (-1);
439*45916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
440*45916cd2Sjpk 	    dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep);
441*45916cd2Sjpk 	if (length >= size)
442*45916cd2Sjpk 		return (-1);
443*45916cd2Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
444*45916cd2Sjpk 	    dap->da_devexec ? dap->da_devexec : "");
445*45916cd2Sjpk 	if (length >= size)
446*45916cd2Sjpk 		return (-1);
447*45916cd2Sjpk 
448*45916cd2Sjpk 	return (0);
449*45916cd2Sjpk }
450*45916cd2Sjpk 
451*45916cd2Sjpk /*
452*45916cd2Sjpk  * _da2strentry -
453*45916cd2Sjpk  *	calls da2str to break given devalloc_t into printable entry.
454*45916cd2Sjpk  *	returns pointer to decoded entry, NULL on error.
455*45916cd2Sjpk  */
456*45916cd2Sjpk static strentry_t *
457*45916cd2Sjpk _da2strentry(da_args *dargs, devalloc_t *dap)
458*45916cd2Sjpk {
459*45916cd2Sjpk 	strentry_t	*sep;
460*45916cd2Sjpk 
461*45916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
462*45916cd2Sjpk 		return (NULL);
463*45916cd2Sjpk 	if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str),
464*45916cd2Sjpk 	    KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) {
465*45916cd2Sjpk 		free(sep);
466*45916cd2Sjpk 		return (NULL);
467*45916cd2Sjpk 	}
468*45916cd2Sjpk 	return (sep);
469*45916cd2Sjpk }
470*45916cd2Sjpk 
471*45916cd2Sjpk /*
472*45916cd2Sjpk  * _def2str
473*45916cd2Sjpk  *	converts da_defs_t into a printable string.
474*45916cd2Sjpk  *	returns 0 on success, -1 on error.
475*45916cd2Sjpk  */
476*45916cd2Sjpk static int
477*45916cd2Sjpk _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep)
478*45916cd2Sjpk {
479*45916cd2Sjpk 	int length;
480*45916cd2Sjpk 
481*45916cd2Sjpk 	length = snprintf(buf, size, "%s%s", da_defs->devtype, sep);
482*45916cd2Sjpk 	if (length >= size)
483*45916cd2Sjpk 		return (-1);
484*45916cd2Sjpk 	if (da_defs->devopts) {
485*45916cd2Sjpk 		if (_kva2str(da_defs->devopts, buf + length, size - length,
486*45916cd2Sjpk 		    KV_ASSIGN, KV_DELIMITER) != 0)
487*45916cd2Sjpk 			return (-1);
488*45916cd2Sjpk 		length = strlen(buf);
489*45916cd2Sjpk 	}
490*45916cd2Sjpk 	if (length >= size)
491*45916cd2Sjpk 		return (-1);
492*45916cd2Sjpk 
493*45916cd2Sjpk 	return (0);
494*45916cd2Sjpk }
495*45916cd2Sjpk 
496*45916cd2Sjpk /*
497*45916cd2Sjpk  * _def2strentry
498*45916cd2Sjpk  *	calls _def2str to break given da_defs_t into printable entry.
499*45916cd2Sjpk  *	returns pointer decoded entry, NULL on error.
500*45916cd2Sjpk  */
501*45916cd2Sjpk static strentry_t *
502*45916cd2Sjpk _def2strentry(da_defs_t *da_defs)
503*45916cd2Sjpk {
504*45916cd2Sjpk 	strentry_t	*sep;
505*45916cd2Sjpk 
506*45916cd2Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
507*45916cd2Sjpk 		return (NULL);
508*45916cd2Sjpk 	if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str),
509*45916cd2Sjpk 	    KV_TOKEN_DELIMIT) != 0) {
510*45916cd2Sjpk 		free(sep);
511*45916cd2Sjpk 		return (NULL);
512*45916cd2Sjpk 	}
513*45916cd2Sjpk 
514*45916cd2Sjpk 	return (sep);
515*45916cd2Sjpk }
516*45916cd2Sjpk 
517*45916cd2Sjpk /*
518*45916cd2Sjpk  * _build_defattrs
519*45916cd2Sjpk  *	cycles through all defattr entries, stores them in memory. removes
520*45916cd2Sjpk  *	entries with the given search_key (device type).
521*45916cd2Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
522*45916cd2Sjpk  *	error.
523*45916cd2Sjpk  */
524*45916cd2Sjpk static int
525*45916cd2Sjpk _build_defattrs(da_args *dargs, strentry_t **head_defent)
526*45916cd2Sjpk {
527*45916cd2Sjpk 	int		rc = 0;
528*45916cd2Sjpk 	da_defs_t	*da_defs;
529*45916cd2Sjpk 	strentry_t	*tail_str, *tmp_str;
530*45916cd2Sjpk 
531*45916cd2Sjpk 	setdadefent();
532*45916cd2Sjpk 	while ((da_defs = getdadefent()) != NULL) {
533*45916cd2Sjpk 		rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype));
534*45916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
535*45916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
536*45916cd2Sjpk 			/*
537*45916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
538*45916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
539*45916cd2Sjpk 			 */
540*45916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
541*45916cd2Sjpk 			rc = 0;
542*45916cd2Sjpk 		}
543*45916cd2Sjpk 		if (rc == 0) {
544*45916cd2Sjpk 			tmp_str = _def2strentry(da_defs);
545*45916cd2Sjpk 			if (tmp_str == NULL) {
546*45916cd2Sjpk 				freedadefent(da_defs);
547*45916cd2Sjpk 				enddadefent();
548*45916cd2Sjpk 				return (2);
549*45916cd2Sjpk 			}
550*45916cd2Sjpk 			/* retaining defattr entry: tmp_str->se_str */
551*45916cd2Sjpk 			tmp_str->se_next = NULL;
552*45916cd2Sjpk 			if (*head_defent == NULL) {
553*45916cd2Sjpk 				*head_defent = tail_str = tmp_str;
554*45916cd2Sjpk 			} else {
555*45916cd2Sjpk 				tail_str->se_next = tmp_str;
556*45916cd2Sjpk 				tail_str = tmp_str;
557*45916cd2Sjpk 			}
558*45916cd2Sjpk 		}
559*45916cd2Sjpk 		freedadefent(da_defs);
560*45916cd2Sjpk 	}
561*45916cd2Sjpk 	enddadefent();
562*45916cd2Sjpk 
563*45916cd2Sjpk 	return (rc);
564*45916cd2Sjpk }
565*45916cd2Sjpk 
566*45916cd2Sjpk /*
567*45916cd2Sjpk  * _build_lists -
568*45916cd2Sjpk  *	cycles through all the entries, stores them in memory. removes entries
569*45916cd2Sjpk  *	with the given search_key (device name or type).
570*45916cd2Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
571*45916cd2Sjpk  *	error.
572*45916cd2Sjpk  */
573*45916cd2Sjpk static int
574*45916cd2Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp,
575*45916cd2Sjpk     strentry_t **head_devmapp)
576*45916cd2Sjpk {
577*45916cd2Sjpk 	int		rc = 0;
578*45916cd2Sjpk 	devalloc_t	*devallocp;
579*45916cd2Sjpk 	devmap_t	*devmapp;
580*45916cd2Sjpk 	strentry_t	*tail_str;
581*45916cd2Sjpk 	strentry_t	*tmp_str;
582*45916cd2Sjpk 
583*45916cd2Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
584*45916cd2Sjpk 		goto dmap_only;
585*45916cd2Sjpk 
586*45916cd2Sjpk 	/* build device_allocate */
587*45916cd2Sjpk 	setdaent();
588*45916cd2Sjpk 	while ((devallocp = getdaent()) != NULL) {
589*45916cd2Sjpk 		rc = da_match(devallocp, dargs);
590*45916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
591*45916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
592*45916cd2Sjpk 			/*
593*45916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
594*45916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
595*45916cd2Sjpk 			 */
596*45916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
597*45916cd2Sjpk 			rc = 0;
598*45916cd2Sjpk 		}
599*45916cd2Sjpk 		if (rc == 0) {
600*45916cd2Sjpk 			tmp_str = _da2strentry(dargs, devallocp);
601*45916cd2Sjpk 			if (tmp_str == NULL) {
602*45916cd2Sjpk 				freedaent(devallocp);
603*45916cd2Sjpk 				enddaent();
604*45916cd2Sjpk 				return (2);
605*45916cd2Sjpk 			}
606*45916cd2Sjpk 			/* retaining devalloc entry: tmp_str->se_str */
607*45916cd2Sjpk 			tmp_str->se_next = NULL;
608*45916cd2Sjpk 			if (*head_devallocp == NULL) {
609*45916cd2Sjpk 				*head_devallocp = tail_str = tmp_str;
610*45916cd2Sjpk 			} else {
611*45916cd2Sjpk 				tail_str->se_next = tmp_str;
612*45916cd2Sjpk 				tail_str = tmp_str;
613*45916cd2Sjpk 			}
614*45916cd2Sjpk 		}
615*45916cd2Sjpk 		freedaent(devallocp);
616*45916cd2Sjpk 	}
617*45916cd2Sjpk 	enddaent();
618*45916cd2Sjpk 
619*45916cd2Sjpk dmap_only:
620*45916cd2Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
621*45916cd2Sjpk 		return (rc);
622*45916cd2Sjpk 
623*45916cd2Sjpk 	/* build device_maps */
624*45916cd2Sjpk 	rc = 0;
625*45916cd2Sjpk 	setdmapent();
626*45916cd2Sjpk 	while ((devmapp = getdmapent()) != NULL) {
627*45916cd2Sjpk 		rc = dm_match(devmapp, dargs);
628*45916cd2Sjpk 		if (rc && dargs->optflag & DA_ADD &&
629*45916cd2Sjpk 		    !(dargs->optflag & DA_FORCE)) {
630*45916cd2Sjpk 			/*
631*45916cd2Sjpk 			 * During DA_ADD, we keep an existing entry unless
632*45916cd2Sjpk 			 * we have DA_FORCE set to override that entry.
633*45916cd2Sjpk 			 */
634*45916cd2Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
635*45916cd2Sjpk 			rc = 0;
636*45916cd2Sjpk 		}
637*45916cd2Sjpk 		if (rc == 0) {
638*45916cd2Sjpk 			tmp_str = _dmap2strentry(dargs, devmapp);
639*45916cd2Sjpk 			if (tmp_str == NULL) {
640*45916cd2Sjpk 				freedmapent(devmapp);
641*45916cd2Sjpk 				enddmapent();
642*45916cd2Sjpk 				return (2);
643*45916cd2Sjpk 			}
644*45916cd2Sjpk 			/* retaining devmap entry: tmp_str->se_str */
645*45916cd2Sjpk 			tmp_str->se_next = NULL;
646*45916cd2Sjpk 			if (*head_devmapp == NULL) {
647*45916cd2Sjpk 				*head_devmapp = tail_str = tmp_str;
648*45916cd2Sjpk 			} else {
649*45916cd2Sjpk 				tail_str->se_next = tmp_str;
650*45916cd2Sjpk 				tail_str = tmp_str;
651*45916cd2Sjpk 			}
652*45916cd2Sjpk 		}
653*45916cd2Sjpk 		freedmapent(devmapp);
654*45916cd2Sjpk 	}
655*45916cd2Sjpk 	enddmapent();
656*45916cd2Sjpk 
657*45916cd2Sjpk 	return (rc);
658*45916cd2Sjpk }
659*45916cd2Sjpk 
660*45916cd2Sjpk /*
661*45916cd2Sjpk  * _write_defattrs
662*45916cd2Sjpk  *	writes current entries to devalloc_defaults.
663*45916cd2Sjpk  */
664*45916cd2Sjpk static void
665*45916cd2Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent)
666*45916cd2Sjpk {
667*45916cd2Sjpk 	strentry_t *tmp_str;
668*45916cd2Sjpk 
669*45916cd2Sjpk 	for (tmp_str = head_defent; tmp_str != NULL;
670*45916cd2Sjpk 	    tmp_str = tmp_str->se_next) {
671*45916cd2Sjpk 		(void) fputs(tmp_str->se_str, fp);
672*45916cd2Sjpk 		(void) fputs("\n", fp);
673*45916cd2Sjpk 	}
674*45916cd2Sjpk 
675*45916cd2Sjpk }
676*45916cd2Sjpk 
677*45916cd2Sjpk /*
678*45916cd2Sjpk  * _write_device_allocate -
679*45916cd2Sjpk  *	writes current entries in the list to device_allocate.
680*45916cd2Sjpk  */
681*45916cd2Sjpk static void
682*45916cd2Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
683*45916cd2Sjpk {
684*45916cd2Sjpk 	int		is_on = -1;
685*45916cd2Sjpk 	strentry_t	*tmp_str;
686*45916cd2Sjpk 	struct stat	dastat;
687*45916cd2Sjpk 
688*45916cd2Sjpk 	(void) fseek(dafp, (off_t)0, SEEK_SET);
689*45916cd2Sjpk 
690*45916cd2Sjpk 	/*
691*45916cd2Sjpk 	 * if the devalloc on/off string existed before,
692*45916cd2Sjpk 	 * put it back before anything else.
693*45916cd2Sjpk 	 * we need to check for the string only if the file
694*45916cd2Sjpk 	 * exists.
695*45916cd2Sjpk 	 */
696*45916cd2Sjpk 	if (stat(odevalloc, &dastat) == 0) {
697*45916cd2Sjpk 		is_on = da_is_on();
698*45916cd2Sjpk 		if (is_on == 0)
699*45916cd2Sjpk 			(void) fputs(DA_OFF_STR, dafp);
700*45916cd2Sjpk 		else if (is_on == 1)
701*45916cd2Sjpk 			(void) fputs(DA_ON_STR, dafp);
702*45916cd2Sjpk 	}
703*45916cd2Sjpk 	tmp_str = head_devallocp;
704*45916cd2Sjpk 	while (tmp_str) {
705*45916cd2Sjpk 		(void) fputs(tmp_str->se_str, dafp);
706*45916cd2Sjpk 		(void) fputs("\n", dafp);
707*45916cd2Sjpk 		tmp_str = tmp_str->se_next;
708*45916cd2Sjpk 	}
709*45916cd2Sjpk }
710*45916cd2Sjpk 
711*45916cd2Sjpk /*
712*45916cd2Sjpk  * _write_device_maps -
713*45916cd2Sjpk  *	writes current entries in the list to device_maps.
714*45916cd2Sjpk  */
715*45916cd2Sjpk static void
716*45916cd2Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
717*45916cd2Sjpk {
718*45916cd2Sjpk 	strentry_t	*tmp_str;
719*45916cd2Sjpk 
720*45916cd2Sjpk 	(void) fseek(dmfp, (off_t)0, SEEK_SET);
721*45916cd2Sjpk 
722*45916cd2Sjpk 	tmp_str = head_devmapp;
723*45916cd2Sjpk 	while (tmp_str) {
724*45916cd2Sjpk 		(void) fputs(tmp_str->se_str, dmfp);
725*45916cd2Sjpk 		(void) fputs("\n", dmfp);
726*45916cd2Sjpk 		tmp_str = tmp_str->se_next;
727*45916cd2Sjpk 	}
728*45916cd2Sjpk }
729*45916cd2Sjpk 
730*45916cd2Sjpk /*
731*45916cd2Sjpk  * _write_new_defattrs
732*45916cd2Sjpk  *	writes the new entry to devalloc_defaults.
733*45916cd2Sjpk  *	returns 0 on success, -1 on error.
734*45916cd2Sjpk  */
735*45916cd2Sjpk static int
736*45916cd2Sjpk _write_new_defattrs(FILE *fp, da_args *dargs)
737*45916cd2Sjpk {
738*45916cd2Sjpk 	int		count;
739*45916cd2Sjpk 	char		*tok = NULL, *tokp = NULL;
740*45916cd2Sjpk 	char		*lasts;
741*45916cd2Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
742*45916cd2Sjpk 
743*45916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
744*45916cd2Sjpk 		return (-1);
745*45916cd2Sjpk 	if (!devinfo->devopts)
746*45916cd2Sjpk 		return (0);
747*45916cd2Sjpk 	(void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
748*45916cd2Sjpk 	    KV_TOKEN_DELIMIT);
749*45916cd2Sjpk 	if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) {
750*45916cd2Sjpk 		(void) strcpy(tokp, devinfo->devopts);
751*45916cd2Sjpk 		if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) {
752*45916cd2Sjpk 			(void) fprintf(fp, "%s", tok);
753*45916cd2Sjpk 			count = 1;
754*45916cd2Sjpk 		}
755*45916cd2Sjpk 		while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
756*45916cd2Sjpk 			if (count)
757*45916cd2Sjpk 				(void) fprintf(fp, "%s", KV_DELIMITER);
758*45916cd2Sjpk 			(void) fprintf(fp, "%s", tok);
759*45916cd2Sjpk 			count++;
760*45916cd2Sjpk 		}
761*45916cd2Sjpk 	} else {
762*45916cd2Sjpk 		(void) fprintf(fp, "%s", devinfo->devopts);
763*45916cd2Sjpk 	}
764*45916cd2Sjpk 
765*45916cd2Sjpk 	return (0);
766*45916cd2Sjpk }
767*45916cd2Sjpk 
768*45916cd2Sjpk /*
769*45916cd2Sjpk  * _write_new_entry -
770*45916cd2Sjpk  *	writes the new devalloc_t to device_allocate or the new devmap_t to
771*45916cd2Sjpk  *	device_maps.
772*45916cd2Sjpk  *	returns 0 on success, -1 on error.
773*45916cd2Sjpk  */
774*45916cd2Sjpk static int
775*45916cd2Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag)
776*45916cd2Sjpk {
777*45916cd2Sjpk 	int		count;
778*45916cd2Sjpk 	char		*tok = NULL, *tokp = NULL;
779*45916cd2Sjpk 	char		*lasts;
780*45916cd2Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
781*45916cd2Sjpk 
782*45916cd2Sjpk 	if (flag & DA_MAPS_ONLY)
783*45916cd2Sjpk 		goto dmap_only;
784*45916cd2Sjpk 
785*45916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
786*45916cd2Sjpk 		return (-1);
787*45916cd2Sjpk 
788*45916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
789*45916cd2Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
790*45916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
791*45916cd2Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
792*45916cd2Sjpk 	if (devinfo->devopts == NULL) {
793*45916cd2Sjpk 		(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
794*45916cd2Sjpk 		    KV_DELIMITER);
795*45916cd2Sjpk 	} else {
796*45916cd2Sjpk 		if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) {
797*45916cd2Sjpk 			(void) strcpy(tokp, devinfo->devopts);
798*45916cd2Sjpk 			if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
799*45916cd2Sjpk 			    NULL) {
800*45916cd2Sjpk 				(void) fprintf(fp, "%s", tok);
801*45916cd2Sjpk 				count = 1;
802*45916cd2Sjpk 			}
803*45916cd2Sjpk 			while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
804*45916cd2Sjpk 			    &lasts)) != NULL) {
805*45916cd2Sjpk 				if (count)
806*45916cd2Sjpk 					(void) fprintf(fp, "%s",
807*45916cd2Sjpk 					    KV_TOKEN_DELIMIT "\\\n\t");
808*45916cd2Sjpk 				(void) fprintf(fp, "%s", tok);
809*45916cd2Sjpk 				count++;
810*45916cd2Sjpk 			}
811*45916cd2Sjpk 			if (count)
812*45916cd2Sjpk 				(void) fprintf(fp, "%s",
813*45916cd2Sjpk 				    KV_DELIMITER "\\\n\t");
814*45916cd2Sjpk 		} else {
815*45916cd2Sjpk 			(void) fprintf(fp, "%s%s", devinfo->devopts,
816*45916cd2Sjpk 			    KV_DELIMITER "\\\n\t");
817*45916cd2Sjpk 		}
818*45916cd2Sjpk 	}
819*45916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
820*45916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
821*45916cd2Sjpk 	    (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
822*45916cd2Sjpk 	    KV_DELIMITER);
823*45916cd2Sjpk 	(void) fprintf(fp, "%s\n",
824*45916cd2Sjpk 	    (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
825*45916cd2Sjpk 
826*45916cd2Sjpk dmap_only:
827*45916cd2Sjpk 	if (flag & DA_ALLOC_ONLY)
828*45916cd2Sjpk 		return (0);
829*45916cd2Sjpk 
830*45916cd2Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
831*45916cd2Sjpk 		return (-1);
832*45916cd2Sjpk 
833*45916cd2Sjpk 	(void) fprintf(fp, "%s%s\\\n",
834*45916cd2Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
835*45916cd2Sjpk 	(void) fprintf(fp, "\t%s%s\\\n",
836*45916cd2Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
837*45916cd2Sjpk 	(void) fprintf(fp, "\t%s\n",
838*45916cd2Sjpk 	    (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
839*45916cd2Sjpk 
840*45916cd2Sjpk 	return (0);
841*45916cd2Sjpk }
842*45916cd2Sjpk 
843*45916cd2Sjpk /*
844*45916cd2Sjpk  * _da_lock_devdb -
845*45916cd2Sjpk  *	locks the database files; lock can be either broken explicitly by
846*45916cd2Sjpk  *	closing the fd of the lock file, or it expires automatically at process
847*45916cd2Sjpk  *	termination.
848*45916cd2Sjpk  * 	returns fd of the lock file or -1 on error.
849*45916cd2Sjpk  */
850*45916cd2Sjpk int
851*45916cd2Sjpk _da_lock_devdb(char *rootdir)
852*45916cd2Sjpk {
853*45916cd2Sjpk 	int		lockfd = -1;
854*45916cd2Sjpk 	char		*lockfile;
855*45916cd2Sjpk 	char		path[MAXPATHLEN];
856*45916cd2Sjpk 	int		size = sizeof (path);
857*45916cd2Sjpk 
858*45916cd2Sjpk 	if (rootdir == NULL) {
859*45916cd2Sjpk 		lockfile = DA_DB_LOCK;
860*45916cd2Sjpk 	} else {
861*45916cd2Sjpk 		path[0] = '\0';
862*45916cd2Sjpk 		if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
863*45916cd2Sjpk 			return (-1);
864*45916cd2Sjpk 		lockfile = path;
865*45916cd2Sjpk 	}
866*45916cd2Sjpk 
867*45916cd2Sjpk 	if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
868*45916cd2Sjpk 		/* cannot open lock file */
869*45916cd2Sjpk 		return (-1);
870*45916cd2Sjpk 
871*45916cd2Sjpk 	(void) fchown(lockfd, DA_UID, DA_GID);
872*45916cd2Sjpk 
873*45916cd2Sjpk 	if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
874*45916cd2Sjpk 		/* cannot position lock file */
875*45916cd2Sjpk 		(void) close(lockfd);
876*45916cd2Sjpk 		return (-1);
877*45916cd2Sjpk 	}
878*45916cd2Sjpk 	if (lockf(lockfd, F_TLOCK, 0) == -1) {
879*45916cd2Sjpk 		/* cannot set lock */
880*45916cd2Sjpk 		(void) close(lockfd);
881*45916cd2Sjpk 		return (-1);
882*45916cd2Sjpk 	}
883*45916cd2Sjpk 	(void) utime(lockfile, NULL);
884*45916cd2Sjpk 
885*45916cd2Sjpk 	return (lockfd);
886*45916cd2Sjpk }
887*45916cd2Sjpk 
888*45916cd2Sjpk /*
889*45916cd2Sjpk  * da_open_devdb -
890*45916cd2Sjpk  *	opens one or both database files - device_allocate, device_maps - in
891*45916cd2Sjpk  *	the specified mode.
892*45916cd2Sjpk  *	locks the database files; lock is either broken explicitly by the
893*45916cd2Sjpk  *	caller by closing the lock file fd, or it expires automatically at
894*45916cd2Sjpk  *	process termination.
895*45916cd2Sjpk  *	writes the file pointer of opened file in the input args - dafp, dmfp.
896*45916cd2Sjpk  *	returns fd of the lock file on success, -2 if database file does not
897*45916cd2Sjpk  *	exist, -1 on other errors.
898*45916cd2Sjpk  */
899*45916cd2Sjpk int
900*45916cd2Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
901*45916cd2Sjpk {
902*45916cd2Sjpk 	int	oflag = 0;
903*45916cd2Sjpk 	int	fda = -1;
904*45916cd2Sjpk 	int	fdm = -1;
905*45916cd2Sjpk 	int	lockfd = -1;
906*45916cd2Sjpk 	char	*fname;
907*45916cd2Sjpk 	char	*fmode;
908*45916cd2Sjpk 	char	path[MAXPATHLEN];
909*45916cd2Sjpk 	FILE	*devfile;
910*45916cd2Sjpk 
911*45916cd2Sjpk 	if ((dafp == NULL) && (dmfp == NULL))
912*45916cd2Sjpk 		return (-1);
913*45916cd2Sjpk 
914*45916cd2Sjpk 	if (flag & DA_RDWR) {
915*45916cd2Sjpk 		oflag = DA_RDWR;
916*45916cd2Sjpk 		fmode = "r+";
917*45916cd2Sjpk 	} else if (flag & DA_RDONLY) {
918*45916cd2Sjpk 		oflag = DA_RDONLY;
919*45916cd2Sjpk 		fmode = "r";
920*45916cd2Sjpk 	}
921*45916cd2Sjpk 
922*45916cd2Sjpk 	if ((lockfd = _da_lock_devdb(rootdir)) == -1)
923*45916cd2Sjpk 		return (-1);
924*45916cd2Sjpk 
925*45916cd2Sjpk 	if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
926*45916cd2Sjpk 		goto dmap_only;
927*45916cd2Sjpk 
928*45916cd2Sjpk 	path[0] = '\0';
929*45916cd2Sjpk 
930*45916cd2Sjpk 	/*
931*45916cd2Sjpk 	 * open the device allocation file
932*45916cd2Sjpk 	 */
933*45916cd2Sjpk 	if (rootdir == NULL) {
934*45916cd2Sjpk 		fname = DEVALLOC;
935*45916cd2Sjpk 	} else {
936*45916cd2Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
937*45916cd2Sjpk 		    DEVALLOC) >= sizeof (path)) {
938*45916cd2Sjpk 			if (lockfd != -1)
939*45916cd2Sjpk 				(void) close(lockfd);
940*45916cd2Sjpk 			return (-1);
941*45916cd2Sjpk 		}
942*45916cd2Sjpk 		fname = path;
943*45916cd2Sjpk 	}
944*45916cd2Sjpk 	if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
945*45916cd2Sjpk 		if (lockfd != -1)
946*45916cd2Sjpk 			(void) close(lockfd);
947*45916cd2Sjpk 		return ((errno == ENOENT) ? -2 : -1);
948*45916cd2Sjpk 	}
949*45916cd2Sjpk 	if ((devfile = fdopen(fda, fmode)) == NULL) {
950*45916cd2Sjpk 		(void) close(fda);
951*45916cd2Sjpk 		if (lockfd != -1)
952*45916cd2Sjpk 			(void) close(lockfd);
953*45916cd2Sjpk 		return (-1);
954*45916cd2Sjpk 	}
955*45916cd2Sjpk 	*dafp = devfile;
956*45916cd2Sjpk 	(void) fchmod(fda, DA_DBMODE);
957*45916cd2Sjpk 
958*45916cd2Sjpk 	if ((flag & DA_ALLOC_ONLY))
959*45916cd2Sjpk 		goto out;
960*45916cd2Sjpk 
961*45916cd2Sjpk dmap_only:
962*45916cd2Sjpk 	path[0] = '\0';
963*45916cd2Sjpk 	/*
964*45916cd2Sjpk 	 * open the device map file
965*45916cd2Sjpk 	 */
966*45916cd2Sjpk 	if (rootdir == NULL) {
967*45916cd2Sjpk 		fname = DEVMAP;
968*45916cd2Sjpk 	} else {
969*45916cd2Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
970*45916cd2Sjpk 		    DEVMAP) >= sizeof (path)) {
971*45916cd2Sjpk 			(void) close(fda);
972*45916cd2Sjpk 			if (lockfd != -1)
973*45916cd2Sjpk 				(void) close(lockfd);
974*45916cd2Sjpk 			return (-1);
975*45916cd2Sjpk 		}
976*45916cd2Sjpk 		fname = path;
977*45916cd2Sjpk 	}
978*45916cd2Sjpk 
979*45916cd2Sjpk 	if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
980*45916cd2Sjpk 		if (lockfd != -1)
981*45916cd2Sjpk 			(void) close(lockfd);
982*45916cd2Sjpk 		return ((errno == ENOENT) ? -2 : -1);
983*45916cd2Sjpk 	}
984*45916cd2Sjpk 
985*45916cd2Sjpk 	if ((devfile = fdopen(fdm, fmode)) == NULL) {
986*45916cd2Sjpk 		(void) close(fdm);
987*45916cd2Sjpk 		(void) close(fda);
988*45916cd2Sjpk 		if (lockfd != -1)
989*45916cd2Sjpk 			(void) close(lockfd);
990*45916cd2Sjpk 		return (-1);
991*45916cd2Sjpk 	}
992*45916cd2Sjpk 	*dmfp = devfile;
993*45916cd2Sjpk 	(void) fchmod(fdm, DA_DBMODE);
994*45916cd2Sjpk 
995*45916cd2Sjpk out:
996*45916cd2Sjpk 	return (lockfd);
997*45916cd2Sjpk }
998*45916cd2Sjpk 
999*45916cd2Sjpk /*
1000*45916cd2Sjpk  * _record_on_off -
1001*45916cd2Sjpk  *	adds either DA_ON_STR or DA_OFF_STR to device_allocate
1002*45916cd2Sjpk  *	returns 0 on success, -1 on error.
1003*45916cd2Sjpk  */
1004*45916cd2Sjpk static int
1005*45916cd2Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
1006*45916cd2Sjpk {
1007*45916cd2Sjpk 	int		dafd;
1008*45916cd2Sjpk 	int		nsize;
1009*45916cd2Sjpk 	int		nitems = 1;
1010*45916cd2Sjpk 	int		actionlen;
1011*45916cd2Sjpk 	int		str_found = 0;
1012*45916cd2Sjpk 	int		len = 0, nlen = 0, plen = 0;
1013*45916cd2Sjpk 	char		*ptr = NULL;
1014*45916cd2Sjpk 	char		*actionstr;
1015*45916cd2Sjpk 	char		*nbuf = NULL;
1016*45916cd2Sjpk 	char		line[MAX_CANON];
1017*45916cd2Sjpk 	struct stat	dastat;
1018*45916cd2Sjpk 
1019*45916cd2Sjpk 	if (dargs->optflag & DA_ON)
1020*45916cd2Sjpk 		actionstr = DA_ON_STR;
1021*45916cd2Sjpk 	else
1022*45916cd2Sjpk 		actionstr = DA_OFF_STR;
1023*45916cd2Sjpk 	actionlen = strlen(actionstr);
1024*45916cd2Sjpk 	dafd = fileno(dafp);
1025*45916cd2Sjpk 	if (fstat(dafd, &dastat) == -1)
1026*45916cd2Sjpk 		return (-1);
1027*45916cd2Sjpk 
1028*45916cd2Sjpk 	/* check the old device_allocate for on/off string */
1029*45916cd2Sjpk 	ptr = fgets(line, MAX_CANON, dafp);
1030*45916cd2Sjpk 	if (ptr != NULL) {
1031*45916cd2Sjpk 		if ((strcmp(line, DA_ON_STR) == 0) ||
1032*45916cd2Sjpk 		    (strcmp(line, DA_OFF_STR) == 0)) {
1033*45916cd2Sjpk 			str_found = 1;
1034*45916cd2Sjpk 			nsize = dastat.st_size;
1035*45916cd2Sjpk 		}
1036*45916cd2Sjpk 	}
1037*45916cd2Sjpk 	if (!ptr || !str_found) {
1038*45916cd2Sjpk 		/*
1039*45916cd2Sjpk 		 * the file never had either the on or the off string;
1040*45916cd2Sjpk 		 * make room for it.
1041*45916cd2Sjpk 		 */
1042*45916cd2Sjpk 		str_found = 0;
1043*45916cd2Sjpk 		nsize = dastat.st_size + actionlen + 1;
1044*45916cd2Sjpk 	}
1045*45916cd2Sjpk 	if ((nbuf = (char *)malloc(nsize)) == NULL)
1046*45916cd2Sjpk 		return (-1);
1047*45916cd2Sjpk 	nbuf[0] = '\0';
1048*45916cd2Sjpk 	/* put the on/off string */
1049*45916cd2Sjpk 	(void) strcpy(nbuf, actionstr);
1050*45916cd2Sjpk 	nlen = strlen(nbuf);
1051*45916cd2Sjpk 	plen = nlen;
1052*45916cd2Sjpk 	if (ptr && !str_found) {
1053*45916cd2Sjpk 		/* now put the first line that we read in fgets */
1054*45916cd2Sjpk 		nlen = plen + strlen(line) + 1;
1055*45916cd2Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
1056*45916cd2Sjpk 		if (len >= nsize) {
1057*45916cd2Sjpk 			free(nbuf);
1058*45916cd2Sjpk 			return (-1);
1059*45916cd2Sjpk 		}
1060*45916cd2Sjpk 		plen += len;
1061*45916cd2Sjpk 	}
1062*45916cd2Sjpk 
1063*45916cd2Sjpk 	/* now get the rest of the old file */
1064*45916cd2Sjpk 	while (fgets(line, MAX_CANON, dafp) != NULL) {
1065*45916cd2Sjpk 		nlen = plen + strlen(line) + 1;
1066*45916cd2Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
1067*45916cd2Sjpk 		if (len >= nsize) {
1068*45916cd2Sjpk 			free(nbuf);
1069*45916cd2Sjpk 			return (-1);
1070*45916cd2Sjpk 		}
1071*45916cd2Sjpk 		plen += len;
1072*45916cd2Sjpk 	}
1073*45916cd2Sjpk 	len = strlen(nbuf) + 1;
1074*45916cd2Sjpk 	if (len < nsize)
1075*45916cd2Sjpk 		nbuf[len] = '\n';
1076*45916cd2Sjpk 
1077*45916cd2Sjpk 	/* write the on/off str + the old device_allocate to the temp file */
1078*45916cd2Sjpk 	if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
1079*45916cd2Sjpk 		free(nbuf);
1080*45916cd2Sjpk 		return (-1);
1081*45916cd2Sjpk 	}
1082*45916cd2Sjpk 
1083*45916cd2Sjpk 	free(nbuf);
1084*45916cd2Sjpk 
1085*45916cd2Sjpk 	return (0);
1086*45916cd2Sjpk }
1087*45916cd2Sjpk 
1088*45916cd2Sjpk /*
1089*45916cd2Sjpk  * da_update_defattrs -
1090*45916cd2Sjpk  *	writes default attributes to devalloc_defaults
1091*45916cd2Sjpk  *	returns 0 on success, -1 on error.
1092*45916cd2Sjpk  */
1093*45916cd2Sjpk int
1094*45916cd2Sjpk da_update_defattrs(da_args *dargs)
1095*45916cd2Sjpk {
1096*45916cd2Sjpk 	int		rc = 0, lockfd = 0, tmpfd = 0;
1097*45916cd2Sjpk 	char		*defpath = DEFATTRS;
1098*45916cd2Sjpk 	char		*tmpdefpath = TMPATTRS;
1099*45916cd2Sjpk 	FILE		*tmpfp = NULL;
1100*45916cd2Sjpk 	struct stat	dstat;
1101*45916cd2Sjpk 	strentry_t	*head_defent = NULL;
1102*45916cd2Sjpk 
1103*45916cd2Sjpk 	if (dargs == NULL)
1104*45916cd2Sjpk 		return (0);
1105*45916cd2Sjpk 	if ((lockfd = _da_lock_devdb(NULL)) == -1)
1106*45916cd2Sjpk 		return (-1);
1107*45916cd2Sjpk 	if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
1108*45916cd2Sjpk 		(void) close(lockfd);
1109*45916cd2Sjpk 		return (-1);
1110*45916cd2Sjpk 	}
1111*45916cd2Sjpk 	(void) fchown(tmpfd, DA_UID, DA_GID);
1112*45916cd2Sjpk 	if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) {
1113*45916cd2Sjpk 		(void) close(tmpfd);
1114*45916cd2Sjpk 		(void) unlink(tmpdefpath);
1115*45916cd2Sjpk 		(void) close(lockfd);
1116*45916cd2Sjpk 		return (-1);
1117*45916cd2Sjpk 	}
1118*45916cd2Sjpk 	/*
1119*45916cd2Sjpk 	 * examine all entries, remove an old one if required, check
1120*45916cd2Sjpk 	 * if a new one needs to be added.
1121*45916cd2Sjpk 	 */
1122*45916cd2Sjpk 	if (stat(defpath, &dstat) == 0) {
1123*45916cd2Sjpk 		if ((rc = _build_defattrs(dargs, &head_defent)) != 0) {
1124*45916cd2Sjpk 			if (rc == 1) {
1125*45916cd2Sjpk 				(void) close(tmpfd);
1126*45916cd2Sjpk 				(void) unlink(tmpdefpath);
1127*45916cd2Sjpk 				(void) close(lockfd);
1128*45916cd2Sjpk 				return (rc);
1129*45916cd2Sjpk 			}
1130*45916cd2Sjpk 		}
1131*45916cd2Sjpk 	}
1132*45916cd2Sjpk 	/*
1133*45916cd2Sjpk 	 * write back any existing entries.
1134*45916cd2Sjpk 	 */
1135*45916cd2Sjpk 	_write_defattrs(tmpfp, head_defent);
1136*45916cd2Sjpk 
1137*45916cd2Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
1138*45916cd2Sjpk 		/* add new entries */
1139*45916cd2Sjpk 		rc = _write_new_defattrs(tmpfp, dargs);
1140*45916cd2Sjpk 		(void) fclose(tmpfp);
1141*45916cd2Sjpk 	} else {
1142*45916cd2Sjpk 		(void) fclose(tmpfp);
1143*45916cd2Sjpk 	}
1144*45916cd2Sjpk 	if (rename(tmpdefpath, defpath) != 0) {
1145*45916cd2Sjpk 		rc = -1;
1146*45916cd2Sjpk 		(void) unlink(tmpdefpath);
1147*45916cd2Sjpk 	}
1148*45916cd2Sjpk 	(void) close(lockfd);
1149*45916cd2Sjpk 
1150*45916cd2Sjpk 	return (rc);
1151*45916cd2Sjpk }
1152*45916cd2Sjpk 
1153*45916cd2Sjpk /*
1154*45916cd2Sjpk  * da_update_device -
1155*45916cd2Sjpk  *	writes devices entries to device_allocate and device_maps.
1156*45916cd2Sjpk  * 	returns 0 on success, -1 on error.
1157*45916cd2Sjpk  */
1158*45916cd2Sjpk int
1159*45916cd2Sjpk da_update_device(da_args *dargs)
1160*45916cd2Sjpk {
1161*45916cd2Sjpk 	int		rc;
1162*45916cd2Sjpk 	int		tafd = -1, tmfd = -1;
1163*45916cd2Sjpk 	int		lockfd = -1;
1164*45916cd2Sjpk 	char		*rootdir = NULL;
1165*45916cd2Sjpk 	char		*apathp = NULL, *mpathp = NULL, *dapathp = NULL,
1166*45916cd2Sjpk 			*dmpathp = NULL;
1167*45916cd2Sjpk 	char		apath[MAXPATHLEN], mpath[MAXPATHLEN],
1168*45916cd2Sjpk 			dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
1169*45916cd2Sjpk 	FILE		*tafp = NULL, *tmfp = NULL, *dafp = NULL;
1170*45916cd2Sjpk 	struct stat	dastat;
1171*45916cd2Sjpk 	devinfo_t	*devinfo;
1172*45916cd2Sjpk 	strentry_t	*head_devmapp = NULL;
1173*45916cd2Sjpk 	strentry_t	*head_devallocp = NULL;
1174*45916cd2Sjpk 
1175*45916cd2Sjpk 	if (dargs == NULL)
1176*45916cd2Sjpk 		return (0);
1177*45916cd2Sjpk 
1178*45916cd2Sjpk 	rootdir = dargs->rootdir;
1179*45916cd2Sjpk 	devinfo = dargs->devinfo;
1180*45916cd2Sjpk 
1181*45916cd2Sjpk 	/*
1182*45916cd2Sjpk 	 * adding/removing entries should be done in both
1183*45916cd2Sjpk 	 * device_allocate and device_maps. updates can be
1184*45916cd2Sjpk 	 * done in both or either of the files.
1185*45916cd2Sjpk 	 */
1186*45916cd2Sjpk 	if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
1187*45916cd2Sjpk 		if (dargs->optflag & DA_ALLOC_ONLY ||
1188*45916cd2Sjpk 		    dargs->optflag & DA_MAPS_ONLY)
1189*45916cd2Sjpk 			return (0);
1190*45916cd2Sjpk 	}
1191*45916cd2Sjpk 
1192*45916cd2Sjpk 	/*
1193*45916cd2Sjpk 	 * name, type and list are required fields for adding a new
1194*45916cd2Sjpk 	 * device.
1195*45916cd2Sjpk 	 */
1196*45916cd2Sjpk 	if ((dargs->optflag & DA_ADD) &&
1197*45916cd2Sjpk 	    ((devinfo->devname == NULL) ||
1198*45916cd2Sjpk 	    (devinfo->devtype == NULL) ||
1199*45916cd2Sjpk 	    (devinfo->devlist == NULL))) {
1200*45916cd2Sjpk 		return (-1);
1201*45916cd2Sjpk 	}
1202*45916cd2Sjpk 
1203*45916cd2Sjpk 	if (rootdir != NULL) {
1204*45916cd2Sjpk 		if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
1205*45916cd2Sjpk 		    TMPALLOC) >= sizeof (apath))
1206*45916cd2Sjpk 			return (-1);
1207*45916cd2Sjpk 		apathp = apath;
1208*45916cd2Sjpk 		if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
1209*45916cd2Sjpk 		    DEVALLOC) >= sizeof (dapath))
1210*45916cd2Sjpk 			return (-1);
1211*45916cd2Sjpk 		dapathp = dapath;
1212*45916cd2Sjpk 		if (!(dargs->optflag & DA_ALLOC_ONLY)) {
1213*45916cd2Sjpk 			if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
1214*45916cd2Sjpk 			    TMPMAP) >= sizeof (mpath))
1215*45916cd2Sjpk 				return (-1);
1216*45916cd2Sjpk 			mpathp = mpath;
1217*45916cd2Sjpk 			if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
1218*45916cd2Sjpk 			    DEVMAP) >= sizeof (dmpath))
1219*45916cd2Sjpk 				return (-1);
1220*45916cd2Sjpk 			dmpathp = dmpath;
1221*45916cd2Sjpk 		}
1222*45916cd2Sjpk 	} else {
1223*45916cd2Sjpk 		apathp = TMPALLOC;
1224*45916cd2Sjpk 		dapathp = DEVALLOC;
1225*45916cd2Sjpk 		mpathp = TMPMAP;
1226*45916cd2Sjpk 		dmpathp = DEVMAP;
1227*45916cd2Sjpk 	}
1228*45916cd2Sjpk 
1229*45916cd2Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
1230*45916cd2Sjpk 		goto dmap_only;
1231*45916cd2Sjpk 
1232*45916cd2Sjpk 	/*
1233*45916cd2Sjpk 	 * Check if we are here just to record on/off status of
1234*45916cd2Sjpk 	 * device_allocation.
1235*45916cd2Sjpk 	 */
1236*45916cd2Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
1237*45916cd2Sjpk 		lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
1238*45916cd2Sjpk 		    DA_RDONLY|DA_ALLOC_ONLY);
1239*45916cd2Sjpk 	else
1240*45916cd2Sjpk 		lockfd = _da_lock_devdb(rootdir);
1241*45916cd2Sjpk 	if (lockfd == -1)
1242*45916cd2Sjpk 		return (-1);
1243*45916cd2Sjpk 
1244*45916cd2Sjpk 	if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
1245*45916cd2Sjpk 		(void) close(lockfd);
1246*45916cd2Sjpk 		(void) fclose(dafp);
1247*45916cd2Sjpk 		return (-1);
1248*45916cd2Sjpk 	}
1249*45916cd2Sjpk 	(void) fchown(tafd, DA_UID, DA_GID);
1250*45916cd2Sjpk 	if ((tafp = fdopen(tafd, "r+")) == NULL) {
1251*45916cd2Sjpk 		(void) close(tafd);
1252*45916cd2Sjpk 		(void) unlink(apathp);
1253*45916cd2Sjpk 		(void) fclose(dafp);
1254*45916cd2Sjpk 		(void) close(lockfd);
1255*45916cd2Sjpk 		return (-1);
1256*45916cd2Sjpk 	}
1257*45916cd2Sjpk 
1258*45916cd2Sjpk 	/*
1259*45916cd2Sjpk 	 * We don't need to parse the file if we are here just to record
1260*45916cd2Sjpk 	 * on/off status of device_allocation.
1261*45916cd2Sjpk 	 */
1262*45916cd2Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
1263*45916cd2Sjpk 		if (_record_on_off(dargs, tafp, dafp) == -1) {
1264*45916cd2Sjpk 			(void) close(tafd);
1265*45916cd2Sjpk 			(void) unlink(apathp);
1266*45916cd2Sjpk 			(void) fclose(dafp);
1267*45916cd2Sjpk 			(void) close(lockfd);
1268*45916cd2Sjpk 			return (-1);
1269*45916cd2Sjpk 		}
1270*45916cd2Sjpk 		(void) fclose(dafp);
1271*45916cd2Sjpk 		goto out;
1272*45916cd2Sjpk 	}
1273*45916cd2Sjpk 
1274*45916cd2Sjpk 	/*
1275*45916cd2Sjpk 	 * examine all the entries, remove an old one if forced to,
1276*45916cd2Sjpk 	 * and check that they are suitable for updating.
1277*45916cd2Sjpk 	 *  we need to do this only if the file exists already.
1278*45916cd2Sjpk 	 */
1279*45916cd2Sjpk 	if (stat(dapathp, &dastat) == 0) {
1280*45916cd2Sjpk 		if ((rc = _build_lists(dargs, &head_devallocp,
1281*45916cd2Sjpk 		    &head_devmapp)) != 0) {
1282*45916cd2Sjpk 			if (rc != 1) {
1283*45916cd2Sjpk 				(void) close(tafd);
1284*45916cd2Sjpk 				(void) unlink(apathp);
1285*45916cd2Sjpk 				(void) close(lockfd);
1286*45916cd2Sjpk 				return (rc);
1287*45916cd2Sjpk 			}
1288*45916cd2Sjpk 		}
1289*45916cd2Sjpk 	}
1290*45916cd2Sjpk 
1291*45916cd2Sjpk 	/*
1292*45916cd2Sjpk 	 * write back any existing devalloc entries, along with
1293*45916cd2Sjpk 	 * the devalloc on/off string.
1294*45916cd2Sjpk 	 */
1295*45916cd2Sjpk 	_write_device_allocate(dapathp, tafp, head_devallocp);
1296*45916cd2Sjpk 
1297*45916cd2Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
1298*45916cd2Sjpk 		goto out;
1299*45916cd2Sjpk 
1300*45916cd2Sjpk dmap_only:
1301*45916cd2Sjpk 	if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
1302*45916cd2Sjpk 		(void) close(tafd);
1303*45916cd2Sjpk 		(void) unlink(apathp);
1304*45916cd2Sjpk 		(void) close(lockfd);
1305*45916cd2Sjpk 		return (-1);
1306*45916cd2Sjpk 	}
1307*45916cd2Sjpk 	(void) fchown(tmfd, DA_UID, DA_GID);
1308*45916cd2Sjpk 	if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
1309*45916cd2Sjpk 		(void) close(tafd);
1310*45916cd2Sjpk 		(void) unlink(apathp);
1311*45916cd2Sjpk 		(void) close(tmfd);
1312*45916cd2Sjpk 		(void) unlink(mpathp);
1313*45916cd2Sjpk 		(void) close(lockfd);
1314*45916cd2Sjpk 		return (-1);
1315*45916cd2Sjpk 	}
1316*45916cd2Sjpk 
1317*45916cd2Sjpk 	/* write back any existing devmap entries */
1318*45916cd2Sjpk 	if (head_devmapp != NULL)
1319*45916cd2Sjpk 		_write_device_maps(tmfp, head_devmapp);
1320*45916cd2Sjpk 
1321*45916cd2Sjpk out:
1322*45916cd2Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
1323*45916cd2Sjpk 		/* add any new entries */
1324*45916cd2Sjpk 		rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
1325*45916cd2Sjpk 		(void) fclose(tafp);
1326*45916cd2Sjpk 
1327*45916cd2Sjpk 		if (rc == 0)
1328*45916cd2Sjpk 			rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
1329*45916cd2Sjpk 		(void) fclose(tmfp);
1330*45916cd2Sjpk 	} else {
1331*45916cd2Sjpk 		if (tafp)
1332*45916cd2Sjpk 			(void) fclose(tafp);
1333*45916cd2Sjpk 		if (tmfp)
1334*45916cd2Sjpk 			(void) fclose(tmfp);
1335*45916cd2Sjpk 	}
1336*45916cd2Sjpk 
1337*45916cd2Sjpk 	rc = 0;
1338*45916cd2Sjpk 	if (!(dargs->optflag & DA_MAPS_ONLY)) {
1339*45916cd2Sjpk 		if (rename(apathp, dapathp) != 0) {
1340*45916cd2Sjpk 			rc = -1;
1341*45916cd2Sjpk 			(void) unlink(apathp);
1342*45916cd2Sjpk 		}
1343*45916cd2Sjpk 	}
1344*45916cd2Sjpk 	if (!(dargs->optflag & DA_ALLOC_ONLY)) {
1345*45916cd2Sjpk 		if (rename(mpathp, dmpathp) != 0) {
1346*45916cd2Sjpk 			rc = -1;
1347*45916cd2Sjpk 			(void) unlink(mpathp);
1348*45916cd2Sjpk 		}
1349*45916cd2Sjpk 	}
1350*45916cd2Sjpk 
1351*45916cd2Sjpk 	(void) close(lockfd);
1352*45916cd2Sjpk 
1353*45916cd2Sjpk 	return (rc);
1354*45916cd2Sjpk }
1355*45916cd2Sjpk 
1356*45916cd2Sjpk /*
1357*45916cd2Sjpk  * da_add_list -
1358*45916cd2Sjpk  *	adds new /dev link name to the linked list of devices.
1359*45916cd2Sjpk  *	returns 0 if link added successfully, -1 on error.
1360*45916cd2Sjpk  */
1361*45916cd2Sjpk int
1362*45916cd2Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
1363*45916cd2Sjpk {
1364*45916cd2Sjpk 	int		instance;
1365*45916cd2Sjpk 	int		nlen, plen;
1366*45916cd2Sjpk 	int		new_entry = 0;
1367*45916cd2Sjpk 	char		*dtype, *dexec, *tname, *kval;
1368*45916cd2Sjpk 	char		*minstr = NULL, *maxstr = NULL;
1369*45916cd2Sjpk 	char		dname[DA_MAXNAME];
1370*45916cd2Sjpk 	kva_t		*kva;
1371*45916cd2Sjpk 	deventry_t	*dentry = NULL, *nentry = NULL, *pentry = NULL;
1372*45916cd2Sjpk 	da_defs_t	*da_defs;
1373*45916cd2Sjpk 
1374*45916cd2Sjpk 	if (dlist == NULL || link == NULL)
1375*45916cd2Sjpk 		return (-1);
1376*45916cd2Sjpk 
1377*45916cd2Sjpk 	dname[0] = '\0';
1378*45916cd2Sjpk 	if (flag & DA_AUDIO) {
1379*45916cd2Sjpk 		dentry = dlist->audio;
1380*45916cd2Sjpk 		tname = DA_AUDIO_NAME;
1381*45916cd2Sjpk 		dtype = DA_AUDIO_TYPE;
1382*45916cd2Sjpk 		dexec = DA_DEFAULT_AUDIO_CLEAN;
1383*45916cd2Sjpk 	} else if (flag & DA_CD) {
1384*45916cd2Sjpk 		dentry = dlist->cd;
1385*45916cd2Sjpk 		tname = DA_CD_NAME;
1386*45916cd2Sjpk 		dtype = DA_CD_TYPE;
1387*45916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
1388*45916cd2Sjpk 	} else if (flag & DA_FLOPPY) {
1389*45916cd2Sjpk 		dentry = dlist->floppy;
1390*45916cd2Sjpk 		tname = DA_FLOPPY_NAME;
1391*45916cd2Sjpk 		dtype = DA_FLOPPY_TYPE;
1392*45916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
1393*45916cd2Sjpk 	} else if (flag & DA_TAPE) {
1394*45916cd2Sjpk 		dentry = dlist->tape;
1395*45916cd2Sjpk 		tname = DA_TAPE_NAME;
1396*45916cd2Sjpk 		dtype = DA_TAPE_TYPE;
1397*45916cd2Sjpk 		dexec = DA_DEFAULT_TAPE_CLEAN;
1398*45916cd2Sjpk 	} else if (flag & DA_RMDISK) {
1399*45916cd2Sjpk 		dentry = dlist->rmdisk;
1400*45916cd2Sjpk 		tname = DA_RMDISK_NAME;
1401*45916cd2Sjpk 		dtype = DA_RMDISK_TYPE;
1402*45916cd2Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
1403*45916cd2Sjpk 	} else {
1404*45916cd2Sjpk 		return (-1);
1405*45916cd2Sjpk 	}
1406*45916cd2Sjpk 
1407*45916cd2Sjpk 	for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
1408*45916cd2Sjpk 		pentry = nentry;
1409*45916cd2Sjpk 		(void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
1410*45916cd2Sjpk 		if (nentry->devinfo.instance == new_instance)
1411*45916cd2Sjpk 			/*
1412*45916cd2Sjpk 			 * Add the new link name to the list of links
1413*45916cd2Sjpk 			 * that the device 'dname' has.
1414*45916cd2Sjpk 			 */
1415*45916cd2Sjpk 			break;
1416*45916cd2Sjpk 	}
1417*45916cd2Sjpk 
1418*45916cd2Sjpk 	if (nentry == NULL) {
1419*45916cd2Sjpk 		/*
1420*45916cd2Sjpk 		 * Either this is the first entry ever, or no matching entry
1421*45916cd2Sjpk 		 * was found. Create a new one and add to the list.
1422*45916cd2Sjpk 		 */
1423*45916cd2Sjpk 		if (dentry == NULL)		/* first entry ever */
1424*45916cd2Sjpk 			instance = 0;
1425*45916cd2Sjpk 		else				/* no matching entry */
1426*45916cd2Sjpk 			instance++;
1427*45916cd2Sjpk 		(void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
1428*45916cd2Sjpk 		if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
1429*45916cd2Sjpk 		    NULL)
1430*45916cd2Sjpk 			return (-1);
1431*45916cd2Sjpk 		if (pentry != NULL)
1432*45916cd2Sjpk 			pentry->next = nentry;
1433*45916cd2Sjpk 		new_entry = 1;
1434*45916cd2Sjpk 		nentry->devinfo.devname = strdup(dname);
1435*45916cd2Sjpk 		nentry->devinfo.devtype = dtype;
1436*45916cd2Sjpk 		nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
1437*45916cd2Sjpk 		nentry->devinfo.devexec = dexec;
1438*45916cd2Sjpk 		nentry->devinfo.instance = new_instance;
1439*45916cd2Sjpk 		/*
1440*45916cd2Sjpk 		 * Look for default label range, authorizations and cleaning
1441*45916cd2Sjpk 		 * program in devalloc_defaults. If label range is not
1442*45916cd2Sjpk 		 * specified in devalloc_defaults, assume it to be admin_low
1443*45916cd2Sjpk 		 * to admin_high.
1444*45916cd2Sjpk 		 */
1445*45916cd2Sjpk 		minstr = DA_DEFAULT_MIN;
1446*45916cd2Sjpk 		maxstr = DA_DEFAULT_MAX;
1447*45916cd2Sjpk 		setdadefent();
1448*45916cd2Sjpk 		if (da_defs = getdadeftype(nentry->devinfo.devtype)) {
1449*45916cd2Sjpk 			kva = da_defs->devopts;
1450*45916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
1451*45916cd2Sjpk 				minstr = strdup(kval);
1452*45916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
1453*45916cd2Sjpk 				maxstr = strdup(kval);
1454*45916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
1455*45916cd2Sjpk 				nentry->devinfo.devauths = strdup(kval);
1456*45916cd2Sjpk 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
1457*45916cd2Sjpk 				nentry->devinfo.devexec = strdup(kval);
1458*45916cd2Sjpk 			freedadefent(da_defs);
1459*45916cd2Sjpk 		}
1460*45916cd2Sjpk 		enddadefent();
1461*45916cd2Sjpk 		kval = NULL;
1462*45916cd2Sjpk 		nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
1463*45916cd2Sjpk 		    strlen(minstr) + strlen(KV_TOKEN_DELIMIT) +
1464*45916cd2Sjpk 		    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr)
1465*45916cd2Sjpk 		    + 1;			/* +1 for terminator */
1466*45916cd2Sjpk 		if (kval = (char *)malloc(nlen))
1467*45916cd2Sjpk 			(void) snprintf(kval, nlen, "%s%s%s%s%s%s%s",
1468*45916cd2Sjpk 			    DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT,
1469*45916cd2Sjpk 			    DAOPT_MAXLABEL, KV_ASSIGN, maxstr);
1470*45916cd2Sjpk 		nentry->devinfo.devopts = kval;
1471*45916cd2Sjpk 
1472*45916cd2Sjpk 		nentry->devinfo.devlist = NULL;
1473*45916cd2Sjpk 		nentry->next = NULL;
1474*45916cd2Sjpk 	}
1475*45916cd2Sjpk 
1476*45916cd2Sjpk 	nlen = strlen(link) + 1;		/* +1 terminator */
1477*45916cd2Sjpk 	if (nentry->devinfo.devlist) {
1478*45916cd2Sjpk 		plen = strlen(nentry->devinfo.devlist);
1479*45916cd2Sjpk 		nlen = nlen + plen + 1;	/* +1 for blank to separate entries */
1480*45916cd2Sjpk 	} else {
1481*45916cd2Sjpk 		plen = 0;
1482*45916cd2Sjpk 	}
1483*45916cd2Sjpk 
1484*45916cd2Sjpk 	if ((nentry->devinfo.devlist =
1485*45916cd2Sjpk 	    (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
1486*45916cd2Sjpk 		if (new_entry) {
1487*45916cd2Sjpk 			nentry->devinfo.devname = NULL;
1488*45916cd2Sjpk 			free(nentry->devinfo.devname);
1489*45916cd2Sjpk 			nentry = NULL;
1490*45916cd2Sjpk 			free(nentry);
1491*45916cd2Sjpk 			if (pentry != NULL)
1492*45916cd2Sjpk 				pentry->next = NULL;
1493*45916cd2Sjpk 		}
1494*45916cd2Sjpk 		return (-1);
1495*45916cd2Sjpk 	}
1496*45916cd2Sjpk 
1497*45916cd2Sjpk 	if (plen == 0)
1498*45916cd2Sjpk 		(void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
1499*45916cd2Sjpk 	else
1500*45916cd2Sjpk 		(void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
1501*45916cd2Sjpk 		    " %s", link);
1502*45916cd2Sjpk 
1503*45916cd2Sjpk 	if (pentry == NULL) {
1504*45916cd2Sjpk 		/*
1505*45916cd2Sjpk 		 * This is the first entry of this device type.
1506*45916cd2Sjpk 		 */
1507*45916cd2Sjpk 		if (flag & DA_AUDIO)
1508*45916cd2Sjpk 			dlist->audio = nentry;
1509*45916cd2Sjpk 		else if (flag & DA_CD)
1510*45916cd2Sjpk 			dlist->cd = nentry;
1511*45916cd2Sjpk 		else if (flag & DA_FLOPPY)
1512*45916cd2Sjpk 			dlist->floppy = nentry;
1513*45916cd2Sjpk 		else if (flag & DA_TAPE)
1514*45916cd2Sjpk 			dlist->tape = nentry;
1515*45916cd2Sjpk 		else if (flag & DA_RMDISK)
1516*45916cd2Sjpk 			dlist->rmdisk = nentry;
1517*45916cd2Sjpk 	}
1518*45916cd2Sjpk 
1519*45916cd2Sjpk 	return (0);
1520*45916cd2Sjpk }
1521*45916cd2Sjpk 
1522*45916cd2Sjpk /*
1523*45916cd2Sjpk  * da_remove_list -
1524*45916cd2Sjpk  *	removes a /dev link name from the linked list of devices.
1525*45916cd2Sjpk  *	returns type of device if link for that device removed
1526*45916cd2Sjpk  *	successfully, else returns -1 on error.
1527*45916cd2Sjpk  *	if all links for a device are removed, stores that device
1528*45916cd2Sjpk  *	name in devname.
1529*45916cd2Sjpk  */
1530*45916cd2Sjpk int
1531*45916cd2Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
1532*45916cd2Sjpk {
1533*45916cd2Sjpk 	int		flag;
1534*45916cd2Sjpk 	int		remove_dev = 0;
1535*45916cd2Sjpk 	int		nlen, plen, slen;
1536*45916cd2Sjpk 	char		*lasts, *lname, *oldlist;
1537*45916cd2Sjpk 	struct stat	rmstat;
1538*45916cd2Sjpk 	deventry_t	*dentry, *current, *prev;
1539*45916cd2Sjpk 
1540*45916cd2Sjpk 	if (type != NULL)
1541*45916cd2Sjpk 		flag = type;
1542*45916cd2Sjpk 	else if (link == NULL)
1543*45916cd2Sjpk 		return (-1);
1544*45916cd2Sjpk 	else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
1545*45916cd2Sjpk 		flag = DA_AUDIO;
1546*45916cd2Sjpk 	else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
1547*45916cd2Sjpk 	    strstr(link, "sr") || strstr(link, "rsr"))
1548*45916cd2Sjpk 		flag = DA_CD;
1549*45916cd2Sjpk 	else if (strstr(link, "fd") || strstr(link, "rfd") ||
1550*45916cd2Sjpk 	    strstr(link, "diskette") || strstr(link, "rdiskette"))
1551*45916cd2Sjpk 		flag = DA_FLOPPY;
1552*45916cd2Sjpk 	else if (strstr(link, DA_TAPE_NAME))
1553*45916cd2Sjpk 		flag = DA_TAPE;
1554*45916cd2Sjpk 	else
1555*45916cd2Sjpk 		flag = DA_RMDISK;
1556*45916cd2Sjpk 
1557*45916cd2Sjpk 	switch (type) {
1558*45916cd2Sjpk 	case DA_AUDIO:
1559*45916cd2Sjpk 		dentry = dlist->audio;
1560*45916cd2Sjpk 		break;
1561*45916cd2Sjpk 	case DA_CD:
1562*45916cd2Sjpk 		dentry = dlist->cd;
1563*45916cd2Sjpk 		break;
1564*45916cd2Sjpk 	case DA_FLOPPY:
1565*45916cd2Sjpk 		dentry = dlist->floppy;
1566*45916cd2Sjpk 		break;
1567*45916cd2Sjpk 	case DA_TAPE:
1568*45916cd2Sjpk 		dentry = dlist->tape;
1569*45916cd2Sjpk 		break;
1570*45916cd2Sjpk 	case DA_RMDISK:
1571*45916cd2Sjpk 		dentry = dlist->rmdisk;
1572*45916cd2Sjpk 		break;
1573*45916cd2Sjpk 	default:
1574*45916cd2Sjpk 		return (-1);
1575*45916cd2Sjpk 	}
1576*45916cd2Sjpk 
1577*45916cd2Sjpk 	if ((type != NULL) && (link == NULL)) {
1578*45916cd2Sjpk 		for (current = dentry, prev = dentry; current != NULL;
1579*45916cd2Sjpk 		    current = current->next) {
1580*45916cd2Sjpk 			oldlist = strdup(current->devinfo.devlist);
1581*45916cd2Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
1582*45916cd2Sjpk 			    lname != NULL;
1583*45916cd2Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
1584*45916cd2Sjpk 				if (stat(lname, &rmstat) != 0) {
1585*45916cd2Sjpk 					remove_dev = 1;
1586*45916cd2Sjpk 					goto remove_dev;
1587*45916cd2Sjpk 				}
1588*45916cd2Sjpk 			}
1589*45916cd2Sjpk 			prev = current;
1590*45916cd2Sjpk 		}
1591*45916cd2Sjpk 		return (-1);
1592*45916cd2Sjpk 	}
1593*45916cd2Sjpk 
1594*45916cd2Sjpk 	for (current = dentry, prev = dentry; current != NULL;
1595*45916cd2Sjpk 	    current = current->next) {
1596*45916cd2Sjpk 		plen = strlen(current->devinfo.devlist);
1597*45916cd2Sjpk 		nlen = strlen(link);
1598*45916cd2Sjpk 		if (plen == nlen) {
1599*45916cd2Sjpk 			if (strcmp(current->devinfo.devlist, link) == 0) {
1600*45916cd2Sjpk 				/* last name in the list */
1601*45916cd2Sjpk 				remove_dev = 1;
1602*45916cd2Sjpk 				break;
1603*45916cd2Sjpk 			}
1604*45916cd2Sjpk 		}
1605*45916cd2Sjpk 		if (strstr(current->devinfo.devlist, link)) {
1606*45916cd2Sjpk 			nlen = plen - nlen + 1;
1607*45916cd2Sjpk 			oldlist = strdup(current->devinfo.devlist);
1608*45916cd2Sjpk 			if ((current->devinfo.devlist =
1609*45916cd2Sjpk 			    (char *)realloc(current->devinfo.devlist,
1610*45916cd2Sjpk 			    nlen)) == NULL) {
1611*45916cd2Sjpk 				free(oldlist);
1612*45916cd2Sjpk 				return (-1);
1613*45916cd2Sjpk 			}
1614*45916cd2Sjpk 			current->devinfo.devlist[0] = '\0';
1615*45916cd2Sjpk 			nlen = plen = slen = 0;
1616*45916cd2Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
1617*45916cd2Sjpk 			    lname != NULL;
1618*45916cd2Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
1619*45916cd2Sjpk 				if (strcmp(lname, link) == 0)
1620*45916cd2Sjpk 					continue;
1621*45916cd2Sjpk 				nlen = strlen(lname) + plen + 1;
1622*45916cd2Sjpk 				if (plen == 0) {
1623*45916cd2Sjpk 					slen =
1624*45916cd2Sjpk 					    snprintf(current->devinfo.devlist,
1625*45916cd2Sjpk 						nlen, "%s", lname);
1626*45916cd2Sjpk 				} else {
1627*45916cd2Sjpk 					slen =
1628*45916cd2Sjpk 					    snprintf(current->devinfo.devlist +
1629*45916cd2Sjpk 						plen, nlen - plen, " %s",
1630*45916cd2Sjpk 						lname);
1631*45916cd2Sjpk 				}
1632*45916cd2Sjpk 				plen = plen + slen + 1;
1633*45916cd2Sjpk 			}
1634*45916cd2Sjpk 			free(oldlist);
1635*45916cd2Sjpk 			break;
1636*45916cd2Sjpk 		}
1637*45916cd2Sjpk 		prev = current;
1638*45916cd2Sjpk 	}
1639*45916cd2Sjpk 
1640*45916cd2Sjpk remove_dev:
1641*45916cd2Sjpk 	if (remove_dev == 1) {
1642*45916cd2Sjpk 		(void) strlcpy(devname, current->devinfo.devname, size);
1643*45916cd2Sjpk 		free(current->devinfo.devname);
1644*45916cd2Sjpk 		free(current->devinfo.devlist);
1645*45916cd2Sjpk 		current->devinfo.devname = current->devinfo.devlist = NULL;
1646*45916cd2Sjpk 		prev->next = current->next;
1647*45916cd2Sjpk 		free(current);
1648*45916cd2Sjpk 		current = NULL;
1649*45916cd2Sjpk 	}
1650*45916cd2Sjpk 	if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
1651*45916cd2Sjpk 		if (prev->next) {
1652*45916cd2Sjpk 			/*
1653*45916cd2Sjpk 			 * what we removed above was the first entry
1654*45916cd2Sjpk 			 * in the list. make the next entry to be the
1655*45916cd2Sjpk 			 * first.
1656*45916cd2Sjpk 			 */
1657*45916cd2Sjpk 			current = prev->next;
1658*45916cd2Sjpk 		} else {
1659*45916cd2Sjpk 			/*
1660*45916cd2Sjpk 			 * the matching entry was the only entry in the list
1661*45916cd2Sjpk 			 * for this type.
1662*45916cd2Sjpk 			 */
1663*45916cd2Sjpk 			current = NULL;
1664*45916cd2Sjpk 		}
1665*45916cd2Sjpk 		if (flag & DA_AUDIO)
1666*45916cd2Sjpk 			dlist->audio = current;
1667*45916cd2Sjpk 		else if (flag & DA_CD)
1668*45916cd2Sjpk 			dlist->cd = current;
1669*45916cd2Sjpk 		else if (flag & DA_FLOPPY)
1670*45916cd2Sjpk 			dlist->floppy = current;
1671*45916cd2Sjpk 		else if (flag & DA_TAPE)
1672*45916cd2Sjpk 			dlist->tape = current;
1673*45916cd2Sjpk 		else if (flag & DA_RMDISK)
1674*45916cd2Sjpk 			dlist->rmdisk = current;
1675*45916cd2Sjpk 	}
1676*45916cd2Sjpk 
1677*45916cd2Sjpk 	return (flag);
1678*45916cd2Sjpk }
1679*45916cd2Sjpk 
1680*45916cd2Sjpk /*
1681*45916cd2Sjpk  * da_is_on -
1682*45916cd2Sjpk  *	checks if device allocation feature is turned on.
1683*45916cd2Sjpk  *	returns 1 if on, 0 if off, -1 if status string not
1684*45916cd2Sjpk  *	found in device_allocate.
1685*45916cd2Sjpk  */
1686*45916cd2Sjpk int
1687*45916cd2Sjpk da_is_on()
1688*45916cd2Sjpk {
1689*45916cd2Sjpk 	return (getdaon());
1690*45916cd2Sjpk }
1691*45916cd2Sjpk 
1692*45916cd2Sjpk /*
1693*45916cd2Sjpk  * da_print_device -
1694*45916cd2Sjpk  *	debug routine to print device entries.
1695*45916cd2Sjpk  */
1696*45916cd2Sjpk void
1697*45916cd2Sjpk da_print_device(int flag, devlist_t *devlist)
1698*45916cd2Sjpk {
1699*45916cd2Sjpk 	deventry_t	*entry, *dentry;
1700*45916cd2Sjpk 	devinfo_t	*devinfo;
1701*45916cd2Sjpk 
1702*45916cd2Sjpk 	if (flag & DA_AUDIO)
1703*45916cd2Sjpk 		dentry = devlist->audio;
1704*45916cd2Sjpk 	else if (flag & DA_CD)
1705*45916cd2Sjpk 		dentry = devlist->cd;
1706*45916cd2Sjpk 	else if (flag & DA_FLOPPY)
1707*45916cd2Sjpk 		dentry = devlist->floppy;
1708*45916cd2Sjpk 	else if (flag & DA_TAPE)
1709*45916cd2Sjpk 		dentry = devlist->tape;
1710*45916cd2Sjpk 	else if (flag & DA_RMDISK)
1711*45916cd2Sjpk 		dentry = devlist->rmdisk;
1712*45916cd2Sjpk 	else
1713*45916cd2Sjpk 		return;
1714*45916cd2Sjpk 
1715*45916cd2Sjpk 	for (entry = dentry; entry != NULL; entry = entry->next) {
1716*45916cd2Sjpk 		devinfo = &(entry->devinfo);
1717*45916cd2Sjpk 		(void) fprintf(stdout, "name: %s\n", devinfo->devname);
1718*45916cd2Sjpk 		(void) fprintf(stdout, "type: %s\n", devinfo->devtype);
1719*45916cd2Sjpk 		(void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
1720*45916cd2Sjpk 		(void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
1721*45916cd2Sjpk 		(void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);
1722*45916cd2Sjpk 	}
1723*45916cd2Sjpk }
1724