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