11676Sjpk /*
21676Sjpk  * CDDL HEADER START
31676Sjpk  *
41676Sjpk  * The contents of this file are subject to the terms of the
51676Sjpk  * Common Development and Distribution License (the "License").
61676Sjpk  * You may not use this file except in compliance with the License.
71676Sjpk  *
81676Sjpk  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91676Sjpk  * or http://www.opensolaris.org/os/licensing.
101676Sjpk  * See the License for the specific language governing permissions
111676Sjpk  * and limitations under the License.
121676Sjpk  *
131676Sjpk  * When distributing Covered Code, include this CDDL HEADER in each
141676Sjpk  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151676Sjpk  * If applicable, add the following below this CDDL HEADER, with the
161676Sjpk  * fields enclosed by brackets "[]" replaced with your own identifying
171676Sjpk  * information: Portions Copyright [yyyy] [name of copyright owner]
181676Sjpk  *
191676Sjpk  * CDDL HEADER END
201676Sjpk  */
211676Sjpk 
221676Sjpk /*
231676Sjpk  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
241676Sjpk  * Use is subject to license terms.
251676Sjpk  */
261676Sjpk 
271676Sjpk #pragma ident	"%Z%%M%	%I%	%E% SMI"
281676Sjpk 
291676Sjpk #include <stdlib.h>
301676Sjpk #include <ctype.h>
311676Sjpk #include <unistd.h>
321676Sjpk #include <limits.h>
331676Sjpk #include <fcntl.h>
341676Sjpk #include <sys/types.h>
351676Sjpk #include <sys/stat.h>
361676Sjpk #include <utime.h>
371676Sjpk #include <synch.h>
381676Sjpk #include <strings.h>
391676Sjpk #include <string.h>
401676Sjpk #include <libintl.h>
411676Sjpk #include <errno.h>
421676Sjpk #include <auth_list.h>
431676Sjpk #include <bsm/devices.h>
441676Sjpk #include <bsm/devalloc.h>
451676Sjpk 
461676Sjpk #define	DA_DEFS	"/etc/security/tsol/devalloc_defaults"
471676Sjpk 
481676Sjpk extern int _readbufline(char *, int, char *, int, int *);
491676Sjpk extern char *strtok_r(char *, const char *, char **);
501676Sjpk extern char *_strtok_escape(char *, char *, char **);
511676Sjpk extern int getdaon(void);
521676Sjpk extern int da_matchname(devalloc_t *, char *);
531676Sjpk extern int da_match(devalloc_t *, da_args *);
541676Sjpk extern int dmap_matchname(devmap_t *, char *);
551676Sjpk extern int dm_match(devmap_t *, da_args *);
561676Sjpk 
571676Sjpk /*
581676Sjpk  * The following structure is for recording old entries to be retained.
591676Sjpk  * We read the entries from the database into a linked list in memory,
601676Sjpk  * then turn around and write them out again.
611676Sjpk  */
621676Sjpk typedef struct strentry {
631676Sjpk 	struct strentry	*se_next;
641676Sjpk 	char		se_str[4096 + 1];
651676Sjpk } strentry_t;
661676Sjpk 
671676Sjpk /*
681676Sjpk  * da_check_longindevperm -
691676Sjpk  *	reads /etc/logindevperm and checks if specified device is in the file.
701676Sjpk  *	returns 1 if specified device found in /etc/logindevperm, else returns 0
711676Sjpk  */
721676Sjpk int
731676Sjpk da_check_logindevperm(char *devname)
741676Sjpk {
751676Sjpk 	int		ret = 0;
761676Sjpk 	int		fd = -1;
771676Sjpk 	int		nlen, plen, slen, lineno, fsize;
781676Sjpk 	char		line[MAX_CANON];
791676Sjpk 	char		*field_delims = " \t\n";
801676Sjpk 	char		*fbuf = NULL;
811676Sjpk 	char		*ptr, *device;
821676Sjpk 	char		*lasts = NULL;
831676Sjpk 	FILE		*fp;
841676Sjpk 	struct stat	f_stat;
851676Sjpk 
861676Sjpk 	/*
871676Sjpk 	 * check if /etc/logindevperm exists and get its size
881676Sjpk 	 */
891676Sjpk 	if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1)
901676Sjpk 		return (0);
911676Sjpk 	if (fstat(fd, &f_stat) != 0) {
921676Sjpk 		(void) close(fd);
931676Sjpk 		return (0);
941676Sjpk 	}
951676Sjpk 	fsize = f_stat.st_size;
961676Sjpk 	if ((fbuf = (char *)malloc(fsize)) == NULL) {
971676Sjpk 		(void) close(fd);
981676Sjpk 		return (0);
991676Sjpk 	}
100*1914Scasper 	if ((fp = fdopen(fd, "rF")) == NULL) {
1011676Sjpk 		free(fbuf);
1021676Sjpk 		(void) close(fd);
1031676Sjpk 		return (0);
1041676Sjpk 	}
1051676Sjpk 
1061676Sjpk 	/*
1071676Sjpk 	 * read and parse /etc/logindevperm
1081676Sjpk 	 */
1091676Sjpk 	plen = nlen = lineno = 0;
1101676Sjpk 	while (fgets(line, MAX_CANON, fp) != NULL) {
1111676Sjpk 		lineno++;
1121676Sjpk 		if ((ptr = strchr(line, '#')) != NULL)
1131676Sjpk 			*ptr = '\0';	/* handle comments */
1141676Sjpk 		if (strtok_r(line, field_delims, &lasts) == NULL)
1151676Sjpk 			continue;	/* ignore blank lines */
1161676Sjpk 		if (strtok_r(NULL, field_delims, &lasts) == NULL)
1171676Sjpk 			/* invalid entry */
1181676Sjpk 			continue;
1191676Sjpk 		if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL)
1201676Sjpk 			/* empty device list */
1211676Sjpk 			continue;
1221676Sjpk 		nlen = strlen(ptr) + 1;		/* +1 terminator */
1231676Sjpk 		nlen += (plen + 1);
1241676Sjpk 		if (plen == 0)
1251676Sjpk 			slen = snprintf(fbuf, nlen, "%s", ptr);
1261676Sjpk 		else
1271676Sjpk 			slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr);
1281676Sjpk 		if (slen >= fsize) {
1291676Sjpk 			fbuf[0] = '\0';
1301676Sjpk 			(void) fclose(fp);
1311676Sjpk 			return (slen);
1321676Sjpk 		}
1331676Sjpk 		plen += slen;
1341676Sjpk 	}
1351676Sjpk 	(void) fclose(fp);
1361676Sjpk 
1371676Sjpk 	/*
1381676Sjpk 	 * check if devname exists in /etc/logindevperm
1391676Sjpk 	 */
1401676Sjpk 	device = strtok_r(fbuf, ":", &lasts);
1411676Sjpk 	while (device != NULL) {
1421676Sjpk 		/*
1431676Sjpk 		 * device and devname may be one of these types -
1441676Sjpk 		 *    /dev/xx
1451676Sjpk 		 *    /dev/xx*
1461676Sjpk 		 *    /dev/dir/xx
1471676Sjpk 		 *    /dev/dir/xx*
1481676Sjpk 		 *    /dev/dir/"*"
1491676Sjpk 		 */
1501676Sjpk 		if (strcmp(device, devname) == 0) {
1511676Sjpk 			/* /dev/xx, /dev/dir/xx */
1521676Sjpk 			free(fbuf);
1531676Sjpk 			return (1);
1541676Sjpk 		}
1551676Sjpk 		if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) {
1561676Sjpk 			/* all wildcard types */
1571676Sjpk 			*ptr = '\0';
1581676Sjpk 			if (strncmp(device, devname, strlen(device)) == 0) {
1591676Sjpk 				free(fbuf);
1601676Sjpk 				return (1);
1611676Sjpk 			}
1621676Sjpk 		}
1631676Sjpk 		device = strtok_r(NULL, ":", &lasts);
1641676Sjpk 	}
1651676Sjpk 
1661676Sjpk 	return (ret);
1671676Sjpk }
1681676Sjpk 
1691676Sjpk /*
1701676Sjpk  * _da_read_file -
1711676Sjpk  *	establishes readers/writer lock on fname; reads in the file if its
1721676Sjpk  *	contents changed since the last time we read it.
1731676Sjpk  *	returns size of buffer read, or -1 on failure.
1741676Sjpk  */
1751676Sjpk int
1761676Sjpk _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock,
1771676Sjpk     int flag)
1781676Sjpk {
1791676Sjpk 	int		fd = -1;
1801676Sjpk 	int		fsize = 0;
1811676Sjpk 	time_t		newtime;
1821676Sjpk 	struct stat	f_stat;
1831676Sjpk 
1841676Sjpk 	if (flag & DA_FORCE)
1851676Sjpk 		*ftime = 0;
1861676Sjpk 
1871676Sjpk 	/* check the size and the time stamp on the file */
1881676Sjpk 	if (rw_rdlock(flock) != 0)
1891676Sjpk 		return (-1);
1901676Sjpk 	if (stat(fname, &f_stat) != 0) {
1911676Sjpk 		(void) rw_unlock(flock);
1921676Sjpk 		return (-1);
1931676Sjpk 	}
1941676Sjpk 	fsize = f_stat.st_size;
1951676Sjpk 	newtime = f_stat.st_mtime;
1961676Sjpk 	(void) rw_unlock(flock);
1971676Sjpk 
1981676Sjpk 	while (newtime > *ftime) {
1991676Sjpk 		/*
2001676Sjpk 		 * file has been modified since we last read it; or this
2011676Sjpk 		 * is a forced read.
2021676Sjpk 		 * read file into the buffer with rw lock.
2031676Sjpk 		 */
2041676Sjpk 		if (rw_wrlock(flock) != 0)
2051676Sjpk 			return (-1);
206*1914Scasper 		if ((fd = open(fname, O_RDONLY)) == -1) {
2071676Sjpk 			(void) rw_unlock(flock);
2081676Sjpk 			return (-1);
2091676Sjpk 		}
2101676Sjpk 		if (*fbuf != NULL) {
2111676Sjpk 			free(*fbuf);
2121676Sjpk 			*fbuf = NULL;
2131676Sjpk 		}
2141676Sjpk 		if ((*fbuf = malloc(fsize)) == NULL) {
2151676Sjpk 			(void) rw_unlock(flock);
2161676Sjpk 			(void) close(fd);
2171676Sjpk 			return (-1);
2181676Sjpk 		}
2191676Sjpk 		if (read(fd, *fbuf, fsize) < fsize) {
2201676Sjpk 			free(*fbuf);
2211676Sjpk 			(void) rw_unlock(flock);
2221676Sjpk 			(void) close(fd);
2231676Sjpk 			return (-1);
2241676Sjpk 		}
2251676Sjpk 		(void) rw_unlock(flock);
2261676Sjpk 		/*
2271676Sjpk 		 * verify that the file did not change just after we read it.
2281676Sjpk 		 */
2291676Sjpk 		if (rw_rdlock(flock) != 0) {
2301676Sjpk 			free(*fbuf);
2311676Sjpk 			(void) close(fd);
2321676Sjpk 			return (-1);
2331676Sjpk 		}
2341676Sjpk 		if (stat(fname, &f_stat) != 0) {
2351676Sjpk 			free(*fbuf);
2361676Sjpk 			(void) rw_unlock(flock);
2371676Sjpk 			(void) close(fd);
2381676Sjpk 			return (-1);
2391676Sjpk 		}
2401676Sjpk 		fsize = f_stat.st_size;
2411676Sjpk 		newtime = f_stat.st_mtime;
2421676Sjpk 		(void) rw_unlock(flock);
2431676Sjpk 		(void) close(fd);
2441676Sjpk 		*ftime = newtime;
2451676Sjpk 	}
2461676Sjpk 
2471676Sjpk 	return (fsize);
2481676Sjpk }
2491676Sjpk 
2501676Sjpk /*
2511676Sjpk  * _update_zonename -
2521676Sjpk  *	add/remove current zone's name to the given devalloc_t.
2531676Sjpk  */
2541676Sjpk void
2551676Sjpk _update_zonename(da_args *dargs, devalloc_t *dap)
2561676Sjpk {
2571676Sjpk 	int		i, j;
2581676Sjpk 	int		oldsize, newsize;
2591676Sjpk 	int		has_zonename = 0;
2601676Sjpk 	char		*zonename;
2611676Sjpk 	kva_t		*newkva, *oldkva;
2621676Sjpk 	kv_t		*newdata, *olddata;
2631676Sjpk 	devinfo_t	*devinfo;
2641676Sjpk 
2651676Sjpk 	devinfo = dargs->devinfo;
2661676Sjpk 	oldkva = dap->da_devopts;
2671676Sjpk 	if (oldkva == NULL) {
2681676Sjpk 		if (dargs->optflag & DA_REMOVE_ZONE)
2691676Sjpk 			return;
2701676Sjpk 		if (dargs->optflag & DA_ADD_ZONE) {
2711676Sjpk 			newkva = _str2kva(devinfo->devopts, KV_ASSIGN,
2721676Sjpk 			    KV_TOKEN_DELIMIT);
2731676Sjpk 			if (newkva != NULL)
2741676Sjpk 				dap->da_devopts = newkva;
2751676Sjpk 			return;
2761676Sjpk 		}
2771676Sjpk 	}
2781676Sjpk 	newsize = oldsize = oldkva->length;
2791676Sjpk 	if (kva_match(oldkva, DAOPT_ZONE))
2801676Sjpk 		has_zonename = 1;
2811676Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
2821676Sjpk 		if ((zonename = index(devinfo->devopts, '=')) == NULL)
2831676Sjpk 			return;
2841676Sjpk 		zonename++;
2851676Sjpk 		if (has_zonename) {
2861676Sjpk 			(void) _insert2kva(oldkva, DAOPT_ZONE, zonename);
2871676Sjpk 			return;
2881676Sjpk 		}
2891676Sjpk 		newsize += 1;
2901676Sjpk 	} else if (dargs->optflag & DA_REMOVE_ZONE) {
2911676Sjpk 		if (has_zonename) {
2921676Sjpk 			newsize -= 1;
2931676Sjpk 			if (newsize == 0) {
2941676Sjpk 				/*
2951676Sjpk 				 * If zone name was the only key/value pair,
2961676Sjpk 				 * put 'reserved' in the empty slot.
2971676Sjpk 				 */
2981676Sjpk 				_kva_free(oldkva);
2991676Sjpk 				dap->da_devopts = NULL;
3001676Sjpk 				return;
3011676Sjpk 			}
3021676Sjpk 		} else {
3031676Sjpk 			return;
3041676Sjpk 		}
3051676Sjpk 	}
3061676Sjpk 	newkva = _new_kva(newsize);
3071676Sjpk 	newkva->length = 0;
3081676Sjpk 	newdata = newkva->data;
3091676Sjpk 	olddata = oldkva->data;
3101676Sjpk 	for (i = 0, j = 0; i < oldsize; i++) {
3111676Sjpk 		if ((dargs->optflag & DA_REMOVE_ZONE) &&
3121676Sjpk 		    (strcmp(olddata[i].key, DAOPT_ZONE) == 0))
3131676Sjpk 			continue;
3141676Sjpk 		newdata[j].key = strdup(olddata[i].key);
3151676Sjpk 		newdata[j].value = strdup(olddata[i].value);
3161676Sjpk 		newkva->length++;
3171676Sjpk 		j++;
3181676Sjpk 	}
3191676Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
3201676Sjpk 		newdata[j].key = strdup(DAOPT_ZONE);
3211676Sjpk 		newdata[j].value = strdup(zonename);
3221676Sjpk 		newkva->length++;
3231676Sjpk 	}
3241676Sjpk 	_kva_free(oldkva);
3251676Sjpk 	dap->da_devopts = newkva;
3261676Sjpk }
3271676Sjpk 
3281676Sjpk /*
3291676Sjpk  * _dmap2str -
3301676Sjpk  *	converts a device_map entry into a printable string
3311676Sjpk  *	returns 0 on success, -1 on error.
3321676Sjpk  */
3331676Sjpk /*ARGSUSED*/
3341676Sjpk static int
3351676Sjpk _dmap2str(da_args *dargs, devmap_t *dmp, char *buf, int size, const char *sep)
3361676Sjpk {
3371676Sjpk 	int	length;
3381676Sjpk 
3391676Sjpk 	length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep);
3401676Sjpk 	if (length >= size)
3411676Sjpk 		return (-1);
3421676Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
3431676Sjpk 	    dmp->dmap_devtype, sep);
3441676Sjpk 	if (length >= size)
3451676Sjpk 		return (-1);
3461676Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
3471676Sjpk 	    dmp->dmap_devlist);
3481676Sjpk 	if (length >= size)
3491676Sjpk 		return (-1);
3501676Sjpk 	return (0);
3511676Sjpk }
3521676Sjpk 
3531676Sjpk /*
3541676Sjpk  * _dmap2strentry -
3551676Sjpk  *	calls dmap2str to break given devmap_t into printable entry.
3561676Sjpk  *	returns pointer to decoded entry, NULL on error.
3571676Sjpk  */
3581676Sjpk static strentry_t *
3591676Sjpk _dmap2strentry(da_args *dargs, devmap_t *devmapp)
3601676Sjpk {
3611676Sjpk 	strentry_t	*sep;
3621676Sjpk 
3631676Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
3641676Sjpk 		return (NULL);
3651676Sjpk 	if (_dmap2str(dargs, devmapp, sep->se_str, sizeof (sep->se_str),
3661676Sjpk 	    KV_TOKEN_DELIMIT"\\\n\t") != 0) {
3671676Sjpk 		free(sep);
3681676Sjpk 		return (NULL);
3691676Sjpk 	}
3701676Sjpk 	return (sep);
3711676Sjpk }
3721676Sjpk 
3731676Sjpk /*
3741676Sjpk  * fix_optstr -
3751676Sjpk  * 	removes trailing ':' from buf.
3761676Sjpk  */
3771676Sjpk void
3781676Sjpk fix_optstr(char *buf)
3791676Sjpk {
3801676Sjpk 	char	*p = NULL;
3811676Sjpk 
3821676Sjpk 	if (p = rindex(buf, ':'))
3831676Sjpk 		*p = ';';
3841676Sjpk }
3851676Sjpk 
3861676Sjpk /*
3871676Sjpk  * _da2str -
3881676Sjpk  *	converts a device_allocate entry into a printable string
3891676Sjpk  *	returns 0 on success, -1 on error.
3901676Sjpk  */
3911676Sjpk static int
3921676Sjpk _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep,
3931676Sjpk     const char *osep)
3941676Sjpk {
3951676Sjpk 	int	length;
3961676Sjpk 	int	matching_entry = 0;
3971676Sjpk 	char	**dnames;
3981676Sjpk 
3991676Sjpk 	if (dargs->optflag & DA_UPDATE &&
4001676Sjpk 	    (dargs->optflag & DA_ADD_ZONE ||
4011676Sjpk 	    dargs->optflag & DA_REMOVE_ZONE) &&
4021676Sjpk 	    dargs->devnames) {
4031676Sjpk 		for (dnames = dargs->devnames; *dnames != NULL; dnames++) {
4041676Sjpk 			if (da_matchname(dap, *dnames)) {
4051676Sjpk 				matching_entry = 1;
4061676Sjpk 				break;
4071676Sjpk 			}
4081676Sjpk 		}
4091676Sjpk 	}
4101676Sjpk 	length = snprintf(buf, size, "%s%s", dap->da_devname, sep);
4111676Sjpk 	if (length >= size)
4121676Sjpk 		return (-1);
4131676Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
4141676Sjpk 	    dap->da_devtype, sep);
4151676Sjpk 	if (length >= size)
4161676Sjpk 		return (-1);
4171676Sjpk 	if (matching_entry)
4181676Sjpk 		_update_zonename(dargs, dap);
4191676Sjpk 	if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) &&
4201676Sjpk 	    (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) {
4211676Sjpk 		length += snprintf(buf + length, size - length, "%s%s",
4221676Sjpk 		    DA_RESERVED, sep);
4231676Sjpk 	} else {
4241676Sjpk 		if (_kva2str(dap->da_devopts, buf + length, size - length,
4251676Sjpk 		    KV_ASSIGN, (char *)osep) != 0)
4261676Sjpk 			return (-1);
4271676Sjpk 		length = strlen(buf);
4281676Sjpk 	}
4291676Sjpk 	if (dap->da_devopts)
4301676Sjpk 		fix_optstr(buf);
4311676Sjpk 	if (length >= size)
4321676Sjpk 		return (-1);
4331676Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
4341676Sjpk 	    DA_RESERVED, sep);
4351676Sjpk 	if (length >= size)
4361676Sjpk 		return (-1);
4371676Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
4381676Sjpk 	    dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep);
4391676Sjpk 	if (length >= size)
4401676Sjpk 		return (-1);
4411676Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
4421676Sjpk 	    dap->da_devexec ? dap->da_devexec : "");
4431676Sjpk 	if (length >= size)
4441676Sjpk 		return (-1);
4451676Sjpk 
4461676Sjpk 	return (0);
4471676Sjpk }
4481676Sjpk 
4491676Sjpk /*
4501676Sjpk  * _da2strentry -
4511676Sjpk  *	calls da2str to break given devalloc_t into printable entry.
4521676Sjpk  *	returns pointer to decoded entry, NULL on error.
4531676Sjpk  */
4541676Sjpk static strentry_t *
4551676Sjpk _da2strentry(da_args *dargs, devalloc_t *dap)
4561676Sjpk {
4571676Sjpk 	strentry_t	*sep;
4581676Sjpk 
4591676Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
4601676Sjpk 		return (NULL);
4611676Sjpk 	if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str),
4621676Sjpk 	    KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) {
4631676Sjpk 		free(sep);
4641676Sjpk 		return (NULL);
4651676Sjpk 	}
4661676Sjpk 	return (sep);
4671676Sjpk }
4681676Sjpk 
4691676Sjpk /*
4701676Sjpk  * _def2str
4711676Sjpk  *	converts da_defs_t into a printable string.
4721676Sjpk  *	returns 0 on success, -1 on error.
4731676Sjpk  */
4741676Sjpk static int
4751676Sjpk _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep)
4761676Sjpk {
4771676Sjpk 	int length;
4781676Sjpk 
4791676Sjpk 	length = snprintf(buf, size, "%s%s", da_defs->devtype, sep);
4801676Sjpk 	if (length >= size)
4811676Sjpk 		return (-1);
4821676Sjpk 	if (da_defs->devopts) {
4831676Sjpk 		if (_kva2str(da_defs->devopts, buf + length, size - length,
4841676Sjpk 		    KV_ASSIGN, KV_DELIMITER) != 0)
4851676Sjpk 			return (-1);
4861676Sjpk 		length = strlen(buf);
4871676Sjpk 	}
4881676Sjpk 	if (length >= size)
4891676Sjpk 		return (-1);
4901676Sjpk 
4911676Sjpk 	return (0);
4921676Sjpk }
4931676Sjpk 
4941676Sjpk /*
4951676Sjpk  * _def2strentry
4961676Sjpk  *	calls _def2str to break given da_defs_t into printable entry.
4971676Sjpk  *	returns pointer decoded entry, NULL on error.
4981676Sjpk  */
4991676Sjpk static strentry_t *
5001676Sjpk _def2strentry(da_defs_t *da_defs)
5011676Sjpk {
5021676Sjpk 	strentry_t	*sep;
5031676Sjpk 
5041676Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
5051676Sjpk 		return (NULL);
5061676Sjpk 	if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str),
5071676Sjpk 	    KV_TOKEN_DELIMIT) != 0) {
5081676Sjpk 		free(sep);
5091676Sjpk 		return (NULL);
5101676Sjpk 	}
5111676Sjpk 
5121676Sjpk 	return (sep);
5131676Sjpk }
5141676Sjpk 
5151676Sjpk /*
5161676Sjpk  * _build_defattrs
5171676Sjpk  *	cycles through all defattr entries, stores them in memory. removes
5181676Sjpk  *	entries with the given search_key (device type).
5191676Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
5201676Sjpk  *	error.
5211676Sjpk  */
5221676Sjpk static int
5231676Sjpk _build_defattrs(da_args *dargs, strentry_t **head_defent)
5241676Sjpk {
5251676Sjpk 	int		rc = 0;
5261676Sjpk 	da_defs_t	*da_defs;
5271676Sjpk 	strentry_t	*tail_str, *tmp_str;
5281676Sjpk 
5291676Sjpk 	setdadefent();
5301676Sjpk 	while ((da_defs = getdadefent()) != NULL) {
5311676Sjpk 		rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype));
5321676Sjpk 		if (rc && dargs->optflag & DA_ADD &&
5331676Sjpk 		    !(dargs->optflag & DA_FORCE)) {
5341676Sjpk 			/*
5351676Sjpk 			 * During DA_ADD, we keep an existing entry unless
5361676Sjpk 			 * we have DA_FORCE set to override that entry.
5371676Sjpk 			 */
5381676Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
5391676Sjpk 			rc = 0;
5401676Sjpk 		}
5411676Sjpk 		if (rc == 0) {
5421676Sjpk 			tmp_str = _def2strentry(da_defs);
5431676Sjpk 			if (tmp_str == NULL) {
5441676Sjpk 				freedadefent(da_defs);
5451676Sjpk 				enddadefent();
5461676Sjpk 				return (2);
5471676Sjpk 			}
5481676Sjpk 			/* retaining defattr entry: tmp_str->se_str */
5491676Sjpk 			tmp_str->se_next = NULL;
5501676Sjpk 			if (*head_defent == NULL) {
5511676Sjpk 				*head_defent = tail_str = tmp_str;
5521676Sjpk 			} else {
5531676Sjpk 				tail_str->se_next = tmp_str;
5541676Sjpk 				tail_str = tmp_str;
5551676Sjpk 			}
5561676Sjpk 		}
5571676Sjpk 		freedadefent(da_defs);
5581676Sjpk 	}
5591676Sjpk 	enddadefent();
5601676Sjpk 
5611676Sjpk 	return (rc);
5621676Sjpk }
5631676Sjpk 
5641676Sjpk /*
5651676Sjpk  * _build_lists -
5661676Sjpk  *	cycles through all the entries, stores them in memory. removes entries
5671676Sjpk  *	with the given search_key (device name or type).
5681676Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
5691676Sjpk  *	error.
5701676Sjpk  */
5711676Sjpk static int
5721676Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp,
5731676Sjpk     strentry_t **head_devmapp)
5741676Sjpk {
5751676Sjpk 	int		rc = 0;
5761676Sjpk 	devalloc_t	*devallocp;
5771676Sjpk 	devmap_t	*devmapp;
5781676Sjpk 	strentry_t	*tail_str;
5791676Sjpk 	strentry_t	*tmp_str;
5801676Sjpk 
5811676Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
5821676Sjpk 		goto dmap_only;
5831676Sjpk 
5841676Sjpk 	/* build device_allocate */
5851676Sjpk 	setdaent();
5861676Sjpk 	while ((devallocp = getdaent()) != NULL) {
5871676Sjpk 		rc = da_match(devallocp, dargs);
5881676Sjpk 		if (rc && dargs->optflag & DA_ADD &&
5891676Sjpk 		    !(dargs->optflag & DA_FORCE)) {
5901676Sjpk 			/*
5911676Sjpk 			 * During DA_ADD, we keep an existing entry unless
5921676Sjpk 			 * we have DA_FORCE set to override that entry.
5931676Sjpk 			 */
5941676Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
5951676Sjpk 			rc = 0;
5961676Sjpk 		}
5971676Sjpk 		if (rc == 0) {
5981676Sjpk 			tmp_str = _da2strentry(dargs, devallocp);
5991676Sjpk 			if (tmp_str == NULL) {
6001676Sjpk 				freedaent(devallocp);
6011676Sjpk 				enddaent();
6021676Sjpk 				return (2);
6031676Sjpk 			}
6041676Sjpk 			/* retaining devalloc entry: tmp_str->se_str */
6051676Sjpk 			tmp_str->se_next = NULL;
6061676Sjpk 			if (*head_devallocp == NULL) {
6071676Sjpk 				*head_devallocp = tail_str = tmp_str;
6081676Sjpk 			} else {
6091676Sjpk 				tail_str->se_next = tmp_str;
6101676Sjpk 				tail_str = tmp_str;
6111676Sjpk 			}
6121676Sjpk 		}
6131676Sjpk 		freedaent(devallocp);
6141676Sjpk 	}
6151676Sjpk 	enddaent();
6161676Sjpk 
6171676Sjpk dmap_only:
6181676Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
6191676Sjpk 		return (rc);
6201676Sjpk 
6211676Sjpk 	/* build device_maps */
6221676Sjpk 	rc = 0;
6231676Sjpk 	setdmapent();
6241676Sjpk 	while ((devmapp = getdmapent()) != NULL) {
6251676Sjpk 		rc = dm_match(devmapp, dargs);
6261676Sjpk 		if (rc && dargs->optflag & DA_ADD &&
6271676Sjpk 		    !(dargs->optflag & DA_FORCE)) {
6281676Sjpk 			/*
6291676Sjpk 			 * During DA_ADD, we keep an existing entry unless
6301676Sjpk 			 * we have DA_FORCE set to override that entry.
6311676Sjpk 			 */
6321676Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
6331676Sjpk 			rc = 0;
6341676Sjpk 		}
6351676Sjpk 		if (rc == 0) {
6361676Sjpk 			tmp_str = _dmap2strentry(dargs, devmapp);
6371676Sjpk 			if (tmp_str == NULL) {
6381676Sjpk 				freedmapent(devmapp);
6391676Sjpk 				enddmapent();
6401676Sjpk 				return (2);
6411676Sjpk 			}
6421676Sjpk 			/* retaining devmap entry: tmp_str->se_str */
6431676Sjpk 			tmp_str->se_next = NULL;
6441676Sjpk 			if (*head_devmapp == NULL) {
6451676Sjpk 				*head_devmapp = tail_str = tmp_str;
6461676Sjpk 			} else {
6471676Sjpk 				tail_str->se_next = tmp_str;
6481676Sjpk 				tail_str = tmp_str;
6491676Sjpk 			}
6501676Sjpk 		}
6511676Sjpk 		freedmapent(devmapp);
6521676Sjpk 	}
6531676Sjpk 	enddmapent();
6541676Sjpk 
6551676Sjpk 	return (rc);
6561676Sjpk }
6571676Sjpk 
6581676Sjpk /*
6591676Sjpk  * _write_defattrs
6601676Sjpk  *	writes current entries to devalloc_defaults.
6611676Sjpk  */
6621676Sjpk static void
6631676Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent)
6641676Sjpk {
6651676Sjpk 	strentry_t *tmp_str;
6661676Sjpk 
6671676Sjpk 	for (tmp_str = head_defent; tmp_str != NULL;
6681676Sjpk 	    tmp_str = tmp_str->se_next) {
6691676Sjpk 		(void) fputs(tmp_str->se_str, fp);
6701676Sjpk 		(void) fputs("\n", fp);
6711676Sjpk 	}
6721676Sjpk 
6731676Sjpk }
6741676Sjpk 
6751676Sjpk /*
6761676Sjpk  * _write_device_allocate -
6771676Sjpk  *	writes current entries in the list to device_allocate.
6781676Sjpk  */
6791676Sjpk static void
6801676Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
6811676Sjpk {
6821676Sjpk 	int		is_on = -1;
6831676Sjpk 	strentry_t	*tmp_str;
6841676Sjpk 	struct stat	dastat;
6851676Sjpk 
6861676Sjpk 	(void) fseek(dafp, (off_t)0, SEEK_SET);
6871676Sjpk 
6881676Sjpk 	/*
6891676Sjpk 	 * if the devalloc on/off string existed before,
6901676Sjpk 	 * put it back before anything else.
6911676Sjpk 	 * we need to check for the string only if the file
6921676Sjpk 	 * exists.
6931676Sjpk 	 */
6941676Sjpk 	if (stat(odevalloc, &dastat) == 0) {
6951676Sjpk 		is_on = da_is_on();
6961676Sjpk 		if (is_on == 0)
6971676Sjpk 			(void) fputs(DA_OFF_STR, dafp);
6981676Sjpk 		else if (is_on == 1)
6991676Sjpk 			(void) fputs(DA_ON_STR, dafp);
7001676Sjpk 	}
7011676Sjpk 	tmp_str = head_devallocp;
7021676Sjpk 	while (tmp_str) {
7031676Sjpk 		(void) fputs(tmp_str->se_str, dafp);
7041676Sjpk 		(void) fputs("\n", dafp);
7051676Sjpk 		tmp_str = tmp_str->se_next;
7061676Sjpk 	}
7071676Sjpk }
7081676Sjpk 
7091676Sjpk /*
7101676Sjpk  * _write_device_maps -
7111676Sjpk  *	writes current entries in the list to device_maps.
7121676Sjpk  */
7131676Sjpk static void
7141676Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
7151676Sjpk {
7161676Sjpk 	strentry_t	*tmp_str;
7171676Sjpk 
7181676Sjpk 	(void) fseek(dmfp, (off_t)0, SEEK_SET);
7191676Sjpk 
7201676Sjpk 	tmp_str = head_devmapp;
7211676Sjpk 	while (tmp_str) {
7221676Sjpk 		(void) fputs(tmp_str->se_str, dmfp);
7231676Sjpk 		(void) fputs("\n", dmfp);
7241676Sjpk 		tmp_str = tmp_str->se_next;
7251676Sjpk 	}
7261676Sjpk }
7271676Sjpk 
7281676Sjpk /*
7291676Sjpk  * _write_new_defattrs
7301676Sjpk  *	writes the new entry to devalloc_defaults.
7311676Sjpk  *	returns 0 on success, -1 on error.
7321676Sjpk  */
7331676Sjpk static int
7341676Sjpk _write_new_defattrs(FILE *fp, da_args *dargs)
7351676Sjpk {
7361676Sjpk 	int		count;
7371676Sjpk 	char		*tok = NULL, *tokp = NULL;
7381676Sjpk 	char		*lasts;
7391676Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
7401676Sjpk 
7411676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
7421676Sjpk 		return (-1);
7431676Sjpk 	if (!devinfo->devopts)
7441676Sjpk 		return (0);
7451676Sjpk 	(void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
7461676Sjpk 	    KV_TOKEN_DELIMIT);
7471676Sjpk 	if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) {
7481676Sjpk 		(void) strcpy(tokp, devinfo->devopts);
7491676Sjpk 		if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) {
7501676Sjpk 			(void) fprintf(fp, "%s", tok);
7511676Sjpk 			count = 1;
7521676Sjpk 		}
7531676Sjpk 		while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
7541676Sjpk 			if (count)
7551676Sjpk 				(void) fprintf(fp, "%s", KV_DELIMITER);
7561676Sjpk 			(void) fprintf(fp, "%s", tok);
7571676Sjpk 			count++;
7581676Sjpk 		}
7591676Sjpk 	} else {
7601676Sjpk 		(void) fprintf(fp, "%s", devinfo->devopts);
7611676Sjpk 	}
7621676Sjpk 
7631676Sjpk 	return (0);
7641676Sjpk }
7651676Sjpk 
7661676Sjpk /*
7671676Sjpk  * _write_new_entry -
7681676Sjpk  *	writes the new devalloc_t to device_allocate or the new devmap_t to
7691676Sjpk  *	device_maps.
7701676Sjpk  *	returns 0 on success, -1 on error.
7711676Sjpk  */
7721676Sjpk static int
7731676Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag)
7741676Sjpk {
7751676Sjpk 	int		count;
7761676Sjpk 	char		*tok = NULL, *tokp = NULL;
7771676Sjpk 	char		*lasts;
7781676Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
7791676Sjpk 
7801676Sjpk 	if (flag & DA_MAPS_ONLY)
7811676Sjpk 		goto dmap_only;
7821676Sjpk 
7831676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
7841676Sjpk 		return (-1);
7851676Sjpk 
7861676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
7871676Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
7881676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
7891676Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
7901676Sjpk 	if (devinfo->devopts == NULL) {
7911676Sjpk 		(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
7921676Sjpk 		    KV_DELIMITER);
7931676Sjpk 	} else {
7941676Sjpk 		if ((tokp = (char *)malloc(strlen(devinfo->devopts))) != NULL) {
7951676Sjpk 			(void) strcpy(tokp, devinfo->devopts);
7961676Sjpk 			if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
7971676Sjpk 			    NULL) {
7981676Sjpk 				(void) fprintf(fp, "%s", tok);
7991676Sjpk 				count = 1;
8001676Sjpk 			}
8011676Sjpk 			while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
8021676Sjpk 			    &lasts)) != NULL) {
8031676Sjpk 				if (count)
8041676Sjpk 					(void) fprintf(fp, "%s",
8051676Sjpk 					    KV_TOKEN_DELIMIT "\\\n\t");
8061676Sjpk 				(void) fprintf(fp, "%s", tok);
8071676Sjpk 				count++;
8081676Sjpk 			}
8091676Sjpk 			if (count)
8101676Sjpk 				(void) fprintf(fp, "%s",
8111676Sjpk 				    KV_DELIMITER "\\\n\t");
8121676Sjpk 		} else {
8131676Sjpk 			(void) fprintf(fp, "%s%s", devinfo->devopts,
8141676Sjpk 			    KV_DELIMITER "\\\n\t");
8151676Sjpk 		}
8161676Sjpk 	}
8171676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
8181676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
8191676Sjpk 	    (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
8201676Sjpk 	    KV_DELIMITER);
8211676Sjpk 	(void) fprintf(fp, "%s\n",
8221676Sjpk 	    (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
8231676Sjpk 
8241676Sjpk dmap_only:
8251676Sjpk 	if (flag & DA_ALLOC_ONLY)
8261676Sjpk 		return (0);
8271676Sjpk 
8281676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
8291676Sjpk 		return (-1);
8301676Sjpk 
8311676Sjpk 	(void) fprintf(fp, "%s%s\\\n",
8321676Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
8331676Sjpk 	(void) fprintf(fp, "\t%s%s\\\n",
8341676Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
8351676Sjpk 	(void) fprintf(fp, "\t%s\n",
8361676Sjpk 	    (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
8371676Sjpk 
8381676Sjpk 	return (0);
8391676Sjpk }
8401676Sjpk 
8411676Sjpk /*
8421676Sjpk  * _da_lock_devdb -
8431676Sjpk  *	locks the database files; lock can be either broken explicitly by
8441676Sjpk  *	closing the fd of the lock file, or it expires automatically at process
8451676Sjpk  *	termination.
8461676Sjpk  * 	returns fd of the lock file or -1 on error.
8471676Sjpk  */
8481676Sjpk int
8491676Sjpk _da_lock_devdb(char *rootdir)
8501676Sjpk {
8511676Sjpk 	int		lockfd = -1;
8521676Sjpk 	char		*lockfile;
8531676Sjpk 	char		path[MAXPATHLEN];
8541676Sjpk 	int		size = sizeof (path);
8551676Sjpk 
8561676Sjpk 	if (rootdir == NULL) {
8571676Sjpk 		lockfile = DA_DB_LOCK;
8581676Sjpk 	} else {
8591676Sjpk 		path[0] = '\0';
8601676Sjpk 		if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
8611676Sjpk 			return (-1);
8621676Sjpk 		lockfile = path;
8631676Sjpk 	}
8641676Sjpk 
8651676Sjpk 	if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
8661676Sjpk 		/* cannot open lock file */
8671676Sjpk 		return (-1);
8681676Sjpk 
8691676Sjpk 	(void) fchown(lockfd, DA_UID, DA_GID);
8701676Sjpk 
8711676Sjpk 	if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
8721676Sjpk 		/* cannot position lock file */
8731676Sjpk 		(void) close(lockfd);
8741676Sjpk 		return (-1);
8751676Sjpk 	}
8761676Sjpk 	if (lockf(lockfd, F_TLOCK, 0) == -1) {
8771676Sjpk 		/* cannot set lock */
8781676Sjpk 		(void) close(lockfd);
8791676Sjpk 		return (-1);
8801676Sjpk 	}
8811676Sjpk 	(void) utime(lockfile, NULL);
8821676Sjpk 
8831676Sjpk 	return (lockfd);
8841676Sjpk }
8851676Sjpk 
8861676Sjpk /*
8871676Sjpk  * da_open_devdb -
8881676Sjpk  *	opens one or both database files - device_allocate, device_maps - in
8891676Sjpk  *	the specified mode.
8901676Sjpk  *	locks the database files; lock is either broken explicitly by the
8911676Sjpk  *	caller by closing the lock file fd, or it expires automatically at
8921676Sjpk  *	process termination.
8931676Sjpk  *	writes the file pointer of opened file in the input args - dafp, dmfp.
8941676Sjpk  *	returns fd of the lock file on success, -2 if database file does not
8951676Sjpk  *	exist, -1 on other errors.
8961676Sjpk  */
8971676Sjpk int
8981676Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
8991676Sjpk {
9001676Sjpk 	int	oflag = 0;
9011676Sjpk 	int	fda = -1;
9021676Sjpk 	int	fdm = -1;
9031676Sjpk 	int	lockfd = -1;
9041676Sjpk 	char	*fname;
9051676Sjpk 	char	*fmode;
9061676Sjpk 	char	path[MAXPATHLEN];
9071676Sjpk 	FILE	*devfile;
9081676Sjpk 
9091676Sjpk 	if ((dafp == NULL) && (dmfp == NULL))
9101676Sjpk 		return (-1);
9111676Sjpk 
9121676Sjpk 	if (flag & DA_RDWR) {
9131676Sjpk 		oflag = DA_RDWR;
914*1914Scasper 		fmode = "r+F";
9151676Sjpk 	} else if (flag & DA_RDONLY) {
9161676Sjpk 		oflag = DA_RDONLY;
917*1914Scasper 		fmode = "rF";
9181676Sjpk 	}
9191676Sjpk 
9201676Sjpk 	if ((lockfd = _da_lock_devdb(rootdir)) == -1)
9211676Sjpk 		return (-1);
9221676Sjpk 
9231676Sjpk 	if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
9241676Sjpk 		goto dmap_only;
9251676Sjpk 
9261676Sjpk 	path[0] = '\0';
9271676Sjpk 
9281676Sjpk 	/*
9291676Sjpk 	 * open the device allocation file
9301676Sjpk 	 */
9311676Sjpk 	if (rootdir == NULL) {
9321676Sjpk 		fname = DEVALLOC;
9331676Sjpk 	} else {
9341676Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
9351676Sjpk 		    DEVALLOC) >= sizeof (path)) {
9361676Sjpk 			if (lockfd != -1)
9371676Sjpk 				(void) close(lockfd);
9381676Sjpk 			return (-1);
9391676Sjpk 		}
9401676Sjpk 		fname = path;
9411676Sjpk 	}
9421676Sjpk 	if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
9431676Sjpk 		if (lockfd != -1)
9441676Sjpk 			(void) close(lockfd);
9451676Sjpk 		return ((errno == ENOENT) ? -2 : -1);
9461676Sjpk 	}
9471676Sjpk 	if ((devfile = fdopen(fda, fmode)) == NULL) {
9481676Sjpk 		(void) close(fda);
9491676Sjpk 		if (lockfd != -1)
9501676Sjpk 			(void) close(lockfd);
9511676Sjpk 		return (-1);
9521676Sjpk 	}
9531676Sjpk 	*dafp = devfile;
9541676Sjpk 	(void) fchmod(fda, DA_DBMODE);
9551676Sjpk 
9561676Sjpk 	if ((flag & DA_ALLOC_ONLY))
9571676Sjpk 		goto out;
9581676Sjpk 
9591676Sjpk dmap_only:
9601676Sjpk 	path[0] = '\0';
9611676Sjpk 	/*
9621676Sjpk 	 * open the device map file
9631676Sjpk 	 */
9641676Sjpk 	if (rootdir == NULL) {
9651676Sjpk 		fname = DEVMAP;
9661676Sjpk 	} else {
9671676Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
9681676Sjpk 		    DEVMAP) >= sizeof (path)) {
9691676Sjpk 			(void) close(fda);
9701676Sjpk 			if (lockfd != -1)
9711676Sjpk 				(void) close(lockfd);
9721676Sjpk 			return (-1);
9731676Sjpk 		}
9741676Sjpk 		fname = path;
9751676Sjpk 	}
9761676Sjpk 
9771676Sjpk 	if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
9781676Sjpk 		if (lockfd != -1)
9791676Sjpk 			(void) close(lockfd);
9801676Sjpk 		return ((errno == ENOENT) ? -2 : -1);
9811676Sjpk 	}
9821676Sjpk 
9831676Sjpk 	if ((devfile = fdopen(fdm, fmode)) == NULL) {
9841676Sjpk 		(void) close(fdm);
9851676Sjpk 		(void) close(fda);
9861676Sjpk 		if (lockfd != -1)
9871676Sjpk 			(void) close(lockfd);
9881676Sjpk 		return (-1);
9891676Sjpk 	}
9901676Sjpk 	*dmfp = devfile;
9911676Sjpk 	(void) fchmod(fdm, DA_DBMODE);
9921676Sjpk 
9931676Sjpk out:
9941676Sjpk 	return (lockfd);
9951676Sjpk }
9961676Sjpk 
9971676Sjpk /*
9981676Sjpk  * _record_on_off -
9991676Sjpk  *	adds either DA_ON_STR or DA_OFF_STR to device_allocate
10001676Sjpk  *	returns 0 on success, -1 on error.
10011676Sjpk  */
10021676Sjpk static int
10031676Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
10041676Sjpk {
10051676Sjpk 	int		dafd;
10061676Sjpk 	int		nsize;
10071676Sjpk 	int		nitems = 1;
10081676Sjpk 	int		actionlen;
10091676Sjpk 	int		str_found = 0;
10101676Sjpk 	int		len = 0, nlen = 0, plen = 0;
10111676Sjpk 	char		*ptr = NULL;
10121676Sjpk 	char		*actionstr;
10131676Sjpk 	char		*nbuf = NULL;
10141676Sjpk 	char		line[MAX_CANON];
10151676Sjpk 	struct stat	dastat;
10161676Sjpk 
10171676Sjpk 	if (dargs->optflag & DA_ON)
10181676Sjpk 		actionstr = DA_ON_STR;
10191676Sjpk 	else
10201676Sjpk 		actionstr = DA_OFF_STR;
10211676Sjpk 	actionlen = strlen(actionstr);
10221676Sjpk 	dafd = fileno(dafp);
10231676Sjpk 	if (fstat(dafd, &dastat) == -1)
10241676Sjpk 		return (-1);
10251676Sjpk 
10261676Sjpk 	/* check the old device_allocate for on/off string */
10271676Sjpk 	ptr = fgets(line, MAX_CANON, dafp);
10281676Sjpk 	if (ptr != NULL) {
10291676Sjpk 		if ((strcmp(line, DA_ON_STR) == 0) ||
10301676Sjpk 		    (strcmp(line, DA_OFF_STR) == 0)) {
10311676Sjpk 			str_found = 1;
10321676Sjpk 			nsize = dastat.st_size;
10331676Sjpk 		}
10341676Sjpk 	}
10351676Sjpk 	if (!ptr || !str_found) {
10361676Sjpk 		/*
10371676Sjpk 		 * the file never had either the on or the off string;
10381676Sjpk 		 * make room for it.
10391676Sjpk 		 */
10401676Sjpk 		str_found = 0;
10411676Sjpk 		nsize = dastat.st_size + actionlen + 1;
10421676Sjpk 	}
10431676Sjpk 	if ((nbuf = (char *)malloc(nsize)) == NULL)
10441676Sjpk 		return (-1);
10451676Sjpk 	nbuf[0] = '\0';
10461676Sjpk 	/* put the on/off string */
10471676Sjpk 	(void) strcpy(nbuf, actionstr);
10481676Sjpk 	nlen = strlen(nbuf);
10491676Sjpk 	plen = nlen;
10501676Sjpk 	if (ptr && !str_found) {
10511676Sjpk 		/* now put the first line that we read in fgets */
10521676Sjpk 		nlen = plen + strlen(line) + 1;
10531676Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
10541676Sjpk 		if (len >= nsize) {
10551676Sjpk 			free(nbuf);
10561676Sjpk 			return (-1);
10571676Sjpk 		}
10581676Sjpk 		plen += len;
10591676Sjpk 	}
10601676Sjpk 
10611676Sjpk 	/* now get the rest of the old file */
10621676Sjpk 	while (fgets(line, MAX_CANON, dafp) != NULL) {
10631676Sjpk 		nlen = plen + strlen(line) + 1;
10641676Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
10651676Sjpk 		if (len >= nsize) {
10661676Sjpk 			free(nbuf);
10671676Sjpk 			return (-1);
10681676Sjpk 		}
10691676Sjpk 		plen += len;
10701676Sjpk 	}
10711676Sjpk 	len = strlen(nbuf) + 1;
10721676Sjpk 	if (len < nsize)
10731676Sjpk 		nbuf[len] = '\n';
10741676Sjpk 
10751676Sjpk 	/* write the on/off str + the old device_allocate to the temp file */
10761676Sjpk 	if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
10771676Sjpk 		free(nbuf);
10781676Sjpk 		return (-1);
10791676Sjpk 	}
10801676Sjpk 
10811676Sjpk 	free(nbuf);
10821676Sjpk 
10831676Sjpk 	return (0);
10841676Sjpk }
10851676Sjpk 
10861676Sjpk /*
10871676Sjpk  * da_update_defattrs -
10881676Sjpk  *	writes default attributes to devalloc_defaults
10891676Sjpk  *	returns 0 on success, -1 on error.
10901676Sjpk  */
10911676Sjpk int
10921676Sjpk da_update_defattrs(da_args *dargs)
10931676Sjpk {
10941676Sjpk 	int		rc = 0, lockfd = 0, tmpfd = 0;
10951676Sjpk 	char		*defpath = DEFATTRS;
10961676Sjpk 	char		*tmpdefpath = TMPATTRS;
10971676Sjpk 	FILE		*tmpfp = NULL;
10981676Sjpk 	struct stat	dstat;
10991676Sjpk 	strentry_t	*head_defent = NULL;
11001676Sjpk 
11011676Sjpk 	if (dargs == NULL)
11021676Sjpk 		return (0);
11031676Sjpk 	if ((lockfd = _da_lock_devdb(NULL)) == -1)
11041676Sjpk 		return (-1);
11051676Sjpk 	if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
11061676Sjpk 		(void) close(lockfd);
11071676Sjpk 		return (-1);
11081676Sjpk 	}
11091676Sjpk 	(void) fchown(tmpfd, DA_UID, DA_GID);
11101676Sjpk 	if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) {
11111676Sjpk 		(void) close(tmpfd);
11121676Sjpk 		(void) unlink(tmpdefpath);
11131676Sjpk 		(void) close(lockfd);
11141676Sjpk 		return (-1);
11151676Sjpk 	}
11161676Sjpk 	/*
11171676Sjpk 	 * examine all entries, remove an old one if required, check
11181676Sjpk 	 * if a new one needs to be added.
11191676Sjpk 	 */
11201676Sjpk 	if (stat(defpath, &dstat) == 0) {
11211676Sjpk 		if ((rc = _build_defattrs(dargs, &head_defent)) != 0) {
11221676Sjpk 			if (rc == 1) {
11231676Sjpk 				(void) close(tmpfd);
11241676Sjpk 				(void) unlink(tmpdefpath);
11251676Sjpk 				(void) close(lockfd);
11261676Sjpk 				return (rc);
11271676Sjpk 			}
11281676Sjpk 		}
11291676Sjpk 	}
11301676Sjpk 	/*
11311676Sjpk 	 * write back any existing entries.
11321676Sjpk 	 */
11331676Sjpk 	_write_defattrs(tmpfp, head_defent);
11341676Sjpk 
11351676Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
11361676Sjpk 		/* add new entries */
11371676Sjpk 		rc = _write_new_defattrs(tmpfp, dargs);
11381676Sjpk 		(void) fclose(tmpfp);
11391676Sjpk 	} else {
11401676Sjpk 		(void) fclose(tmpfp);
11411676Sjpk 	}
11421676Sjpk 	if (rename(tmpdefpath, defpath) != 0) {
11431676Sjpk 		rc = -1;
11441676Sjpk 		(void) unlink(tmpdefpath);
11451676Sjpk 	}
11461676Sjpk 	(void) close(lockfd);
11471676Sjpk 
11481676Sjpk 	return (rc);
11491676Sjpk }
11501676Sjpk 
11511676Sjpk /*
11521676Sjpk  * da_update_device -
11531676Sjpk  *	writes devices entries to device_allocate and device_maps.
11541676Sjpk  * 	returns 0 on success, -1 on error.
11551676Sjpk  */
11561676Sjpk int
11571676Sjpk da_update_device(da_args *dargs)
11581676Sjpk {
11591676Sjpk 	int		rc;
11601676Sjpk 	int		tafd = -1, tmfd = -1;
11611676Sjpk 	int		lockfd = -1;
11621676Sjpk 	char		*rootdir = NULL;
11631676Sjpk 	char		*apathp = NULL, *mpathp = NULL, *dapathp = NULL,
11641676Sjpk 			*dmpathp = NULL;
11651676Sjpk 	char		apath[MAXPATHLEN], mpath[MAXPATHLEN],
11661676Sjpk 			dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
11671676Sjpk 	FILE		*tafp = NULL, *tmfp = NULL, *dafp = NULL;
11681676Sjpk 	struct stat	dastat;
11691676Sjpk 	devinfo_t	*devinfo;
11701676Sjpk 	strentry_t	*head_devmapp = NULL;
11711676Sjpk 	strentry_t	*head_devallocp = NULL;
11721676Sjpk 
11731676Sjpk 	if (dargs == NULL)
11741676Sjpk 		return (0);
11751676Sjpk 
11761676Sjpk 	rootdir = dargs->rootdir;
11771676Sjpk 	devinfo = dargs->devinfo;
11781676Sjpk 
11791676Sjpk 	/*
11801676Sjpk 	 * adding/removing entries should be done in both
11811676Sjpk 	 * device_allocate and device_maps. updates can be
11821676Sjpk 	 * done in both or either of the files.
11831676Sjpk 	 */
11841676Sjpk 	if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
11851676Sjpk 		if (dargs->optflag & DA_ALLOC_ONLY ||
11861676Sjpk 		    dargs->optflag & DA_MAPS_ONLY)
11871676Sjpk 			return (0);
11881676Sjpk 	}
11891676Sjpk 
11901676Sjpk 	/*
11911676Sjpk 	 * name, type and list are required fields for adding a new
11921676Sjpk 	 * device.
11931676Sjpk 	 */
11941676Sjpk 	if ((dargs->optflag & DA_ADD) &&
11951676Sjpk 	    ((devinfo->devname == NULL) ||
11961676Sjpk 	    (devinfo->devtype == NULL) ||
11971676Sjpk 	    (devinfo->devlist == NULL))) {
11981676Sjpk 		return (-1);
11991676Sjpk 	}
12001676Sjpk 
12011676Sjpk 	if (rootdir != NULL) {
12021676Sjpk 		if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
12031676Sjpk 		    TMPALLOC) >= sizeof (apath))
12041676Sjpk 			return (-1);
12051676Sjpk 		apathp = apath;
12061676Sjpk 		if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
12071676Sjpk 		    DEVALLOC) >= sizeof (dapath))
12081676Sjpk 			return (-1);
12091676Sjpk 		dapathp = dapath;
12101676Sjpk 		if (!(dargs->optflag & DA_ALLOC_ONLY)) {
12111676Sjpk 			if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
12121676Sjpk 			    TMPMAP) >= sizeof (mpath))
12131676Sjpk 				return (-1);
12141676Sjpk 			mpathp = mpath;
12151676Sjpk 			if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
12161676Sjpk 			    DEVMAP) >= sizeof (dmpath))
12171676Sjpk 				return (-1);
12181676Sjpk 			dmpathp = dmpath;
12191676Sjpk 		}
12201676Sjpk 	} else {
12211676Sjpk 		apathp = TMPALLOC;
12221676Sjpk 		dapathp = DEVALLOC;
12231676Sjpk 		mpathp = TMPMAP;
12241676Sjpk 		dmpathp = DEVMAP;
12251676Sjpk 	}
12261676Sjpk 
12271676Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
12281676Sjpk 		goto dmap_only;
12291676Sjpk 
12301676Sjpk 	/*
12311676Sjpk 	 * Check if we are here just to record on/off status of
12321676Sjpk 	 * device_allocation.
12331676Sjpk 	 */
12341676Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
12351676Sjpk 		lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
12361676Sjpk 		    DA_RDONLY|DA_ALLOC_ONLY);
12371676Sjpk 	else
12381676Sjpk 		lockfd = _da_lock_devdb(rootdir);
12391676Sjpk 	if (lockfd == -1)
12401676Sjpk 		return (-1);
12411676Sjpk 
12421676Sjpk 	if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
12431676Sjpk 		(void) close(lockfd);
12441676Sjpk 		(void) fclose(dafp);
12451676Sjpk 		return (-1);
12461676Sjpk 	}
12471676Sjpk 	(void) fchown(tafd, DA_UID, DA_GID);
12481676Sjpk 	if ((tafp = fdopen(tafd, "r+")) == NULL) {
12491676Sjpk 		(void) close(tafd);
12501676Sjpk 		(void) unlink(apathp);
12511676Sjpk 		(void) fclose(dafp);
12521676Sjpk 		(void) close(lockfd);
12531676Sjpk 		return (-1);
12541676Sjpk 	}
12551676Sjpk 
12561676Sjpk 	/*
12571676Sjpk 	 * We don't need to parse the file if we are here just to record
12581676Sjpk 	 * on/off status of device_allocation.
12591676Sjpk 	 */
12601676Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
12611676Sjpk 		if (_record_on_off(dargs, tafp, dafp) == -1) {
12621676Sjpk 			(void) close(tafd);
12631676Sjpk 			(void) unlink(apathp);
12641676Sjpk 			(void) fclose(dafp);
12651676Sjpk 			(void) close(lockfd);
12661676Sjpk 			return (-1);
12671676Sjpk 		}
12681676Sjpk 		(void) fclose(dafp);
12691676Sjpk 		goto out;
12701676Sjpk 	}
12711676Sjpk 
12721676Sjpk 	/*
12731676Sjpk 	 * examine all the entries, remove an old one if forced to,
12741676Sjpk 	 * and check that they are suitable for updating.
12751676Sjpk 	 *  we need to do this only if the file exists already.
12761676Sjpk 	 */
12771676Sjpk 	if (stat(dapathp, &dastat) == 0) {
12781676Sjpk 		if ((rc = _build_lists(dargs, &head_devallocp,
12791676Sjpk 		    &head_devmapp)) != 0) {
12801676Sjpk 			if (rc != 1) {
12811676Sjpk 				(void) close(tafd);
12821676Sjpk 				(void) unlink(apathp);
12831676Sjpk 				(void) close(lockfd);
12841676Sjpk 				return (rc);
12851676Sjpk 			}
12861676Sjpk 		}
12871676Sjpk 	}
12881676Sjpk 
12891676Sjpk 	/*
12901676Sjpk 	 * write back any existing devalloc entries, along with
12911676Sjpk 	 * the devalloc on/off string.
12921676Sjpk 	 */
12931676Sjpk 	_write_device_allocate(dapathp, tafp, head_devallocp);
12941676Sjpk 
12951676Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
12961676Sjpk 		goto out;
12971676Sjpk 
12981676Sjpk dmap_only:
12991676Sjpk 	if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
13001676Sjpk 		(void) close(tafd);
13011676Sjpk 		(void) unlink(apathp);
13021676Sjpk 		(void) close(lockfd);
13031676Sjpk 		return (-1);
13041676Sjpk 	}
13051676Sjpk 	(void) fchown(tmfd, DA_UID, DA_GID);
13061676Sjpk 	if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
13071676Sjpk 		(void) close(tafd);
13081676Sjpk 		(void) unlink(apathp);
13091676Sjpk 		(void) close(tmfd);
13101676Sjpk 		(void) unlink(mpathp);
13111676Sjpk 		(void) close(lockfd);
13121676Sjpk 		return (-1);
13131676Sjpk 	}
13141676Sjpk 
13151676Sjpk 	/* write back any existing devmap entries */
13161676Sjpk 	if (head_devmapp != NULL)
13171676Sjpk 		_write_device_maps(tmfp, head_devmapp);
13181676Sjpk 
13191676Sjpk out:
13201676Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
13211676Sjpk 		/* add any new entries */
13221676Sjpk 		rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
13231676Sjpk 		(void) fclose(tafp);
13241676Sjpk 
13251676Sjpk 		if (rc == 0)
13261676Sjpk 			rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
13271676Sjpk 		(void) fclose(tmfp);
13281676Sjpk 	} else {
13291676Sjpk 		if (tafp)
13301676Sjpk 			(void) fclose(tafp);
13311676Sjpk 		if (tmfp)
13321676Sjpk 			(void) fclose(tmfp);
13331676Sjpk 	}
13341676Sjpk 
13351676Sjpk 	rc = 0;
13361676Sjpk 	if (!(dargs->optflag & DA_MAPS_ONLY)) {
13371676Sjpk 		if (rename(apathp, dapathp) != 0) {
13381676Sjpk 			rc = -1;
13391676Sjpk 			(void) unlink(apathp);
13401676Sjpk 		}
13411676Sjpk 	}
13421676Sjpk 	if (!(dargs->optflag & DA_ALLOC_ONLY)) {
13431676Sjpk 		if (rename(mpathp, dmpathp) != 0) {
13441676Sjpk 			rc = -1;
13451676Sjpk 			(void) unlink(mpathp);
13461676Sjpk 		}
13471676Sjpk 	}
13481676Sjpk 
13491676Sjpk 	(void) close(lockfd);
13501676Sjpk 
13511676Sjpk 	return (rc);
13521676Sjpk }
13531676Sjpk 
13541676Sjpk /*
13551676Sjpk  * da_add_list -
13561676Sjpk  *	adds new /dev link name to the linked list of devices.
13571676Sjpk  *	returns 0 if link added successfully, -1 on error.
13581676Sjpk  */
13591676Sjpk int
13601676Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
13611676Sjpk {
13621676Sjpk 	int		instance;
13631676Sjpk 	int		nlen, plen;
13641676Sjpk 	int		new_entry = 0;
13651676Sjpk 	char		*dtype, *dexec, *tname, *kval;
13661676Sjpk 	char		*minstr = NULL, *maxstr = NULL;
13671676Sjpk 	char		dname[DA_MAXNAME];
13681676Sjpk 	kva_t		*kva;
13691676Sjpk 	deventry_t	*dentry = NULL, *nentry = NULL, *pentry = NULL;
13701676Sjpk 	da_defs_t	*da_defs;
13711676Sjpk 
13721676Sjpk 	if (dlist == NULL || link == NULL)
13731676Sjpk 		return (-1);
13741676Sjpk 
13751676Sjpk 	dname[0] = '\0';
13761676Sjpk 	if (flag & DA_AUDIO) {
13771676Sjpk 		dentry = dlist->audio;
13781676Sjpk 		tname = DA_AUDIO_NAME;
13791676Sjpk 		dtype = DA_AUDIO_TYPE;
13801676Sjpk 		dexec = DA_DEFAULT_AUDIO_CLEAN;
13811676Sjpk 	} else if (flag & DA_CD) {
13821676Sjpk 		dentry = dlist->cd;
13831676Sjpk 		tname = DA_CD_NAME;
13841676Sjpk 		dtype = DA_CD_TYPE;
13851676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
13861676Sjpk 	} else if (flag & DA_FLOPPY) {
13871676Sjpk 		dentry = dlist->floppy;
13881676Sjpk 		tname = DA_FLOPPY_NAME;
13891676Sjpk 		dtype = DA_FLOPPY_TYPE;
13901676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
13911676Sjpk 	} else if (flag & DA_TAPE) {
13921676Sjpk 		dentry = dlist->tape;
13931676Sjpk 		tname = DA_TAPE_NAME;
13941676Sjpk 		dtype = DA_TAPE_TYPE;
13951676Sjpk 		dexec = DA_DEFAULT_TAPE_CLEAN;
13961676Sjpk 	} else if (flag & DA_RMDISK) {
13971676Sjpk 		dentry = dlist->rmdisk;
13981676Sjpk 		tname = DA_RMDISK_NAME;
13991676Sjpk 		dtype = DA_RMDISK_TYPE;
14001676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
14011676Sjpk 	} else {
14021676Sjpk 		return (-1);
14031676Sjpk 	}
14041676Sjpk 
14051676Sjpk 	for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
14061676Sjpk 		pentry = nentry;
14071676Sjpk 		(void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
14081676Sjpk 		if (nentry->devinfo.instance == new_instance)
14091676Sjpk 			/*
14101676Sjpk 			 * Add the new link name to the list of links
14111676Sjpk 			 * that the device 'dname' has.
14121676Sjpk 			 */
14131676Sjpk 			break;
14141676Sjpk 	}
14151676Sjpk 
14161676Sjpk 	if (nentry == NULL) {
14171676Sjpk 		/*
14181676Sjpk 		 * Either this is the first entry ever, or no matching entry
14191676Sjpk 		 * was found. Create a new one and add to the list.
14201676Sjpk 		 */
14211676Sjpk 		if (dentry == NULL)		/* first entry ever */
14221676Sjpk 			instance = 0;
14231676Sjpk 		else				/* no matching entry */
14241676Sjpk 			instance++;
14251676Sjpk 		(void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
14261676Sjpk 		if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
14271676Sjpk 		    NULL)
14281676Sjpk 			return (-1);
14291676Sjpk 		if (pentry != NULL)
14301676Sjpk 			pentry->next = nentry;
14311676Sjpk 		new_entry = 1;
14321676Sjpk 		nentry->devinfo.devname = strdup(dname);
14331676Sjpk 		nentry->devinfo.devtype = dtype;
14341676Sjpk 		nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
14351676Sjpk 		nentry->devinfo.devexec = dexec;
14361676Sjpk 		nentry->devinfo.instance = new_instance;
14371676Sjpk 		/*
14381676Sjpk 		 * Look for default label range, authorizations and cleaning
14391676Sjpk 		 * program in devalloc_defaults. If label range is not
14401676Sjpk 		 * specified in devalloc_defaults, assume it to be admin_low
14411676Sjpk 		 * to admin_high.
14421676Sjpk 		 */
14431676Sjpk 		minstr = DA_DEFAULT_MIN;
14441676Sjpk 		maxstr = DA_DEFAULT_MAX;
14451676Sjpk 		setdadefent();
14461676Sjpk 		if (da_defs = getdadeftype(nentry->devinfo.devtype)) {
14471676Sjpk 			kva = da_defs->devopts;
14481676Sjpk 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
14491676Sjpk 				minstr = strdup(kval);
14501676Sjpk 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
14511676Sjpk 				maxstr = strdup(kval);
14521676Sjpk 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
14531676Sjpk 				nentry->devinfo.devauths = strdup(kval);
14541676Sjpk 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
14551676Sjpk 				nentry->devinfo.devexec = strdup(kval);
14561676Sjpk 			freedadefent(da_defs);
14571676Sjpk 		}
14581676Sjpk 		enddadefent();
14591676Sjpk 		kval = NULL;
14601676Sjpk 		nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
14611676Sjpk 		    strlen(minstr) + strlen(KV_TOKEN_DELIMIT) +
14621676Sjpk 		    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr)
14631676Sjpk 		    + 1;			/* +1 for terminator */
14641676Sjpk 		if (kval = (char *)malloc(nlen))
14651676Sjpk 			(void) snprintf(kval, nlen, "%s%s%s%s%s%s%s",
14661676Sjpk 			    DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT,
14671676Sjpk 			    DAOPT_MAXLABEL, KV_ASSIGN, maxstr);
14681676Sjpk 		nentry->devinfo.devopts = kval;
14691676Sjpk 
14701676Sjpk 		nentry->devinfo.devlist = NULL;
14711676Sjpk 		nentry->next = NULL;
14721676Sjpk 	}
14731676Sjpk 
14741676Sjpk 	nlen = strlen(link) + 1;		/* +1 terminator */
14751676Sjpk 	if (nentry->devinfo.devlist) {
14761676Sjpk 		plen = strlen(nentry->devinfo.devlist);
14771676Sjpk 		nlen = nlen + plen + 1;	/* +1 for blank to separate entries */
14781676Sjpk 	} else {
14791676Sjpk 		plen = 0;
14801676Sjpk 	}
14811676Sjpk 
14821676Sjpk 	if ((nentry->devinfo.devlist =
14831676Sjpk 	    (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
14841676Sjpk 		if (new_entry) {
14851676Sjpk 			nentry->devinfo.devname = NULL;
14861676Sjpk 			free(nentry->devinfo.devname);
14871676Sjpk 			nentry = NULL;
14881676Sjpk 			free(nentry);
14891676Sjpk 			if (pentry != NULL)
14901676Sjpk 				pentry->next = NULL;
14911676Sjpk 		}
14921676Sjpk 		return (-1);
14931676Sjpk 	}
14941676Sjpk 
14951676Sjpk 	if (plen == 0)
14961676Sjpk 		(void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
14971676Sjpk 	else
14981676Sjpk 		(void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
14991676Sjpk 		    " %s", link);
15001676Sjpk 
15011676Sjpk 	if (pentry == NULL) {
15021676Sjpk 		/*
15031676Sjpk 		 * This is the first entry of this device type.
15041676Sjpk 		 */
15051676Sjpk 		if (flag & DA_AUDIO)
15061676Sjpk 			dlist->audio = nentry;
15071676Sjpk 		else if (flag & DA_CD)
15081676Sjpk 			dlist->cd = nentry;
15091676Sjpk 		else if (flag & DA_FLOPPY)
15101676Sjpk 			dlist->floppy = nentry;
15111676Sjpk 		else if (flag & DA_TAPE)
15121676Sjpk 			dlist->tape = nentry;
15131676Sjpk 		else if (flag & DA_RMDISK)
15141676Sjpk 			dlist->rmdisk = nentry;
15151676Sjpk 	}
15161676Sjpk 
15171676Sjpk 	return (0);
15181676Sjpk }
15191676Sjpk 
15201676Sjpk /*
15211676Sjpk  * da_remove_list -
15221676Sjpk  *	removes a /dev link name from the linked list of devices.
15231676Sjpk  *	returns type of device if link for that device removed
15241676Sjpk  *	successfully, else returns -1 on error.
15251676Sjpk  *	if all links for a device are removed, stores that device
15261676Sjpk  *	name in devname.
15271676Sjpk  */
15281676Sjpk int
15291676Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
15301676Sjpk {
15311676Sjpk 	int		flag;
15321676Sjpk 	int		remove_dev = 0;
15331676Sjpk 	int		nlen, plen, slen;
15341676Sjpk 	char		*lasts, *lname, *oldlist;
15351676Sjpk 	struct stat	rmstat;
15361676Sjpk 	deventry_t	*dentry, *current, *prev;
15371676Sjpk 
15381676Sjpk 	if (type != NULL)
15391676Sjpk 		flag = type;
15401676Sjpk 	else if (link == NULL)
15411676Sjpk 		return (-1);
15421676Sjpk 	else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
15431676Sjpk 		flag = DA_AUDIO;
15441676Sjpk 	else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
15451676Sjpk 	    strstr(link, "sr") || strstr(link, "rsr"))
15461676Sjpk 		flag = DA_CD;
15471676Sjpk 	else if (strstr(link, "fd") || strstr(link, "rfd") ||
15481676Sjpk 	    strstr(link, "diskette") || strstr(link, "rdiskette"))
15491676Sjpk 		flag = DA_FLOPPY;
15501676Sjpk 	else if (strstr(link, DA_TAPE_NAME))
15511676Sjpk 		flag = DA_TAPE;
15521676Sjpk 	else
15531676Sjpk 		flag = DA_RMDISK;
15541676Sjpk 
15551676Sjpk 	switch (type) {
15561676Sjpk 	case DA_AUDIO:
15571676Sjpk 		dentry = dlist->audio;
15581676Sjpk 		break;
15591676Sjpk 	case DA_CD:
15601676Sjpk 		dentry = dlist->cd;
15611676Sjpk 		break;
15621676Sjpk 	case DA_FLOPPY:
15631676Sjpk 		dentry = dlist->floppy;
15641676Sjpk 		break;
15651676Sjpk 	case DA_TAPE:
15661676Sjpk 		dentry = dlist->tape;
15671676Sjpk 		break;
15681676Sjpk 	case DA_RMDISK:
15691676Sjpk 		dentry = dlist->rmdisk;
15701676Sjpk 		break;
15711676Sjpk 	default:
15721676Sjpk 		return (-1);
15731676Sjpk 	}
15741676Sjpk 
15751676Sjpk 	if ((type != NULL) && (link == NULL)) {
15761676Sjpk 		for (current = dentry, prev = dentry; current != NULL;
15771676Sjpk 		    current = current->next) {
15781676Sjpk 			oldlist = strdup(current->devinfo.devlist);
15791676Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
15801676Sjpk 			    lname != NULL;
15811676Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
15821676Sjpk 				if (stat(lname, &rmstat) != 0) {
15831676Sjpk 					remove_dev = 1;
15841676Sjpk 					goto remove_dev;
15851676Sjpk 				}
15861676Sjpk 			}
15871676Sjpk 			prev = current;
15881676Sjpk 		}
15891676Sjpk 		return (-1);
15901676Sjpk 	}
15911676Sjpk 
15921676Sjpk 	for (current = dentry, prev = dentry; current != NULL;
15931676Sjpk 	    current = current->next) {
15941676Sjpk 		plen = strlen(current->devinfo.devlist);
15951676Sjpk 		nlen = strlen(link);
15961676Sjpk 		if (plen == nlen) {
15971676Sjpk 			if (strcmp(current->devinfo.devlist, link) == 0) {
15981676Sjpk 				/* last name in the list */
15991676Sjpk 				remove_dev = 1;
16001676Sjpk 				break;
16011676Sjpk 			}
16021676Sjpk 		}
16031676Sjpk 		if (strstr(current->devinfo.devlist, link)) {
16041676Sjpk 			nlen = plen - nlen + 1;
16051676Sjpk 			oldlist = strdup(current->devinfo.devlist);
16061676Sjpk 			if ((current->devinfo.devlist =
16071676Sjpk 			    (char *)realloc(current->devinfo.devlist,
16081676Sjpk 			    nlen)) == NULL) {
16091676Sjpk 				free(oldlist);
16101676Sjpk 				return (-1);
16111676Sjpk 			}
16121676Sjpk 			current->devinfo.devlist[0] = '\0';
16131676Sjpk 			nlen = plen = slen = 0;
16141676Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
16151676Sjpk 			    lname != NULL;
16161676Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
16171676Sjpk 				if (strcmp(lname, link) == 0)
16181676Sjpk 					continue;
16191676Sjpk 				nlen = strlen(lname) + plen + 1;
16201676Sjpk 				if (plen == 0) {
16211676Sjpk 					slen =
16221676Sjpk 					    snprintf(current->devinfo.devlist,
16231676Sjpk 						nlen, "%s", lname);
16241676Sjpk 				} else {
16251676Sjpk 					slen =
16261676Sjpk 					    snprintf(current->devinfo.devlist +
16271676Sjpk 						plen, nlen - plen, " %s",
16281676Sjpk 						lname);
16291676Sjpk 				}
16301676Sjpk 				plen = plen + slen + 1;
16311676Sjpk 			}
16321676Sjpk 			free(oldlist);
16331676Sjpk 			break;
16341676Sjpk 		}
16351676Sjpk 		prev = current;
16361676Sjpk 	}
16371676Sjpk 
16381676Sjpk remove_dev:
16391676Sjpk 	if (remove_dev == 1) {
16401676Sjpk 		(void) strlcpy(devname, current->devinfo.devname, size);
16411676Sjpk 		free(current->devinfo.devname);
16421676Sjpk 		free(current->devinfo.devlist);
16431676Sjpk 		current->devinfo.devname = current->devinfo.devlist = NULL;
16441676Sjpk 		prev->next = current->next;
16451676Sjpk 		free(current);
16461676Sjpk 		current = NULL;
16471676Sjpk 	}
16481676Sjpk 	if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
16491676Sjpk 		if (prev->next) {
16501676Sjpk 			/*
16511676Sjpk 			 * what we removed above was the first entry
16521676Sjpk 			 * in the list. make the next entry to be the
16531676Sjpk 			 * first.
16541676Sjpk 			 */
16551676Sjpk 			current = prev->next;
16561676Sjpk 		} else {
16571676Sjpk 			/*
16581676Sjpk 			 * the matching entry was the only entry in the list
16591676Sjpk 			 * for this type.
16601676Sjpk 			 */
16611676Sjpk 			current = NULL;
16621676Sjpk 		}
16631676Sjpk 		if (flag & DA_AUDIO)
16641676Sjpk 			dlist->audio = current;
16651676Sjpk 		else if (flag & DA_CD)
16661676Sjpk 			dlist->cd = current;
16671676Sjpk 		else if (flag & DA_FLOPPY)
16681676Sjpk 			dlist->floppy = current;
16691676Sjpk 		else if (flag & DA_TAPE)
16701676Sjpk 			dlist->tape = current;
16711676Sjpk 		else if (flag & DA_RMDISK)
16721676Sjpk 			dlist->rmdisk = current;
16731676Sjpk 	}
16741676Sjpk 
16751676Sjpk 	return (flag);
16761676Sjpk }
16771676Sjpk 
16781676Sjpk /*
16791676Sjpk  * da_is_on -
16801676Sjpk  *	checks if device allocation feature is turned on.
16811676Sjpk  *	returns 1 if on, 0 if off, -1 if status string not
16821676Sjpk  *	found in device_allocate.
16831676Sjpk  */
16841676Sjpk int
16851676Sjpk da_is_on()
16861676Sjpk {
16871676Sjpk 	return (getdaon());
16881676Sjpk }
16891676Sjpk 
16901676Sjpk /*
16911676Sjpk  * da_print_device -
16921676Sjpk  *	debug routine to print device entries.
16931676Sjpk  */
16941676Sjpk void
16951676Sjpk da_print_device(int flag, devlist_t *devlist)
16961676Sjpk {
16971676Sjpk 	deventry_t	*entry, *dentry;
16981676Sjpk 	devinfo_t	*devinfo;
16991676Sjpk 
17001676Sjpk 	if (flag & DA_AUDIO)
17011676Sjpk 		dentry = devlist->audio;
17021676Sjpk 	else if (flag & DA_CD)
17031676Sjpk 		dentry = devlist->cd;
17041676Sjpk 	else if (flag & DA_FLOPPY)
17051676Sjpk 		dentry = devlist->floppy;
17061676Sjpk 	else if (flag & DA_TAPE)
17071676Sjpk 		dentry = devlist->tape;
17081676Sjpk 	else if (flag & DA_RMDISK)
17091676Sjpk 		dentry = devlist->rmdisk;
17101676Sjpk 	else
17111676Sjpk 		return;
17121676Sjpk 
17131676Sjpk 	for (entry = dentry; entry != NULL; entry = entry->next) {
17141676Sjpk 		devinfo = &(entry->devinfo);
17151676Sjpk 		(void) fprintf(stdout, "name: %s\n", devinfo->devname);
17161676Sjpk 		(void) fprintf(stdout, "type: %s\n", devinfo->devtype);
17171676Sjpk 		(void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
17181676Sjpk 		(void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
17191676Sjpk 		(void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);
17201676Sjpk 	}
17211676Sjpk }
1722