xref: /onnv-gate/usr/src/lib/libbsm/common/devalloc.c (revision 12373:a6d4ab1b6cf3)
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 /*
23*12373SJan.Parcel@Sun.COM  * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
241676Sjpk  */
251676Sjpk 
261676Sjpk #include <stdlib.h>
271676Sjpk #include <ctype.h>
281676Sjpk #include <unistd.h>
291676Sjpk #include <limits.h>
301676Sjpk #include <fcntl.h>
311676Sjpk #include <sys/types.h>
321676Sjpk #include <sys/stat.h>
331676Sjpk #include <utime.h>
341676Sjpk #include <synch.h>
351676Sjpk #include <strings.h>
361676Sjpk #include <string.h>
371676Sjpk #include <libintl.h>
381676Sjpk #include <errno.h>
391676Sjpk #include <auth_list.h>
4011529SJan.Parcel@Sun.COM #include <syslog.h>
411676Sjpk #include <bsm/devices.h>
421676Sjpk #include <bsm/devalloc.h>
43*12373SJan.Parcel@Sun.COM #include <tsol/label.h>
441676Sjpk 
451676Sjpk #define	DA_DEFS	"/etc/security/tsol/devalloc_defaults"
461676Sjpk 
471676Sjpk extern int _readbufline(char *, int, char *, int, int *);
481676Sjpk extern char *strtok_r(char *, const char *, char **);
491676Sjpk extern char *_strtok_escape(char *, char *, char **);
501676Sjpk extern int getdaon(void);
511676Sjpk extern int da_matchname(devalloc_t *, char *);
521676Sjpk extern int da_match(devalloc_t *, da_args *);
531676Sjpk extern int dmap_matchname(devmap_t *, char *);
541676Sjpk extern int dm_match(devmap_t *, da_args *);
5511529SJan.Parcel@Sun.COM extern int dmap_matchtype(devmap_t *dmap, char *type);
5611529SJan.Parcel@Sun.COM extern int dmap_matchdev(devmap_t *dmap, char *dev);
5711529SJan.Parcel@Sun.COM extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num);
5811529SJan.Parcel@Sun.COM extern char *dmap_physname(devmap_t *dmap);
591676Sjpk 
601676Sjpk /*
611676Sjpk  * The following structure is for recording old entries to be retained.
621676Sjpk  * We read the entries from the database into a linked list in memory,
631676Sjpk  * then turn around and write them out again.
641676Sjpk  */
651676Sjpk typedef struct strentry {
661676Sjpk 	struct strentry	*se_next;
671676Sjpk 	char		se_str[4096 + 1];
681676Sjpk } strentry_t;
691676Sjpk 
701676Sjpk /*
711676Sjpk  * da_check_longindevperm -
721676Sjpk  *	reads /etc/logindevperm and checks if specified device is in the file.
731676Sjpk  *	returns 1 if specified device found in /etc/logindevperm, else returns 0
741676Sjpk  */
751676Sjpk int
da_check_logindevperm(char * devname)761676Sjpk da_check_logindevperm(char *devname)
771676Sjpk {
781676Sjpk 	int		ret = 0;
791676Sjpk 	int		fd = -1;
801676Sjpk 	int		nlen, plen, slen, lineno, fsize;
811676Sjpk 	char		line[MAX_CANON];
821676Sjpk 	char		*field_delims = " \t\n";
831676Sjpk 	char		*fbuf = NULL;
841676Sjpk 	char		*ptr, *device;
851676Sjpk 	char		*lasts = NULL;
861676Sjpk 	FILE		*fp;
871676Sjpk 	struct stat	f_stat;
881676Sjpk 
891676Sjpk 	/*
901676Sjpk 	 * check if /etc/logindevperm exists and get its size
911676Sjpk 	 */
921676Sjpk 	if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1)
931676Sjpk 		return (0);
941676Sjpk 	if (fstat(fd, &f_stat) != 0) {
951676Sjpk 		(void) close(fd);
961676Sjpk 		return (0);
971676Sjpk 	}
981676Sjpk 	fsize = f_stat.st_size;
991676Sjpk 	if ((fbuf = (char *)malloc(fsize)) == NULL) {
1001676Sjpk 		(void) close(fd);
1011676Sjpk 		return (0);
1021676Sjpk 	}
1031914Scasper 	if ((fp = fdopen(fd, "rF")) == NULL) {
1041676Sjpk 		free(fbuf);
1051676Sjpk 		(void) close(fd);
1061676Sjpk 		return (0);
1071676Sjpk 	}
1081676Sjpk 
1091676Sjpk 	/*
1101676Sjpk 	 * read and parse /etc/logindevperm
1111676Sjpk 	 */
1121676Sjpk 	plen = nlen = lineno = 0;
1131676Sjpk 	while (fgets(line, MAX_CANON, fp) != NULL) {
1141676Sjpk 		lineno++;
1151676Sjpk 		if ((ptr = strchr(line, '#')) != NULL)
1161676Sjpk 			*ptr = '\0';	/* handle comments */
1171676Sjpk 		if (strtok_r(line, field_delims, &lasts) == NULL)
1181676Sjpk 			continue;	/* ignore blank lines */
1191676Sjpk 		if (strtok_r(NULL, field_delims, &lasts) == NULL)
1201676Sjpk 			/* invalid entry */
1211676Sjpk 			continue;
1221676Sjpk 		if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL)
1231676Sjpk 			/* empty device list */
1241676Sjpk 			continue;
1251676Sjpk 		nlen = strlen(ptr) + 1;		/* +1 terminator */
1261676Sjpk 		nlen += (plen + 1);
1271676Sjpk 		if (plen == 0)
1281676Sjpk 			slen = snprintf(fbuf, nlen, "%s", ptr);
1291676Sjpk 		else
1301676Sjpk 			slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr);
1311676Sjpk 		if (slen >= fsize) {
1321676Sjpk 			fbuf[0] = '\0';
1331676Sjpk 			(void) fclose(fp);
1341676Sjpk 			return (slen);
1351676Sjpk 		}
1361676Sjpk 		plen += slen;
1371676Sjpk 	}
1381676Sjpk 	(void) fclose(fp);
1391676Sjpk 
1401676Sjpk 	/*
1411676Sjpk 	 * check if devname exists in /etc/logindevperm
1421676Sjpk 	 */
1431676Sjpk 	device = strtok_r(fbuf, ":", &lasts);
1441676Sjpk 	while (device != NULL) {
1451676Sjpk 		/*
1461676Sjpk 		 * device and devname may be one of these types -
1471676Sjpk 		 *    /dev/xx
1481676Sjpk 		 *    /dev/xx*
1491676Sjpk 		 *    /dev/dir/xx
1501676Sjpk 		 *    /dev/dir/xx*
1511676Sjpk 		 *    /dev/dir/"*"
1521676Sjpk 		 */
1531676Sjpk 		if (strcmp(device, devname) == 0) {
1541676Sjpk 			/* /dev/xx, /dev/dir/xx */
1551676Sjpk 			free(fbuf);
1561676Sjpk 			return (1);
1571676Sjpk 		}
1581676Sjpk 		if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) {
1591676Sjpk 			/* all wildcard types */
1601676Sjpk 			*ptr = '\0';
1611676Sjpk 			if (strncmp(device, devname, strlen(device)) == 0) {
1621676Sjpk 				free(fbuf);
1631676Sjpk 				return (1);
1641676Sjpk 			}
1651676Sjpk 		}
1661676Sjpk 		device = strtok_r(NULL, ":", &lasts);
1671676Sjpk 	}
1681676Sjpk 
1691676Sjpk 	return (ret);
1701676Sjpk }
1711676Sjpk 
1721676Sjpk /*
1731676Sjpk  * _da_read_file -
1741676Sjpk  *	establishes readers/writer lock on fname; reads in the file if its
1751676Sjpk  *	contents changed since the last time we read it.
1761676Sjpk  *	returns size of buffer read, or -1 on failure.
1771676Sjpk  */
1781676Sjpk int
_da_read_file(char * fname,char ** fbuf,time_t * ftime,rwlock_t * flock,int flag)1791676Sjpk _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock,
1801676Sjpk     int flag)
1811676Sjpk {
1821676Sjpk 	int		fd = -1;
1831676Sjpk 	int		fsize = 0;
1841676Sjpk 	time_t		newtime;
1851676Sjpk 	struct stat	f_stat;
1861676Sjpk 
1871676Sjpk 	if (flag & DA_FORCE)
1881676Sjpk 		*ftime = 0;
1891676Sjpk 
1901676Sjpk 	/* check the size and the time stamp on the file */
1911676Sjpk 	if (rw_rdlock(flock) != 0)
1921676Sjpk 		return (-1);
1931676Sjpk 	if (stat(fname, &f_stat) != 0) {
1941676Sjpk 		(void) rw_unlock(flock);
1951676Sjpk 		return (-1);
1961676Sjpk 	}
1971676Sjpk 	fsize = f_stat.st_size;
1981676Sjpk 	newtime = f_stat.st_mtime;
1991676Sjpk 	(void) rw_unlock(flock);
2001676Sjpk 
2011676Sjpk 	while (newtime > *ftime) {
2021676Sjpk 		/*
2031676Sjpk 		 * file has been modified since we last read it; or this
2041676Sjpk 		 * is a forced read.
2051676Sjpk 		 * read file into the buffer with rw lock.
2061676Sjpk 		 */
2071676Sjpk 		if (rw_wrlock(flock) != 0)
2081676Sjpk 			return (-1);
2091914Scasper 		if ((fd = open(fname, O_RDONLY)) == -1) {
2101676Sjpk 			(void) rw_unlock(flock);
2111676Sjpk 			return (-1);
2121676Sjpk 		}
2131676Sjpk 		if (*fbuf != NULL) {
2141676Sjpk 			free(*fbuf);
2151676Sjpk 			*fbuf = NULL;
2161676Sjpk 		}
2171676Sjpk 		if ((*fbuf = malloc(fsize)) == NULL) {
2181676Sjpk 			(void) rw_unlock(flock);
2191676Sjpk 			(void) close(fd);
2201676Sjpk 			return (-1);
2211676Sjpk 		}
2221676Sjpk 		if (read(fd, *fbuf, fsize) < fsize) {
2231676Sjpk 			free(*fbuf);
2241676Sjpk 			(void) rw_unlock(flock);
2251676Sjpk 			(void) close(fd);
2261676Sjpk 			return (-1);
2271676Sjpk 		}
2281676Sjpk 		(void) rw_unlock(flock);
2291676Sjpk 		/*
2301676Sjpk 		 * verify that the file did not change just after we read it.
2311676Sjpk 		 */
2321676Sjpk 		if (rw_rdlock(flock) != 0) {
2331676Sjpk 			free(*fbuf);
2341676Sjpk 			(void) close(fd);
2351676Sjpk 			return (-1);
2361676Sjpk 		}
2371676Sjpk 		if (stat(fname, &f_stat) != 0) {
2381676Sjpk 			free(*fbuf);
2391676Sjpk 			(void) rw_unlock(flock);
2401676Sjpk 			(void) close(fd);
2411676Sjpk 			return (-1);
2421676Sjpk 		}
2431676Sjpk 		fsize = f_stat.st_size;
2441676Sjpk 		newtime = f_stat.st_mtime;
2451676Sjpk 		(void) rw_unlock(flock);
2461676Sjpk 		(void) close(fd);
2471676Sjpk 		*ftime = newtime;
2481676Sjpk 	}
2491676Sjpk 
2501676Sjpk 	return (fsize);
2511676Sjpk }
2521676Sjpk 
2531676Sjpk /*
2541676Sjpk  * _update_zonename -
2551676Sjpk  *	add/remove current zone's name to the given devalloc_t.
2561676Sjpk  */
2571676Sjpk void
_update_zonename(da_args * dargs,devalloc_t * dap)2581676Sjpk _update_zonename(da_args *dargs, devalloc_t *dap)
2591676Sjpk {
2601676Sjpk 	int		i, j;
2611676Sjpk 	int		oldsize, newsize;
2621676Sjpk 	int		has_zonename = 0;
2631676Sjpk 	char		*zonename;
2641676Sjpk 	kva_t		*newkva, *oldkva;
2651676Sjpk 	kv_t		*newdata, *olddata;
2661676Sjpk 	devinfo_t	*devinfo;
2671676Sjpk 
2681676Sjpk 	devinfo = dargs->devinfo;
2691676Sjpk 	oldkva = dap->da_devopts;
2701676Sjpk 	if (oldkva == NULL) {
2711676Sjpk 		if (dargs->optflag & DA_REMOVE_ZONE)
2721676Sjpk 			return;
2731676Sjpk 		if (dargs->optflag & DA_ADD_ZONE) {
2741676Sjpk 			newkva = _str2kva(devinfo->devopts, KV_ASSIGN,
2751676Sjpk 			    KV_TOKEN_DELIMIT);
2761676Sjpk 			if (newkva != NULL)
2771676Sjpk 				dap->da_devopts = newkva;
2781676Sjpk 			return;
2791676Sjpk 		}
2801676Sjpk 	}
2811676Sjpk 	newsize = oldsize = oldkva->length;
2821676Sjpk 	if (kva_match(oldkva, DAOPT_ZONE))
2831676Sjpk 		has_zonename = 1;
2841676Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
2851676Sjpk 		if ((zonename = index(devinfo->devopts, '=')) == NULL)
2861676Sjpk 			return;
2871676Sjpk 		zonename++;
2881676Sjpk 		if (has_zonename) {
2891676Sjpk 			(void) _insert2kva(oldkva, DAOPT_ZONE, zonename);
2901676Sjpk 			return;
2911676Sjpk 		}
2921676Sjpk 		newsize += 1;
2931676Sjpk 	} else if (dargs->optflag & DA_REMOVE_ZONE) {
2941676Sjpk 		if (has_zonename) {
2951676Sjpk 			newsize -= 1;
2961676Sjpk 			if (newsize == 0) {
2971676Sjpk 				/*
2981676Sjpk 				 * If zone name was the only key/value pair,
2991676Sjpk 				 * put 'reserved' in the empty slot.
3001676Sjpk 				 */
3011676Sjpk 				_kva_free(oldkva);
3021676Sjpk 				dap->da_devopts = NULL;
3031676Sjpk 				return;
3041676Sjpk 			}
3051676Sjpk 		} else {
3061676Sjpk 			return;
3071676Sjpk 		}
3081676Sjpk 	}
3091676Sjpk 	newkva = _new_kva(newsize);
3101676Sjpk 	newkva->length = 0;
3111676Sjpk 	newdata = newkva->data;
3121676Sjpk 	olddata = oldkva->data;
3131676Sjpk 	for (i = 0, j = 0; i < oldsize; i++) {
3141676Sjpk 		if ((dargs->optflag & DA_REMOVE_ZONE) &&
3151676Sjpk 		    (strcmp(olddata[i].key, DAOPT_ZONE) == 0))
3161676Sjpk 			continue;
3171676Sjpk 		newdata[j].key = strdup(olddata[i].key);
3181676Sjpk 		newdata[j].value = strdup(olddata[i].value);
3191676Sjpk 		newkva->length++;
3201676Sjpk 		j++;
3211676Sjpk 	}
3221676Sjpk 	if (dargs->optflag & DA_ADD_ZONE) {
3231676Sjpk 		newdata[j].key = strdup(DAOPT_ZONE);
3241676Sjpk 		newdata[j].value = strdup(zonename);
3251676Sjpk 		newkva->length++;
3261676Sjpk 	}
3271676Sjpk 	_kva_free(oldkva);
3281676Sjpk 	dap->da_devopts = newkva;
3291676Sjpk }
3301676Sjpk 
3311676Sjpk /*
3321676Sjpk  * _dmap2str -
3331676Sjpk  *	converts a device_map entry into a printable string
3341676Sjpk  *	returns 0 on success, -1 on error.
3351676Sjpk  */
3361676Sjpk /*ARGSUSED*/
3371676Sjpk static int
_dmap2str(devmap_t * dmp,char * buf,int size,const char * sep)33811529SJan.Parcel@Sun.COM _dmap2str(devmap_t *dmp, char *buf, int size, const char *sep)
3391676Sjpk {
3401676Sjpk 	int	length;
3411676Sjpk 
3421676Sjpk 	length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep);
3431676Sjpk 	if (length >= size)
3441676Sjpk 		return (-1);
3451676Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
3461676Sjpk 	    dmp->dmap_devtype, sep);
3471676Sjpk 	if (length >= size)
3481676Sjpk 		return (-1);
3491676Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
3501676Sjpk 	    dmp->dmap_devlist);
3511676Sjpk 	if (length >= size)
3521676Sjpk 		return (-1);
3531676Sjpk 	return (0);
3541676Sjpk }
3551676Sjpk 
3561676Sjpk /*
3571676Sjpk  * _dmap2strentry -
3581676Sjpk  *	calls dmap2str to break given devmap_t into printable entry.
3591676Sjpk  *	returns pointer to decoded entry, NULL on error.
3601676Sjpk  */
3611676Sjpk static strentry_t *
_dmap2strentry(devmap_t * devmapp)36211529SJan.Parcel@Sun.COM _dmap2strentry(devmap_t *devmapp)
3631676Sjpk {
3641676Sjpk 	strentry_t	*sep;
3651676Sjpk 
3661676Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
3671676Sjpk 		return (NULL);
36811529SJan.Parcel@Sun.COM 	if (_dmap2str(devmapp, sep->se_str, sizeof (sep->se_str),
3691676Sjpk 	    KV_TOKEN_DELIMIT"\\\n\t") != 0) {
3701676Sjpk 		free(sep);
3711676Sjpk 		return (NULL);
3721676Sjpk 	}
3731676Sjpk 	return (sep);
3741676Sjpk }
3751676Sjpk 
3761676Sjpk /*
3771676Sjpk  * fix_optstr -
3781676Sjpk  * 	removes trailing ':' from buf.
3791676Sjpk  */
3801676Sjpk void
fix_optstr(char * buf)3811676Sjpk fix_optstr(char *buf)
3821676Sjpk {
3831676Sjpk 	char	*p = NULL;
3841676Sjpk 
3851676Sjpk 	if (p = rindex(buf, ':'))
3861676Sjpk 		*p = ';';
3871676Sjpk }
3881676Sjpk 
3891676Sjpk /*
3901676Sjpk  * _da2str -
3911676Sjpk  *	converts a device_allocate entry into a printable string
3921676Sjpk  *	returns 0 on success, -1 on error.
3931676Sjpk  */
3941676Sjpk static int
_da2str(da_args * dargs,devalloc_t * dap,char * buf,int size,const char * sep,const char * osep)3951676Sjpk _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep,
3961676Sjpk     const char *osep)
3971676Sjpk {
3981676Sjpk 	int	length;
3991676Sjpk 	int	matching_entry = 0;
4001676Sjpk 	char	**dnames;
4011676Sjpk 
4021676Sjpk 	if (dargs->optflag & DA_UPDATE &&
4031676Sjpk 	    (dargs->optflag & DA_ADD_ZONE ||
4041676Sjpk 	    dargs->optflag & DA_REMOVE_ZONE) &&
4051676Sjpk 	    dargs->devnames) {
4061676Sjpk 		for (dnames = dargs->devnames; *dnames != NULL; dnames++) {
4071676Sjpk 			if (da_matchname(dap, *dnames)) {
4081676Sjpk 				matching_entry = 1;
4091676Sjpk 				break;
4101676Sjpk 			}
4111676Sjpk 		}
4121676Sjpk 	}
4131676Sjpk 	length = snprintf(buf, size, "%s%s", dap->da_devname, sep);
4141676Sjpk 	if (length >= size)
4151676Sjpk 		return (-1);
4161676Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
4171676Sjpk 	    dap->da_devtype, sep);
4181676Sjpk 	if (length >= size)
4191676Sjpk 		return (-1);
4201676Sjpk 	if (matching_entry)
4211676Sjpk 		_update_zonename(dargs, dap);
4221676Sjpk 	if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) &&
4231676Sjpk 	    (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) {
4241676Sjpk 		length += snprintf(buf + length, size - length, "%s%s",
4251676Sjpk 		    DA_RESERVED, sep);
4261676Sjpk 	} else {
4271676Sjpk 		if (_kva2str(dap->da_devopts, buf + length, size - length,
4281676Sjpk 		    KV_ASSIGN, (char *)osep) != 0)
4291676Sjpk 			return (-1);
4301676Sjpk 		length = strlen(buf);
4311676Sjpk 	}
4321676Sjpk 	if (dap->da_devopts)
4331676Sjpk 		fix_optstr(buf);
4341676Sjpk 	if (length >= size)
4351676Sjpk 		return (-1);
4361676Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
4371676Sjpk 	    DA_RESERVED, sep);
4381676Sjpk 	if (length >= size)
4391676Sjpk 		return (-1);
4401676Sjpk 	length += snprintf(buf + length, size - length, "%s%s",
4411676Sjpk 	    dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep);
4421676Sjpk 	if (length >= size)
4431676Sjpk 		return (-1);
4441676Sjpk 	length += snprintf(buf + length, size - length, "%s\n",
4451676Sjpk 	    dap->da_devexec ? dap->da_devexec : "");
4461676Sjpk 	if (length >= size)
4471676Sjpk 		return (-1);
4481676Sjpk 
4491676Sjpk 	return (0);
4501676Sjpk }
4511676Sjpk 
4521676Sjpk /*
4531676Sjpk  * _da2strentry -
4541676Sjpk  *	calls da2str to break given devalloc_t into printable entry.
4551676Sjpk  *	returns pointer to decoded entry, NULL on error.
4561676Sjpk  */
4571676Sjpk static strentry_t *
_da2strentry(da_args * dargs,devalloc_t * dap)4581676Sjpk _da2strentry(da_args *dargs, devalloc_t *dap)
4591676Sjpk {
4601676Sjpk 	strentry_t	*sep;
4611676Sjpk 
4621676Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
4631676Sjpk 		return (NULL);
4641676Sjpk 	if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str),
4651676Sjpk 	    KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) {
4661676Sjpk 		free(sep);
4671676Sjpk 		return (NULL);
4681676Sjpk 	}
4691676Sjpk 	return (sep);
4701676Sjpk }
4711676Sjpk 
4721676Sjpk /*
4731676Sjpk  * _def2str
4741676Sjpk  *	converts da_defs_t into a printable string.
4751676Sjpk  *	returns 0 on success, -1 on error.
4761676Sjpk  */
4771676Sjpk static int
_def2str(da_defs_t * da_defs,char * buf,int size,const char * sep)4781676Sjpk _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep)
4791676Sjpk {
4801676Sjpk 	int length;
4811676Sjpk 
4821676Sjpk 	length = snprintf(buf, size, "%s%s", da_defs->devtype, sep);
4831676Sjpk 	if (length >= size)
4841676Sjpk 		return (-1);
4851676Sjpk 	if (da_defs->devopts) {
4861676Sjpk 		if (_kva2str(da_defs->devopts, buf + length, size - length,
4871676Sjpk 		    KV_ASSIGN, KV_DELIMITER) != 0)
4881676Sjpk 			return (-1);
4891676Sjpk 		length = strlen(buf);
4901676Sjpk 	}
4911676Sjpk 	if (length >= size)
4921676Sjpk 		return (-1);
4931676Sjpk 
4941676Sjpk 	return (0);
4951676Sjpk }
4961676Sjpk 
4971676Sjpk /*
4981676Sjpk  * _def2strentry
4991676Sjpk  *	calls _def2str to break given da_defs_t into printable entry.
5001676Sjpk  *	returns pointer decoded entry, NULL on error.
5011676Sjpk  */
5021676Sjpk static strentry_t *
_def2strentry(da_defs_t * da_defs)5031676Sjpk _def2strentry(da_defs_t *da_defs)
5041676Sjpk {
5051676Sjpk 	strentry_t	*sep;
5061676Sjpk 
5071676Sjpk 	if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
5081676Sjpk 		return (NULL);
5091676Sjpk 	if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str),
5101676Sjpk 	    KV_TOKEN_DELIMIT) != 0) {
5111676Sjpk 		free(sep);
5121676Sjpk 		return (NULL);
5131676Sjpk 	}
5141676Sjpk 
5151676Sjpk 	return (sep);
5161676Sjpk }
5171676Sjpk 
5181676Sjpk /*
5191676Sjpk  * _build_defattrs
5201676Sjpk  *	cycles through all defattr entries, stores them in memory. removes
5211676Sjpk  *	entries with the given search_key (device type).
5221676Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
5231676Sjpk  *	error.
5241676Sjpk  */
5251676Sjpk static int
_build_defattrs(da_args * dargs,strentry_t ** head_defent)5261676Sjpk _build_defattrs(da_args *dargs, strentry_t **head_defent)
5271676Sjpk {
5281676Sjpk 	int		rc = 0;
5291676Sjpk 	da_defs_t	*da_defs;
5301676Sjpk 	strentry_t	*tail_str, *tmp_str;
5311676Sjpk 
5321676Sjpk 	setdadefent();
5331676Sjpk 	while ((da_defs = getdadefent()) != NULL) {
5341676Sjpk 		rc = !(strcmp(da_defs->devtype, dargs->devinfo->devtype));
5351676Sjpk 		if (rc && dargs->optflag & DA_ADD &&
5361676Sjpk 		    !(dargs->optflag & DA_FORCE)) {
5371676Sjpk 			/*
5381676Sjpk 			 * During DA_ADD, we keep an existing entry unless
5391676Sjpk 			 * we have DA_FORCE set to override that entry.
5401676Sjpk 			 */
5411676Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
5421676Sjpk 			rc = 0;
5431676Sjpk 		}
5441676Sjpk 		if (rc == 0) {
5451676Sjpk 			tmp_str = _def2strentry(da_defs);
5461676Sjpk 			if (tmp_str == NULL) {
5471676Sjpk 				freedadefent(da_defs);
5481676Sjpk 				enddadefent();
5491676Sjpk 				return (2);
5501676Sjpk 			}
5511676Sjpk 			/* retaining defattr entry: tmp_str->se_str */
5521676Sjpk 			tmp_str->se_next = NULL;
5531676Sjpk 			if (*head_defent == NULL) {
5541676Sjpk 				*head_defent = tail_str = tmp_str;
5551676Sjpk 			} else {
5561676Sjpk 				tail_str->se_next = tmp_str;
5571676Sjpk 				tail_str = tmp_str;
5581676Sjpk 			}
5591676Sjpk 		}
5601676Sjpk 		freedadefent(da_defs);
5611676Sjpk 	}
5621676Sjpk 	enddadefent();
5631676Sjpk 
5641676Sjpk 	return (rc);
5651676Sjpk }
5661676Sjpk 
5671676Sjpk /*
568*12373SJan.Parcel@Sun.COM  * We have to handle the "standard" types in devlist differently than
569*12373SJan.Parcel@Sun.COM  * other devices, which are not covered by our auto-naming conventions.
570*12373SJan.Parcel@Sun.COM  *
571*12373SJan.Parcel@Sun.COM  * buf must be a buffer of size DA_MAX_NAME + 1
572*12373SJan.Parcel@Sun.COM  */
573*12373SJan.Parcel@Sun.COM int
da_std_type(da_args * dargs,char * namebuf)574*12373SJan.Parcel@Sun.COM da_std_type(da_args *dargs, char *namebuf)
575*12373SJan.Parcel@Sun.COM {
576*12373SJan.Parcel@Sun.COM 	char *type = dargs->devinfo->devtype;
577*12373SJan.Parcel@Sun.COM 	int system_labeled;
578*12373SJan.Parcel@Sun.COM 
579*12373SJan.Parcel@Sun.COM 	system_labeled = is_system_labeled();
580*12373SJan.Parcel@Sun.COM 
581*12373SJan.Parcel@Sun.COM 	/* check safely for sizes */
582*12373SJan.Parcel@Sun.COM 	if (strcmp(DA_AUDIO_TYPE, type) == 0) {
583*12373SJan.Parcel@Sun.COM 		(void) strlcpy(namebuf, DA_AUDIO_NAME, DA_MAXNAME);
584*12373SJan.Parcel@Sun.COM 		return (1);
585*12373SJan.Parcel@Sun.COM 	}
586*12373SJan.Parcel@Sun.COM 	if (strcmp(DA_CD_TYPE, type) == 0) {
587*12373SJan.Parcel@Sun.COM 		if (system_labeled)
588*12373SJan.Parcel@Sun.COM 			(void) strlcpy(namebuf, DA_CD_NAME, DA_MAXNAME);
589*12373SJan.Parcel@Sun.COM 		else
590*12373SJan.Parcel@Sun.COM 			(void) strlcpy(namebuf, DA_CD_TYPE, DA_MAXNAME);
591*12373SJan.Parcel@Sun.COM 		return (1);
592*12373SJan.Parcel@Sun.COM 	}
593*12373SJan.Parcel@Sun.COM 	if (strcmp(DA_FLOPPY_TYPE, type) == 0) {
594*12373SJan.Parcel@Sun.COM 		if (system_labeled)
595*12373SJan.Parcel@Sun.COM 			(void) strlcpy(namebuf, DA_FLOPPY_NAME, DA_MAXNAME);
596*12373SJan.Parcel@Sun.COM 		else
597*12373SJan.Parcel@Sun.COM 			(void) strlcpy(namebuf, DA_FLOPPY_TYPE, DA_MAXNAME);
598*12373SJan.Parcel@Sun.COM 		return (1);
599*12373SJan.Parcel@Sun.COM 	}
600*12373SJan.Parcel@Sun.COM 	if (strcmp(DA_TAPE_TYPE, type) == 0) {
601*12373SJan.Parcel@Sun.COM 		if (system_labeled)
602*12373SJan.Parcel@Sun.COM 			(void) strlcpy(namebuf, DA_TAPE_NAME, DA_MAXNAME);
603*12373SJan.Parcel@Sun.COM 		else
604*12373SJan.Parcel@Sun.COM 			(void) strlcpy(namebuf, DA_TAPE_TYPE, DA_MAXNAME);
605*12373SJan.Parcel@Sun.COM 		return (1);
606*12373SJan.Parcel@Sun.COM 	}
607*12373SJan.Parcel@Sun.COM 	if (strcmp(DA_RMDISK_TYPE, type) == 0) {
608*12373SJan.Parcel@Sun.COM 		(void) strlcpy(namebuf, DA_RMDISK_NAME, DA_MAXNAME);
609*12373SJan.Parcel@Sun.COM 		return (1);
610*12373SJan.Parcel@Sun.COM 	}
611*12373SJan.Parcel@Sun.COM 	namebuf[0] = '\0';
612*12373SJan.Parcel@Sun.COM 	return (0);
613*12373SJan.Parcel@Sun.COM }
614*12373SJan.Parcel@Sun.COM 
615*12373SJan.Parcel@Sun.COM /*
616*12373SJan.Parcel@Sun.COM  * allocatable: returns
617*12373SJan.Parcel@Sun.COM  * -1 if no auths field,
618*12373SJan.Parcel@Sun.COM  * 0 if not allocatable (marked '*')
619*12373SJan.Parcel@Sun.COM  * 1 if not marked '*'
620*12373SJan.Parcel@Sun.COM  */
621*12373SJan.Parcel@Sun.COM static int
allocatable(da_args * dargs)622*12373SJan.Parcel@Sun.COM allocatable(da_args *dargs)
623*12373SJan.Parcel@Sun.COM {
624*12373SJan.Parcel@Sun.COM 
625*12373SJan.Parcel@Sun.COM 	if (!dargs->devinfo->devauths)
626*12373SJan.Parcel@Sun.COM 		return (-1);
627*12373SJan.Parcel@Sun.COM 	if (strcmp("*", dargs->devinfo->devauths) == 0)
628*12373SJan.Parcel@Sun.COM 		return (0);
629*12373SJan.Parcel@Sun.COM 	return (1);
630*12373SJan.Parcel@Sun.COM }
631*12373SJan.Parcel@Sun.COM 
632*12373SJan.Parcel@Sun.COM /*
63311529SJan.Parcel@Sun.COM  * _rebuild_lists -
63411529SJan.Parcel@Sun.COM  *
635*12373SJan.Parcel@Sun.COM  *	If dargs->optflag & DA_EVENT, does not assume the dargs list is
636*12373SJan.Parcel@Sun.COM  *	complete or completely believable, since devfsadm caches
637*12373SJan.Parcel@Sun.COM  *	ONLY what it has been exposed to via syseventd.
63811529SJan.Parcel@Sun.COM  *
63911529SJan.Parcel@Sun.COM  *	Cycles through all the entries in the /etc files, stores them
640*12373SJan.Parcel@Sun.COM  *	in memory, takes note of device->dname numbers (e.g. rmdisk0,
641*12373SJan.Parcel@Sun.COM  *	rmdisk12)
64211529SJan.Parcel@Sun.COM  *
643*12373SJan.Parcel@Sun.COM  *	Cycles through again, adds dargs entry
64411529SJan.Parcel@Sun.COM  *	with the name tname%d (lowest unused number for the device type)
64511529SJan.Parcel@Sun.COM  *	to the list of things for the caller to write out to a file,
646*12373SJan.Parcel@Sun.COM  *	IFF it is a new entry.
64711529SJan.Parcel@Sun.COM  *
648*12373SJan.Parcel@Sun.COM  *	It is an error for it to already be there, if it is allocatable.
64911529SJan.Parcel@Sun.COM  *
65011529SJan.Parcel@Sun.COM  *	Add:
651*12373SJan.Parcel@Sun.COM  *	    Returns 0 if successful and 2 on error.
652*12373SJan.Parcel@Sun.COM  *	Remove:
653*12373SJan.Parcel@Sun.COM  *	    Returns 0 if not found, 1 if found,  2 on error.
65411529SJan.Parcel@Sun.COM  */
65511529SJan.Parcel@Sun.COM static int
_rebuild_lists(da_args * dargs,strentry_t ** head_devallocp,strentry_t ** head_devmapp)65611529SJan.Parcel@Sun.COM _rebuild_lists(da_args *dargs, strentry_t **head_devallocp,
65711529SJan.Parcel@Sun.COM     strentry_t **head_devmapp)
65811529SJan.Parcel@Sun.COM {
65911529SJan.Parcel@Sun.COM 	int		rc = 0;
66011529SJan.Parcel@Sun.COM 	devalloc_t	*devallocp;
66111529SJan.Parcel@Sun.COM 	devmap_t	*devmapp;
66211529SJan.Parcel@Sun.COM 	strentry_t	*tail_str;
66311529SJan.Parcel@Sun.COM 	strentry_t	*tmp_str;
66411529SJan.Parcel@Sun.COM 	uint64_t	tmp_bitmap = 0;
665*12373SJan.Parcel@Sun.COM 	uint_t		tmp = 0;
666*12373SJan.Parcel@Sun.COM 	char		*realname;
667*12373SJan.Parcel@Sun.COM 	int		suffix;
668*12373SJan.Parcel@Sun.COM 	int		found = 0;
669*12373SJan.Parcel@Sun.COM 	int		stdtype = 1;
670*12373SJan.Parcel@Sun.COM 	int		is_allocatable = 1;
67111529SJan.Parcel@Sun.COM 	char		new_devname[DA_MAXNAME + 1];
672*12373SJan.Parcel@Sun.COM 	char		defname[DA_MAXNAME + 1]; /* default name for type */
67311529SJan.Parcel@Sun.COM 	char		errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80];
67411529SJan.Parcel@Sun.COM 
67511529SJan.Parcel@Sun.COM 	if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY))
67611529SJan.Parcel@Sun.COM 		return (2);
67711529SJan.Parcel@Sun.COM 
67811529SJan.Parcel@Sun.COM 	if (dargs->optflag & DA_FORCE)
67911529SJan.Parcel@Sun.COM 		return (2);
68011529SJan.Parcel@Sun.COM 
681*12373SJan.Parcel@Sun.COM 	if (dargs->optflag & DA_ADD) {
682*12373SJan.Parcel@Sun.COM 		stdtype = da_std_type(dargs, defname);
683*12373SJan.Parcel@Sun.COM 		is_allocatable = allocatable(dargs);
684*12373SJan.Parcel@Sun.COM 	}
685*12373SJan.Parcel@Sun.COM 
68611529SJan.Parcel@Sun.COM 	/* read both files, maps first so we can compare actual devices */
68711529SJan.Parcel@Sun.COM 
68811529SJan.Parcel@Sun.COM 	/* build device_maps */
68911529SJan.Parcel@Sun.COM 	setdmapent();
69011529SJan.Parcel@Sun.COM 	while ((devmapp = getdmapent()) != NULL) {
691*12373SJan.Parcel@Sun.COM 		suffix = DA_MAX_DEVNO + 1;
69211529SJan.Parcel@Sun.COM 		if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype))
69311529SJan.Parcel@Sun.COM 		    == 1) {
69411529SJan.Parcel@Sun.COM 			if (dargs->optflag & DA_REMOVE) {
69511529SJan.Parcel@Sun.COM 				if ((devmapp->dmap_devarray == NULL) ||
69611529SJan.Parcel@Sun.COM 				    (devmapp->dmap_devarray[0] == NULL)) {
69711529SJan.Parcel@Sun.COM 					freedmapent(devmapp);
69811529SJan.Parcel@Sun.COM 					enddmapent();
69911529SJan.Parcel@Sun.COM 					return (2);
70011529SJan.Parcel@Sun.COM 				}
70111529SJan.Parcel@Sun.COM 				realname = dmap_physname(devmapp);
70211529SJan.Parcel@Sun.COM 				if (realname == NULL) {
70311529SJan.Parcel@Sun.COM 					freedmapent(devmapp);
70411529SJan.Parcel@Sun.COM 					enddmapent();
70511529SJan.Parcel@Sun.COM 					return (2);
70611529SJan.Parcel@Sun.COM 				}
70711529SJan.Parcel@Sun.COM 				if (strstr(realname, dargs->devinfo->devlist)
70811529SJan.Parcel@Sun.COM 				    != NULL) {
709*12373SJan.Parcel@Sun.COM 					/* if need to free and safe to free */
710*12373SJan.Parcel@Sun.COM 					if (dargs->devinfo->devname != NULL &&
711*12373SJan.Parcel@Sun.COM 					    (dargs->optflag & DA_EVENT) != 0)
71211529SJan.Parcel@Sun.COM 						free(dargs->devinfo->devname);
71311529SJan.Parcel@Sun.COM 					dargs->devinfo->devname =
71411529SJan.Parcel@Sun.COM 					    strdup(devmapp->dmap_devname);
71511529SJan.Parcel@Sun.COM 					found = 1;
71611529SJan.Parcel@Sun.COM 					freedmapent(devmapp);
71711529SJan.Parcel@Sun.COM 					continue; /* don't retain */
71811529SJan.Parcel@Sun.COM 				}
71911529SJan.Parcel@Sun.COM 			} else if (dargs->optflag & DA_ADD) {
72011529SJan.Parcel@Sun.COM 				/*
72111529SJan.Parcel@Sun.COM 				 * Need to know which suffixes are in use
72211529SJan.Parcel@Sun.COM 				 */
72311529SJan.Parcel@Sun.COM 				rc = (dmap_exact_dev(devmapp,
72411529SJan.Parcel@Sun.COM 				    dargs->devinfo->devlist, &suffix));
72511529SJan.Parcel@Sun.COM 
72611529SJan.Parcel@Sun.COM 				if (rc == 0) {
72711529SJan.Parcel@Sun.COM 					/*
72811529SJan.Parcel@Sun.COM 					 * Same type, different device.  Record
729*12373SJan.Parcel@Sun.COM 					 * device suffix already in use, if
730*12373SJan.Parcel@Sun.COM 					 * applicable.
73111529SJan.Parcel@Sun.COM 					 */
732*12373SJan.Parcel@Sun.COM 					if ((suffix < DA_MAX_DEVNO &&
733*12373SJan.Parcel@Sun.COM 					    suffix != -1) && stdtype)
734*12373SJan.Parcel@Sun.COM 						tmp_bitmap |=
735*12373SJan.Parcel@Sun.COM 						    (uint64_t)(1LL << suffix);
736*12373SJan.Parcel@Sun.COM 				} else if ((rc == 1) && !is_allocatable) {
737*12373SJan.Parcel@Sun.COM 					rc = 0;
73811529SJan.Parcel@Sun.COM 				} else {
73911529SJan.Parcel@Sun.COM 					/*
740*12373SJan.Parcel@Sun.COM 					 * Match allocatable on add is an error
74111529SJan.Parcel@Sun.COM 					 * or mapping attempt returned error
74211529SJan.Parcel@Sun.COM 					 */
743*12373SJan.Parcel@Sun.COM 					(void) snprintf(errmsg, sizeof (errmsg),
744*12373SJan.Parcel@Sun.COM 					    "Cannot add %s on node %s",
745*12373SJan.Parcel@Sun.COM 					    dargs->devinfo->devtype,
746*12373SJan.Parcel@Sun.COM 					    devmapp->dmap_devname);
747*12373SJan.Parcel@Sun.COM 					syslog(LOG_ERR, "%s", errmsg);
74811529SJan.Parcel@Sun.COM 					freedmapent(devmapp);
74911529SJan.Parcel@Sun.COM 					enddmapent();
75011529SJan.Parcel@Sun.COM 					return (2);
75111529SJan.Parcel@Sun.COM 				}
75211529SJan.Parcel@Sun.COM 			} else
75311529SJan.Parcel@Sun.COM 				/* add other transaction types as needed */
75411529SJan.Parcel@Sun.COM 				return (2);
755*12373SJan.Parcel@Sun.COM 		} else if ((dargs->optflag & DA_ADD) &&
756*12373SJan.Parcel@Sun.COM 		    (stdtype || is_allocatable) &&
757*12373SJan.Parcel@Sun.COM 		    dmap_exact_dev(devmapp, dargs->devinfo->devlist,
758*12373SJan.Parcel@Sun.COM 		    &suffix)) {
759*12373SJan.Parcel@Sun.COM 			/*
760*12373SJan.Parcel@Sun.COM 			 * no dups w/o DA_FORCE, even if type differs,
761*12373SJan.Parcel@Sun.COM 			 * if there is a chance this operation is
762*12373SJan.Parcel@Sun.COM 			 * machine-driven.  The 5 "standard types"
763*12373SJan.Parcel@Sun.COM 			 * can be machine-driven adds, and tend to
764*12373SJan.Parcel@Sun.COM 			 * be allocatable.
765*12373SJan.Parcel@Sun.COM 			 */
766*12373SJan.Parcel@Sun.COM 			(void) snprintf(errmsg, sizeof (errmsg),
767*12373SJan.Parcel@Sun.COM 			    "Cannot add %s on node %s type %s",
768*12373SJan.Parcel@Sun.COM 			    dargs->devinfo->devtype,
769*12373SJan.Parcel@Sun.COM 			    devmapp->dmap_devname,
770*12373SJan.Parcel@Sun.COM 			    devmapp->dmap_devtype);
771*12373SJan.Parcel@Sun.COM 			syslog(LOG_ERR, "%s", errmsg);
772*12373SJan.Parcel@Sun.COM 			freedmapent(devmapp);
773*12373SJan.Parcel@Sun.COM 			enddmapent();
774*12373SJan.Parcel@Sun.COM 			return (2);
775*12373SJan.Parcel@Sun.COM 		}
77611529SJan.Parcel@Sun.COM 
77711529SJan.Parcel@Sun.COM 		tmp_str = _dmap2strentry(devmapp);
77811529SJan.Parcel@Sun.COM 		if (tmp_str == NULL) {
77911529SJan.Parcel@Sun.COM 			freedmapent(devmapp);
78011529SJan.Parcel@Sun.COM 			enddmapent();
78111529SJan.Parcel@Sun.COM 			return (2);
78211529SJan.Parcel@Sun.COM 		}
78311529SJan.Parcel@Sun.COM 		/* retaining devmap entry: tmp_str->se_str */
78411529SJan.Parcel@Sun.COM 		tmp_str->se_next = NULL;
78511529SJan.Parcel@Sun.COM 		if (*head_devmapp == NULL) {
78611529SJan.Parcel@Sun.COM 			*head_devmapp = tail_str = tmp_str;
78711529SJan.Parcel@Sun.COM 		} else {
78811529SJan.Parcel@Sun.COM 			tail_str->se_next = tmp_str;
78911529SJan.Parcel@Sun.COM 			tail_str = tmp_str;
79011529SJan.Parcel@Sun.COM 		}
79111529SJan.Parcel@Sun.COM 		freedmapent(devmapp);
79211529SJan.Parcel@Sun.COM 	}
79311529SJan.Parcel@Sun.COM 	enddmapent();
79411529SJan.Parcel@Sun.COM 
79511529SJan.Parcel@Sun.COM 	/*
79611529SJan.Parcel@Sun.COM 	 * No need to rewrite the files if the item to be removed is not
79711529SJan.Parcel@Sun.COM 	 * in the files -- wait for another call on another darg.
79811529SJan.Parcel@Sun.COM 	 */
79911529SJan.Parcel@Sun.COM 	if ((dargs->optflag & DA_REMOVE) && !found)
80011529SJan.Parcel@Sun.COM 		return (0);
80111529SJan.Parcel@Sun.COM 
80211529SJan.Parcel@Sun.COM 
80311529SJan.Parcel@Sun.COM 	if (dargs->optflag & DA_ADD) {
804*12373SJan.Parcel@Sun.COM 		int len;
80511529SJan.Parcel@Sun.COM 		/*
806*12373SJan.Parcel@Sun.COM 		 * If we got here from an event, or from devfsadm,
807*12373SJan.Parcel@Sun.COM 		 * we know the stored devname is a useless guess,
808*12373SJan.Parcel@Sun.COM 		 * since the files had not been read when the name
809*12373SJan.Parcel@Sun.COM 		 * was chosen, and we don't keep them anywhere else
810*12373SJan.Parcel@Sun.COM 		 * that is sufficiently definitive.
81111529SJan.Parcel@Sun.COM 		 */
81211529SJan.Parcel@Sun.COM 
81311529SJan.Parcel@Sun.COM 		for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++)
81411529SJan.Parcel@Sun.COM 			if (!(tmp_bitmap & (1LL << tmp)))
81511529SJan.Parcel@Sun.COM 				break;
81611529SJan.Parcel@Sun.COM 		/* Future: support more than 64 hotplug devices per type? */
81711529SJan.Parcel@Sun.COM 		if (tmp > DA_MAX_DEVNO)
81811529SJan.Parcel@Sun.COM 			return (2);
81911529SJan.Parcel@Sun.COM 
820*12373SJan.Parcel@Sun.COM 		/*
821*12373SJan.Parcel@Sun.COM 		 * Let the caller choose the name unless BOTH the name and
822*12373SJan.Parcel@Sun.COM 		 * device type one of: cdrom, floppy, audio, rmdisk, or tape.
823*12373SJan.Parcel@Sun.COM 		 * (or sr, fd for unlabeled)
824*12373SJan.Parcel@Sun.COM 		 */
825*12373SJan.Parcel@Sun.COM 		len = strlen(defname);
826*12373SJan.Parcel@Sun.COM 		if (stdtype &&
827*12373SJan.Parcel@Sun.COM 		    (strncmp(dargs->devinfo->devname, defname, len) == 0)) {
828*12373SJan.Parcel@Sun.COM 			(void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u",
829*12373SJan.Parcel@Sun.COM 			    defname, tmp);
830*12373SJan.Parcel@Sun.COM 			/* if need to free and safe to free */
831*12373SJan.Parcel@Sun.COM 			if (dargs->devinfo->devname != NULL &&
832*12373SJan.Parcel@Sun.COM 			    (dargs->optflag & DA_EVENT) != 0)
833*12373SJan.Parcel@Sun.COM 				free(dargs->devinfo->devname);
834*12373SJan.Parcel@Sun.COM 			dargs->devinfo->devname = strdup(new_devname);
835*12373SJan.Parcel@Sun.COM 		}
83611529SJan.Parcel@Sun.COM 	}
83711529SJan.Parcel@Sun.COM 
83811529SJan.Parcel@Sun.COM 	/*
83911529SJan.Parcel@Sun.COM 	 * Now adjust devalloc list to match devmaps
84011529SJan.Parcel@Sun.COM 	 * Note we now have the correct devname for da_match to use.
84111529SJan.Parcel@Sun.COM 	 */
84211529SJan.Parcel@Sun.COM 	setdaent();
84311529SJan.Parcel@Sun.COM 	while ((devallocp = getdaent()) != NULL) {
84411529SJan.Parcel@Sun.COM 		rc = da_match(devallocp, dargs);
84511529SJan.Parcel@Sun.COM 		if (rc == 1) {
84611529SJan.Parcel@Sun.COM 			if (dargs->optflag & DA_ADD) {
84711529SJan.Parcel@Sun.COM 				/* logging is on if DA_EVENT is set */
84811529SJan.Parcel@Sun.COM 				if (dargs->optflag & DA_EVENT) {
84911529SJan.Parcel@Sun.COM 					(void) snprintf(errmsg, sizeof (errmsg),
85011529SJan.Parcel@Sun.COM 					    "%s and %s out of sync,"
85111529SJan.Parcel@Sun.COM 					    "%s only in %s.",
85211529SJan.Parcel@Sun.COM 					    DEVALLOC, DEVMAP,
85311529SJan.Parcel@Sun.COM 					    devallocp->da_devname, DEVALLOC);
85411529SJan.Parcel@Sun.COM 					syslog(LOG_ERR, "%s", errmsg);
85511529SJan.Parcel@Sun.COM 				}
85611529SJan.Parcel@Sun.COM 				freedaent(devallocp);
85711529SJan.Parcel@Sun.COM 				enddaent();
85811529SJan.Parcel@Sun.COM 				return (2);
85911529SJan.Parcel@Sun.COM 			} else if (dargs->optflag & DA_REMOVE) {
86011529SJan.Parcel@Sun.COM 				/* make list w/o this entry */
86111529SJan.Parcel@Sun.COM 				freedaent(devallocp);
86211529SJan.Parcel@Sun.COM 				continue;
86311529SJan.Parcel@Sun.COM 			}
86411529SJan.Parcel@Sun.COM 		}
86511529SJan.Parcel@Sun.COM 		tmp_str = _da2strentry(dargs, devallocp);
86611529SJan.Parcel@Sun.COM 		if (tmp_str == NULL) {
86711529SJan.Parcel@Sun.COM 			freedaent(devallocp);
86811529SJan.Parcel@Sun.COM 			enddaent();
86911529SJan.Parcel@Sun.COM 			return (2);
87011529SJan.Parcel@Sun.COM 		}
87111529SJan.Parcel@Sun.COM 		/* retaining devalloc entry: tmp_str->se_str */
87211529SJan.Parcel@Sun.COM 		tmp_str->se_next = NULL;
87311529SJan.Parcel@Sun.COM 		if (*head_devallocp == NULL) {
87411529SJan.Parcel@Sun.COM 			*head_devallocp = tail_str = tmp_str;
87511529SJan.Parcel@Sun.COM 		} else {
87611529SJan.Parcel@Sun.COM 			tail_str->se_next = tmp_str;
87711529SJan.Parcel@Sun.COM 			tail_str = tmp_str;
87811529SJan.Parcel@Sun.COM 		}
87911529SJan.Parcel@Sun.COM 		freedaent(devallocp);
88011529SJan.Parcel@Sun.COM 	}
88111529SJan.Parcel@Sun.COM 	enddaent();
88211529SJan.Parcel@Sun.COM 
88311529SJan.Parcel@Sun.COM 	/* the caller needs to know if a remove needs to rewrite files */
88411529SJan.Parcel@Sun.COM 	if (dargs->optflag & DA_REMOVE)
88511529SJan.Parcel@Sun.COM 		return (1);  /* 0 and 2 cases returned earlier */
88611529SJan.Parcel@Sun.COM 
88711529SJan.Parcel@Sun.COM 	return (0);  /* Successful DA_ADD */
88811529SJan.Parcel@Sun.COM }
889*12373SJan.Parcel@Sun.COM 
89011529SJan.Parcel@Sun.COM /*
8911676Sjpk  * _build_lists -
89211529SJan.Parcel@Sun.COM  *	Cycles through all the entries, stores them in memory. removes entries
8931676Sjpk  *	with the given search_key (device name or type).
8941676Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
8951676Sjpk  *	error.
8961676Sjpk  */
8971676Sjpk static int
_build_lists(da_args * dargs,strentry_t ** head_devallocp,strentry_t ** head_devmapp)8981676Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp,
8991676Sjpk     strentry_t **head_devmapp)
9001676Sjpk {
9011676Sjpk 	int		rc = 0;
902*12373SJan.Parcel@Sun.COM 	int		found = 0;
9031676Sjpk 	devalloc_t	*devallocp;
9041676Sjpk 	devmap_t	*devmapp;
9051676Sjpk 	strentry_t	*tail_str;
9061676Sjpk 	strentry_t	*tmp_str;
9071676Sjpk 
9081676Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
9091676Sjpk 		goto dmap_only;
9101676Sjpk 
9111676Sjpk 	/* build device_allocate */
9121676Sjpk 	setdaent();
9131676Sjpk 	while ((devallocp = getdaent()) != NULL) {
9141676Sjpk 		rc = da_match(devallocp, dargs);
915*12373SJan.Parcel@Sun.COM 		/* if in _build_lists and DA_ADD is set, so is DA_FORCE */
9161676Sjpk 		if (rc == 0) {
9171676Sjpk 			tmp_str = _da2strentry(dargs, devallocp);
9181676Sjpk 			if (tmp_str == NULL) {
9191676Sjpk 				freedaent(devallocp);
9201676Sjpk 				enddaent();
9211676Sjpk 				return (2);
9221676Sjpk 			}
9231676Sjpk 			/* retaining devalloc entry: tmp_str->se_str */
9241676Sjpk 			tmp_str->se_next = NULL;
9251676Sjpk 			if (*head_devallocp == NULL) {
9261676Sjpk 				*head_devallocp = tail_str = tmp_str;
9271676Sjpk 			} else {
9281676Sjpk 				tail_str->se_next = tmp_str;
9291676Sjpk 				tail_str = tmp_str;
9301676Sjpk 			}
931*12373SJan.Parcel@Sun.COM 		} else if (rc == 1)
932*12373SJan.Parcel@Sun.COM 			found = 1;
933*12373SJan.Parcel@Sun.COM 
9341676Sjpk 		freedaent(devallocp);
9351676Sjpk 	}
9361676Sjpk 	enddaent();
9371676Sjpk 
9381676Sjpk dmap_only:
9391676Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
9401676Sjpk 		return (rc);
9411676Sjpk 
9421676Sjpk 	/* build device_maps */
9431676Sjpk 	rc = 0;
9441676Sjpk 	setdmapent();
9451676Sjpk 	while ((devmapp = getdmapent()) != NULL) {
9461676Sjpk 		rc = dm_match(devmapp, dargs);
9471676Sjpk 		if (rc == 0) {
94811529SJan.Parcel@Sun.COM 			tmp_str = _dmap2strentry(devmapp);
9491676Sjpk 			if (tmp_str == NULL) {
9501676Sjpk 				freedmapent(devmapp);
9511676Sjpk 				enddmapent();
9521676Sjpk 				return (2);
9531676Sjpk 			}
9541676Sjpk 			/* retaining devmap entry: tmp_str->se_str */
9551676Sjpk 			tmp_str->se_next = NULL;
9561676Sjpk 			if (*head_devmapp == NULL) {
9571676Sjpk 				*head_devmapp = tail_str = tmp_str;
9581676Sjpk 			} else {
9591676Sjpk 				tail_str->se_next = tmp_str;
9601676Sjpk 				tail_str = tmp_str;
9611676Sjpk 			}
9621676Sjpk 		}
9631676Sjpk 		freedmapent(devmapp);
9641676Sjpk 	}
9651676Sjpk 	enddmapent();
9661676Sjpk 
967*12373SJan.Parcel@Sun.COM 	/* later code cleanup may cause the use of "found" in other cases */
968*12373SJan.Parcel@Sun.COM 	if (dargs->optflag & DA_REMOVE)
969*12373SJan.Parcel@Sun.COM 		return (found);
9701676Sjpk 	return (rc);
9711676Sjpk }
9721676Sjpk 
9731676Sjpk /*
9741676Sjpk  * _write_defattrs
9751676Sjpk  *	writes current entries to devalloc_defaults.
9761676Sjpk  */
9771676Sjpk static void
_write_defattrs(FILE * fp,strentry_t * head_defent)9781676Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent)
9791676Sjpk {
9801676Sjpk 	strentry_t *tmp_str;
9811676Sjpk 
9821676Sjpk 	for (tmp_str = head_defent; tmp_str != NULL;
9831676Sjpk 	    tmp_str = tmp_str->se_next) {
9841676Sjpk 		(void) fputs(tmp_str->se_str, fp);
9851676Sjpk 		(void) fputs("\n", fp);
9861676Sjpk 	}
9871676Sjpk 
9881676Sjpk }
9891676Sjpk 
9901676Sjpk /*
9911676Sjpk  * _write_device_allocate -
9921676Sjpk  *	writes current entries in the list to device_allocate.
99311529SJan.Parcel@Sun.COM  *	frees the strings
9941676Sjpk  */
9951676Sjpk static void
_write_device_allocate(char * odevalloc,FILE * dafp,strentry_t * head_devallocp)9961676Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
9971676Sjpk {
9981676Sjpk 	int		is_on = -1;
99911529SJan.Parcel@Sun.COM 	strentry_t	*tmp_str, *old_str;
10001676Sjpk 	struct stat	dastat;
10011676Sjpk 
10021676Sjpk 	(void) fseek(dafp, (off_t)0, SEEK_SET);
10031676Sjpk 
10041676Sjpk 	/*
10051676Sjpk 	 * if the devalloc on/off string existed before,
10061676Sjpk 	 * put it back before anything else.
10071676Sjpk 	 * we need to check for the string only if the file
10081676Sjpk 	 * exists.
10091676Sjpk 	 */
10101676Sjpk 	if (stat(odevalloc, &dastat) == 0) {
10111676Sjpk 		is_on = da_is_on();
10121676Sjpk 		if (is_on == 0)
10131676Sjpk 			(void) fputs(DA_OFF_STR, dafp);
10141676Sjpk 		else if (is_on == 1)
10151676Sjpk 			(void) fputs(DA_ON_STR, dafp);
10161676Sjpk 	}
10171676Sjpk 	tmp_str = head_devallocp;
10181676Sjpk 	while (tmp_str) {
10191676Sjpk 		(void) fputs(tmp_str->se_str, dafp);
10201676Sjpk 		(void) fputs("\n", dafp);
102111529SJan.Parcel@Sun.COM 		old_str = tmp_str;
10221676Sjpk 		tmp_str = tmp_str->se_next;
102311529SJan.Parcel@Sun.COM 		free(old_str);
10241676Sjpk 	}
10251676Sjpk }
10261676Sjpk 
10271676Sjpk /*
10281676Sjpk  * _write_device_maps -
10291676Sjpk  *	writes current entries in the list to device_maps.
103011529SJan.Parcel@Sun.COM  *	and frees the strings
10311676Sjpk  */
10321676Sjpk static void
_write_device_maps(FILE * dmfp,strentry_t * head_devmapp)10331676Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
10341676Sjpk {
103511529SJan.Parcel@Sun.COM 	strentry_t	*tmp_str, *old_str;
10361676Sjpk 
10371676Sjpk 	(void) fseek(dmfp, (off_t)0, SEEK_SET);
10381676Sjpk 
10391676Sjpk 	tmp_str = head_devmapp;
10401676Sjpk 	while (tmp_str) {
10411676Sjpk 		(void) fputs(tmp_str->se_str, dmfp);
10421676Sjpk 		(void) fputs("\n", dmfp);
104311529SJan.Parcel@Sun.COM 		old_str = tmp_str;
10441676Sjpk 		tmp_str = tmp_str->se_next;
104511529SJan.Parcel@Sun.COM 		free(old_str);
10461676Sjpk 	}
10471676Sjpk }
10481676Sjpk 
10491676Sjpk /*
10501676Sjpk  * _write_new_defattrs
10511676Sjpk  *	writes the new entry to devalloc_defaults.
10521676Sjpk  *	returns 0 on success, -1 on error.
10531676Sjpk  */
10541676Sjpk static int
_write_new_defattrs(FILE * fp,da_args * dargs)10551676Sjpk _write_new_defattrs(FILE *fp, da_args *dargs)
10561676Sjpk {
10571676Sjpk 	int		count;
10581676Sjpk 	char		*tok = NULL, *tokp = NULL;
10591676Sjpk 	char		*lasts;
10601676Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
10611676Sjpk 
10621676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
10631676Sjpk 		return (-1);
10641676Sjpk 	if (!devinfo->devopts)
10651676Sjpk 		return (0);
10661676Sjpk 	(void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
10671676Sjpk 	    KV_TOKEN_DELIMIT);
106811529SJan.Parcel@Sun.COM 	if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) {
10691676Sjpk 		(void) strcpy(tokp, devinfo->devopts);
10701676Sjpk 		if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) {
10711676Sjpk 			(void) fprintf(fp, "%s", tok);
10721676Sjpk 			count = 1;
10731676Sjpk 		}
10741676Sjpk 		while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
10751676Sjpk 			if (count)
10761676Sjpk 				(void) fprintf(fp, "%s", KV_DELIMITER);
10771676Sjpk 			(void) fprintf(fp, "%s", tok);
10781676Sjpk 			count++;
10791676Sjpk 		}
10801676Sjpk 	} else {
10811676Sjpk 		(void) fprintf(fp, "%s", devinfo->devopts);
10821676Sjpk 	}
10831676Sjpk 
10841676Sjpk 	return (0);
10851676Sjpk }
10861676Sjpk 
10871676Sjpk /*
10881676Sjpk  * _write_new_entry -
10891676Sjpk  *	writes the new devalloc_t to device_allocate or the new devmap_t to
10901676Sjpk  *	device_maps.
10911676Sjpk  *	returns 0 on success, -1 on error.
10921676Sjpk  */
10931676Sjpk static int
_write_new_entry(FILE * fp,da_args * dargs,int flag)10941676Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag)
10951676Sjpk {
10961676Sjpk 	int		count;
10971676Sjpk 	char		*tok = NULL, *tokp = NULL;
10981676Sjpk 	char		*lasts;
10991676Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
11001676Sjpk 
11011676Sjpk 	if (flag & DA_MAPS_ONLY)
11021676Sjpk 		goto dmap_only;
11031676Sjpk 
11041676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
11051676Sjpk 		return (-1);
11061676Sjpk 
11071676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
11081676Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
11091676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
11101676Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
11111676Sjpk 	if (devinfo->devopts == NULL) {
11121676Sjpk 		(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
11131676Sjpk 		    KV_DELIMITER);
11141676Sjpk 	} else {
111511529SJan.Parcel@Sun.COM 		if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1))
111611529SJan.Parcel@Sun.COM 		    != NULL) {
11171676Sjpk 			(void) strcpy(tokp, devinfo->devopts);
11181676Sjpk 			if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
11191676Sjpk 			    NULL) {
11201676Sjpk 				(void) fprintf(fp, "%s", tok);
11211676Sjpk 				count = 1;
11221676Sjpk 			}
11231676Sjpk 			while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
11241676Sjpk 			    &lasts)) != NULL) {
11251676Sjpk 				if (count)
11261676Sjpk 					(void) fprintf(fp, "%s",
11271676Sjpk 					    KV_TOKEN_DELIMIT "\\\n\t");
11281676Sjpk 				(void) fprintf(fp, "%s", tok);
11291676Sjpk 				count++;
11301676Sjpk 			}
11311676Sjpk 			if (count)
11321676Sjpk 				(void) fprintf(fp, "%s",
11331676Sjpk 				    KV_DELIMITER "\\\n\t");
11341676Sjpk 		} else {
11351676Sjpk 			(void) fprintf(fp, "%s%s", devinfo->devopts,
11361676Sjpk 			    KV_DELIMITER "\\\n\t");
11371676Sjpk 		}
11381676Sjpk 	}
11391676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
11401676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
11411676Sjpk 	    (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
11421676Sjpk 	    KV_DELIMITER);
11431676Sjpk 	(void) fprintf(fp, "%s\n",
11441676Sjpk 	    (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
11451676Sjpk 
11461676Sjpk dmap_only:
11471676Sjpk 	if (flag & DA_ALLOC_ONLY)
11481676Sjpk 		return (0);
11491676Sjpk 
11501676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
11511676Sjpk 		return (-1);
11521676Sjpk 
11531676Sjpk 	(void) fprintf(fp, "%s%s\\\n",
11541676Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
11551676Sjpk 	(void) fprintf(fp, "\t%s%s\\\n",
11561676Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
11571676Sjpk 	(void) fprintf(fp, "\t%s\n",
11581676Sjpk 	    (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
11591676Sjpk 
11601676Sjpk 	return (0);
11611676Sjpk }
11621676Sjpk 
11631676Sjpk /*
11641676Sjpk  * _da_lock_devdb -
11651676Sjpk  *	locks the database files; lock can be either broken explicitly by
11661676Sjpk  *	closing the fd of the lock file, or it expires automatically at process
11671676Sjpk  *	termination.
11681676Sjpk  * 	returns fd of the lock file or -1 on error.
11691676Sjpk  */
11701676Sjpk int
_da_lock_devdb(char * rootdir)11711676Sjpk _da_lock_devdb(char *rootdir)
11721676Sjpk {
11731676Sjpk 	int		lockfd = -1;
11744514Saj 	int		ret;
11754514Saj 	int		count = 0;
11764514Saj 	int		retry = 10;
11774514Saj 	int		retry_sleep;
11784514Saj 	uint_t		seed;
11791676Sjpk 	char		*lockfile;
11801676Sjpk 	char		path[MAXPATHLEN];
11811676Sjpk 	int		size = sizeof (path);
11821676Sjpk 
11831676Sjpk 	if (rootdir == NULL) {
11841676Sjpk 		lockfile = DA_DB_LOCK;
11851676Sjpk 	} else {
11861676Sjpk 		path[0] = '\0';
11871676Sjpk 		if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
11881676Sjpk 			return (-1);
11891676Sjpk 		lockfile = path;
11901676Sjpk 	}
11911676Sjpk 
11921676Sjpk 	if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
11931676Sjpk 		/* cannot open lock file */
11941676Sjpk 		return (-1);
11951676Sjpk 
11961676Sjpk 	(void) fchown(lockfd, DA_UID, DA_GID);
11971676Sjpk 
11981676Sjpk 	if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
11991676Sjpk 		/* cannot position lock file */
12001676Sjpk 		(void) close(lockfd);
12011676Sjpk 		return (-1);
12021676Sjpk 	}
12034514Saj 	errno = 0;
12044514Saj 	while (retry > 0) {
12054514Saj 		count++;
12064514Saj 		seed = (uint_t)gethrtime();
12074514Saj 		ret = lockf(lockfd, F_TLOCK, 0);
12084514Saj 		if (ret == 0) {
12094514Saj 			(void) utime(lockfile, NULL);
12104514Saj 			return (lockfd);
12114514Saj 		}
12124514Saj 		if ((errno != EACCES) && (errno != EAGAIN)) {
12134514Saj 			/* cannot set lock */
12144514Saj 			(void) close(lockfd);
12154514Saj 			return (-1);
12164514Saj 		}
12174514Saj 		retry--;
12184514Saj 		retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count;
12194514Saj 		(void) sleep(retry_sleep);
12204514Saj 		errno = 0;
12211676Sjpk 	}
12221676Sjpk 
12234514Saj 	return (-1);
12241676Sjpk }
12251676Sjpk 
12261676Sjpk /*
12271676Sjpk  * da_open_devdb -
12281676Sjpk  *	opens one or both database files - device_allocate, device_maps - in
12291676Sjpk  *	the specified mode.
12301676Sjpk  *	locks the database files; lock is either broken explicitly by the
12311676Sjpk  *	caller by closing the lock file fd, or it expires automatically at
12321676Sjpk  *	process termination.
12331676Sjpk  *	writes the file pointer of opened file in the input args - dafp, dmfp.
12341676Sjpk  *	returns fd of the lock file on success, -2 if database file does not
12351676Sjpk  *	exist, -1 on other errors.
12361676Sjpk  */
12371676Sjpk int
da_open_devdb(char * rootdir,FILE ** dafp,FILE ** dmfp,int flag)12381676Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
12391676Sjpk {
12401676Sjpk 	int	oflag = 0;
12411676Sjpk 	int	fda = -1;
12421676Sjpk 	int	fdm = -1;
12431676Sjpk 	int	lockfd = -1;
12441676Sjpk 	char	*fname;
12451676Sjpk 	char	*fmode;
12461676Sjpk 	char	path[MAXPATHLEN];
12471676Sjpk 	FILE	*devfile;
12481676Sjpk 
12491676Sjpk 	if ((dafp == NULL) && (dmfp == NULL))
12501676Sjpk 		return (-1);
12511676Sjpk 
12521676Sjpk 	if (flag & DA_RDWR) {
12531676Sjpk 		oflag = DA_RDWR;
12541914Scasper 		fmode = "r+F";
12551676Sjpk 	} else if (flag & DA_RDONLY) {
12561676Sjpk 		oflag = DA_RDONLY;
12571914Scasper 		fmode = "rF";
12581676Sjpk 	}
12591676Sjpk 
12601676Sjpk 	if ((lockfd = _da_lock_devdb(rootdir)) == -1)
12611676Sjpk 		return (-1);
12621676Sjpk 
12631676Sjpk 	if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
12641676Sjpk 		goto dmap_only;
12651676Sjpk 
12661676Sjpk 	path[0] = '\0';
12671676Sjpk 
12681676Sjpk 	/*
12691676Sjpk 	 * open the device allocation file
12701676Sjpk 	 */
12711676Sjpk 	if (rootdir == NULL) {
12721676Sjpk 		fname = DEVALLOC;
12731676Sjpk 	} else {
12741676Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
12751676Sjpk 		    DEVALLOC) >= sizeof (path)) {
12761676Sjpk 			if (lockfd != -1)
12771676Sjpk 				(void) close(lockfd);
12781676Sjpk 			return (-1);
12791676Sjpk 		}
12801676Sjpk 		fname = path;
12811676Sjpk 	}
12821676Sjpk 	if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
12831676Sjpk 		if (lockfd != -1)
12841676Sjpk 			(void) close(lockfd);
12851676Sjpk 		return ((errno == ENOENT) ? -2 : -1);
12861676Sjpk 	}
12871676Sjpk 	if ((devfile = fdopen(fda, fmode)) == NULL) {
12881676Sjpk 		(void) close(fda);
12891676Sjpk 		if (lockfd != -1)
12901676Sjpk 			(void) close(lockfd);
12911676Sjpk 		return (-1);
12921676Sjpk 	}
12931676Sjpk 	*dafp = devfile;
12941676Sjpk 	(void) fchmod(fda, DA_DBMODE);
12951676Sjpk 
12961676Sjpk 	if ((flag & DA_ALLOC_ONLY))
12971676Sjpk 		goto out;
12981676Sjpk 
12991676Sjpk dmap_only:
13001676Sjpk 	path[0] = '\0';
13011676Sjpk 	/*
13021676Sjpk 	 * open the device map file
13031676Sjpk 	 */
13041676Sjpk 	if (rootdir == NULL) {
13051676Sjpk 		fname = DEVMAP;
13061676Sjpk 	} else {
13071676Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
13081676Sjpk 		    DEVMAP) >= sizeof (path)) {
13091676Sjpk 			(void) close(fda);
13101676Sjpk 			if (lockfd != -1)
13111676Sjpk 				(void) close(lockfd);
13121676Sjpk 			return (-1);
13131676Sjpk 		}
13141676Sjpk 		fname = path;
13151676Sjpk 	}
13161676Sjpk 
13171676Sjpk 	if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
13181676Sjpk 		if (lockfd != -1)
13191676Sjpk 			(void) close(lockfd);
13201676Sjpk 		return ((errno == ENOENT) ? -2 : -1);
13211676Sjpk 	}
13221676Sjpk 
13231676Sjpk 	if ((devfile = fdopen(fdm, fmode)) == NULL) {
13241676Sjpk 		(void) close(fdm);
13251676Sjpk 		(void) close(fda);
13261676Sjpk 		if (lockfd != -1)
13271676Sjpk 			(void) close(lockfd);
13281676Sjpk 		return (-1);
13291676Sjpk 	}
13301676Sjpk 	*dmfp = devfile;
13311676Sjpk 	(void) fchmod(fdm, DA_DBMODE);
13321676Sjpk 
13331676Sjpk out:
13341676Sjpk 	return (lockfd);
13351676Sjpk }
13361676Sjpk 
13371676Sjpk /*
13381676Sjpk  * _record_on_off -
13391676Sjpk  *	adds either DA_ON_STR or DA_OFF_STR to device_allocate
13401676Sjpk  *	returns 0 on success, -1 on error.
13411676Sjpk  */
13421676Sjpk static int
_record_on_off(da_args * dargs,FILE * tafp,FILE * dafp)13431676Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
13441676Sjpk {
13451676Sjpk 	int		dafd;
13461676Sjpk 	int		nsize;
13471676Sjpk 	int		nitems = 1;
13481676Sjpk 	int		actionlen;
13491676Sjpk 	int		str_found = 0;
13501676Sjpk 	int		len = 0, nlen = 0, plen = 0;
13511676Sjpk 	char		*ptr = NULL;
13521676Sjpk 	char		*actionstr;
13531676Sjpk 	char		*nbuf = NULL;
13541676Sjpk 	char		line[MAX_CANON];
13551676Sjpk 	struct stat	dastat;
13561676Sjpk 
13571676Sjpk 	if (dargs->optflag & DA_ON)
13581676Sjpk 		actionstr = DA_ON_STR;
13591676Sjpk 	else
13601676Sjpk 		actionstr = DA_OFF_STR;
13611676Sjpk 	actionlen = strlen(actionstr);
13621676Sjpk 	dafd = fileno(dafp);
13631676Sjpk 	if (fstat(dafd, &dastat) == -1)
13641676Sjpk 		return (-1);
13651676Sjpk 
13661676Sjpk 	/* check the old device_allocate for on/off string */
13671676Sjpk 	ptr = fgets(line, MAX_CANON, dafp);
13681676Sjpk 	if (ptr != NULL) {
13691676Sjpk 		if ((strcmp(line, DA_ON_STR) == 0) ||
13701676Sjpk 		    (strcmp(line, DA_OFF_STR) == 0)) {
13711676Sjpk 			str_found = 1;
13721676Sjpk 			nsize = dastat.st_size;
13731676Sjpk 		}
13741676Sjpk 	}
13751676Sjpk 	if (!ptr || !str_found) {
13761676Sjpk 		/*
13771676Sjpk 		 * the file never had either the on or the off string;
13781676Sjpk 		 * make room for it.
13791676Sjpk 		 */
13801676Sjpk 		str_found = 0;
13811676Sjpk 		nsize = dastat.st_size + actionlen + 1;
13821676Sjpk 	}
138311529SJan.Parcel@Sun.COM 	if ((nbuf = (char *)malloc(nsize + 1)) == NULL)
13841676Sjpk 		return (-1);
13851676Sjpk 	nbuf[0] = '\0';
13861676Sjpk 	/* put the on/off string */
13871676Sjpk 	(void) strcpy(nbuf, actionstr);
13881676Sjpk 	nlen = strlen(nbuf);
13891676Sjpk 	plen = nlen;
13901676Sjpk 	if (ptr && !str_found) {
13911676Sjpk 		/* now put the first line that we read in fgets */
13921676Sjpk 		nlen = plen + strlen(line) + 1;
13931676Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
13941676Sjpk 		if (len >= nsize) {
13951676Sjpk 			free(nbuf);
13961676Sjpk 			return (-1);
13971676Sjpk 		}
13981676Sjpk 		plen += len;
13991676Sjpk 	}
14001676Sjpk 
14011676Sjpk 	/* now get the rest of the old file */
14021676Sjpk 	while (fgets(line, MAX_CANON, dafp) != NULL) {
14031676Sjpk 		nlen = plen + strlen(line) + 1;
14041676Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
14051676Sjpk 		if (len >= nsize) {
14061676Sjpk 			free(nbuf);
14071676Sjpk 			return (-1);
14081676Sjpk 		}
14091676Sjpk 		plen += len;
14101676Sjpk 	}
14111676Sjpk 	len = strlen(nbuf) + 1;
14121676Sjpk 	if (len < nsize)
14131676Sjpk 		nbuf[len] = '\n';
14141676Sjpk 
14151676Sjpk 	/* write the on/off str + the old device_allocate to the temp file */
14161676Sjpk 	if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
14171676Sjpk 		free(nbuf);
14181676Sjpk 		return (-1);
14191676Sjpk 	}
14201676Sjpk 
14211676Sjpk 	free(nbuf);
14221676Sjpk 
14231676Sjpk 	return (0);
14241676Sjpk }
14251676Sjpk 
14261676Sjpk /*
14271676Sjpk  * da_update_defattrs -
14281676Sjpk  *	writes default attributes to devalloc_defaults
14291676Sjpk  *	returns 0 on success, -1 on error.
14301676Sjpk  */
14311676Sjpk int
da_update_defattrs(da_args * dargs)14321676Sjpk da_update_defattrs(da_args *dargs)
14331676Sjpk {
14341676Sjpk 	int		rc = 0, lockfd = 0, tmpfd = 0;
14351676Sjpk 	char		*defpath = DEFATTRS;
14361676Sjpk 	char		*tmpdefpath = TMPATTRS;
14371676Sjpk 	FILE		*tmpfp = NULL;
14381676Sjpk 	struct stat	dstat;
14391676Sjpk 	strentry_t	*head_defent = NULL;
14401676Sjpk 
14411676Sjpk 	if (dargs == NULL)
14421676Sjpk 		return (0);
14431676Sjpk 	if ((lockfd = _da_lock_devdb(NULL)) == -1)
14441676Sjpk 		return (-1);
14451676Sjpk 	if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
14461676Sjpk 		(void) close(lockfd);
14471676Sjpk 		return (-1);
14481676Sjpk 	}
14491676Sjpk 	(void) fchown(tmpfd, DA_UID, DA_GID);
14501676Sjpk 	if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) {
14511676Sjpk 		(void) close(tmpfd);
14521676Sjpk 		(void) unlink(tmpdefpath);
14531676Sjpk 		(void) close(lockfd);
14541676Sjpk 		return (-1);
14551676Sjpk 	}
14561676Sjpk 	/*
14571676Sjpk 	 * examine all entries, remove an old one if required, check
14581676Sjpk 	 * if a new one needs to be added.
14591676Sjpk 	 */
14601676Sjpk 	if (stat(defpath, &dstat) == 0) {
14611676Sjpk 		if ((rc = _build_defattrs(dargs, &head_defent)) != 0) {
14621676Sjpk 			if (rc == 1) {
14631676Sjpk 				(void) close(tmpfd);
14641676Sjpk 				(void) unlink(tmpdefpath);
14651676Sjpk 				(void) close(lockfd);
14661676Sjpk 				return (rc);
14671676Sjpk 			}
14681676Sjpk 		}
14691676Sjpk 	}
14701676Sjpk 	/*
14711676Sjpk 	 * write back any existing entries.
14721676Sjpk 	 */
14731676Sjpk 	_write_defattrs(tmpfp, head_defent);
14741676Sjpk 
14751676Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
14761676Sjpk 		/* add new entries */
14771676Sjpk 		rc = _write_new_defattrs(tmpfp, dargs);
14781676Sjpk 		(void) fclose(tmpfp);
14791676Sjpk 	} else {
14801676Sjpk 		(void) fclose(tmpfp);
14811676Sjpk 	}
14821676Sjpk 	if (rename(tmpdefpath, defpath) != 0) {
14831676Sjpk 		rc = -1;
14841676Sjpk 		(void) unlink(tmpdefpath);
14851676Sjpk 	}
14861676Sjpk 	(void) close(lockfd);
14871676Sjpk 
14881676Sjpk 	return (rc);
14891676Sjpk }
14901676Sjpk 
14911676Sjpk /*
14921676Sjpk  * da_update_device -
149311529SJan.Parcel@Sun.COM  *	Writes existing entries and the SINGLE change requested by da_args,
1494*12373SJan.Parcel@Sun.COM  *	to device_allocate and device_maps.
1495*12373SJan.Parcel@Sun.COM  *	Returns 0 on success, -1 on error.
14961676Sjpk  */
14971676Sjpk int
da_update_device(da_args * dargs)14981676Sjpk da_update_device(da_args *dargs)
14991676Sjpk {
15001676Sjpk 	int		rc;
15011676Sjpk 	int		tafd = -1, tmfd = -1;
15021676Sjpk 	int		lockfd = -1;
15031676Sjpk 	char		*rootdir = NULL;
15044514Saj 	char		*apathp = NULL, *mpathp = NULL;
15054514Saj 	char		*dapathp = NULL, *dmpathp = NULL;
15064514Saj 	char		apath[MAXPATHLEN], mpath[MAXPATHLEN];
15074514Saj 	char		dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
15081676Sjpk 	FILE		*tafp = NULL, *tmfp = NULL, *dafp = NULL;
15091676Sjpk 	struct stat	dastat;
15101676Sjpk 	devinfo_t	*devinfo;
15111676Sjpk 	strentry_t	*head_devmapp = NULL;
15121676Sjpk 	strentry_t	*head_devallocp = NULL;
15131676Sjpk 
15141676Sjpk 	if (dargs == NULL)
15151676Sjpk 		return (0);
15161676Sjpk 
15171676Sjpk 	rootdir = dargs->rootdir;
15181676Sjpk 	devinfo = dargs->devinfo;
15191676Sjpk 
15201676Sjpk 	/*
15211676Sjpk 	 * adding/removing entries should be done in both
15221676Sjpk 	 * device_allocate and device_maps. updates can be
15231676Sjpk 	 * done in both or either of the files.
15241676Sjpk 	 */
15251676Sjpk 	if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
15261676Sjpk 		if (dargs->optflag & DA_ALLOC_ONLY ||
15271676Sjpk 		    dargs->optflag & DA_MAPS_ONLY)
15281676Sjpk 			return (0);
15291676Sjpk 	}
15301676Sjpk 
15311676Sjpk 	/*
15321676Sjpk 	 * name, type and list are required fields for adding a new
15331676Sjpk 	 * device.
15341676Sjpk 	 */
15351676Sjpk 	if ((dargs->optflag & DA_ADD) &&
15361676Sjpk 	    ((devinfo->devname == NULL) ||
15371676Sjpk 	    (devinfo->devtype == NULL) ||
15381676Sjpk 	    (devinfo->devlist == NULL))) {
15391676Sjpk 		return (-1);
15401676Sjpk 	}
15411676Sjpk 
15421676Sjpk 	if (rootdir != NULL) {
15431676Sjpk 		if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
15441676Sjpk 		    TMPALLOC) >= sizeof (apath))
15451676Sjpk 			return (-1);
15461676Sjpk 		apathp = apath;
15471676Sjpk 		if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
15481676Sjpk 		    DEVALLOC) >= sizeof (dapath))
15491676Sjpk 			return (-1);
15501676Sjpk 		dapathp = dapath;
15511676Sjpk 		if (!(dargs->optflag & DA_ALLOC_ONLY)) {
15521676Sjpk 			if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
15531676Sjpk 			    TMPMAP) >= sizeof (mpath))
15541676Sjpk 				return (-1);
15551676Sjpk 			mpathp = mpath;
15561676Sjpk 			if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
15571676Sjpk 			    DEVMAP) >= sizeof (dmpath))
15581676Sjpk 				return (-1);
15591676Sjpk 			dmpathp = dmpath;
15601676Sjpk 		}
15611676Sjpk 	} else {
15621676Sjpk 		apathp = TMPALLOC;
15631676Sjpk 		dapathp = DEVALLOC;
15641676Sjpk 		mpathp = TMPMAP;
15651676Sjpk 		dmpathp = DEVMAP;
15661676Sjpk 	}
15671676Sjpk 
15681676Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
15691676Sjpk 		goto dmap_only;
15701676Sjpk 
15711676Sjpk 	/*
15721676Sjpk 	 * Check if we are here just to record on/off status of
15731676Sjpk 	 * device_allocation.
15741676Sjpk 	 */
15751676Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
15761676Sjpk 		lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
15771676Sjpk 		    DA_RDONLY|DA_ALLOC_ONLY);
15781676Sjpk 	else
15791676Sjpk 		lockfd = _da_lock_devdb(rootdir);
15801676Sjpk 	if (lockfd == -1)
15811676Sjpk 		return (-1);
15821676Sjpk 
15831676Sjpk 	if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
15841676Sjpk 		(void) close(lockfd);
15851676Sjpk 		(void) fclose(dafp);
15861676Sjpk 		return (-1);
15871676Sjpk 	}
15881676Sjpk 	(void) fchown(tafd, DA_UID, DA_GID);
15891676Sjpk 	if ((tafp = fdopen(tafd, "r+")) == NULL) {
15901676Sjpk 		(void) close(tafd);
15911676Sjpk 		(void) unlink(apathp);
15921676Sjpk 		(void) fclose(dafp);
15931676Sjpk 		(void) close(lockfd);
15941676Sjpk 		return (-1);
15951676Sjpk 	}
15961676Sjpk 
15971676Sjpk 	/*
15981676Sjpk 	 * We don't need to parse the file if we are here just to record
15991676Sjpk 	 * on/off status of device_allocation.
16001676Sjpk 	 */
16011676Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
16021676Sjpk 		if (_record_on_off(dargs, tafp, dafp) == -1) {
16031676Sjpk 			(void) close(tafd);
16041676Sjpk 			(void) unlink(apathp);
16051676Sjpk 			(void) fclose(dafp);
16061676Sjpk 			(void) close(lockfd);
16071676Sjpk 			return (-1);
16081676Sjpk 		}
16091676Sjpk 		(void) fclose(dafp);
16101676Sjpk 		goto out;
16111676Sjpk 	}
16121676Sjpk 
16131676Sjpk 	/*
161411529SJan.Parcel@Sun.COM 	 * If reacting to a hotplug, read the file entries,
161511529SJan.Parcel@Sun.COM 	 * figure out what dname (tname + a new number) goes to the
161611529SJan.Parcel@Sun.COM 	 * device being added/removed, and create a good head_devallocp and
161711529SJan.Parcel@Sun.COM 	 * head_devmapp with everything good still in it (_rebuild_lists)
161811529SJan.Parcel@Sun.COM 	 *
161911529SJan.Parcel@Sun.COM 	 * Else examine all the entries, remove an old one if it is
162011529SJan.Parcel@Sun.COM 	 * a duplicate with a device being added, returning the
162111529SJan.Parcel@Sun.COM 	 * remaining list (_build_lists.)
162211529SJan.Parcel@Sun.COM 	 *
162311529SJan.Parcel@Sun.COM 	 * We need to do this only if the file exists already.
162411529SJan.Parcel@Sun.COM 	 *
162511529SJan.Parcel@Sun.COM 	 * Once we have built these lists, we need to free the strings
162611529SJan.Parcel@Sun.COM 	 * in the head_* arrays before returning.
16271676Sjpk 	 */
16281676Sjpk 	if (stat(dapathp, &dastat) == 0) {
162911529SJan.Parcel@Sun.COM 		/* for device allocation, the /etc files are the "master" */
163011529SJan.Parcel@Sun.COM 		if ((dargs->optflag & (DA_ADD| DA_EVENT)) &&
163111529SJan.Parcel@Sun.COM 		    (!(dargs->optflag & DA_FORCE)))
163211529SJan.Parcel@Sun.COM 			rc = _rebuild_lists(dargs, &head_devallocp,
163311529SJan.Parcel@Sun.COM 			    &head_devmapp);
163411529SJan.Parcel@Sun.COM 		else
163511529SJan.Parcel@Sun.COM 			rc = _build_lists(dargs, &head_devallocp,
163611529SJan.Parcel@Sun.COM 			    &head_devmapp);
163711529SJan.Parcel@Sun.COM 
163811529SJan.Parcel@Sun.COM 		if (rc != 0 && rc != 1) {
163911529SJan.Parcel@Sun.COM 			(void) close(tafd);
164011529SJan.Parcel@Sun.COM 			(void) unlink(apathp);
164111529SJan.Parcel@Sun.COM 			(void) close(lockfd);
164211529SJan.Parcel@Sun.COM 			return (-1);
16431676Sjpk 		}
164411529SJan.Parcel@Sun.COM 	} else
164511529SJan.Parcel@Sun.COM 		rc = 0;
164611529SJan.Parcel@Sun.COM 
164711529SJan.Parcel@Sun.COM 	if ((dargs->optflag & DA_REMOVE) && (rc == 0)) {
164811529SJan.Parcel@Sun.COM 		(void) close(tafd);
164911529SJan.Parcel@Sun.COM 		(void) unlink(apathp);
165011529SJan.Parcel@Sun.COM 		(void) close(lockfd);
165111529SJan.Parcel@Sun.COM 		return (0);
16521676Sjpk 	}
165311529SJan.Parcel@Sun.COM 	/*
165411529SJan.Parcel@Sun.COM 	 * TODO: clean up the workings of DA_UPDATE.
165511529SJan.Parcel@Sun.COM 	 * Due to da_match looking at fields that are missing
165611529SJan.Parcel@Sun.COM 	 * in dargs for DA_UPDATE, the da_match call returns no match,
165711529SJan.Parcel@Sun.COM 	 * but due to the way _da2str combines the devalloc_t info with
165811529SJan.Parcel@Sun.COM 	 * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work.
165911529SJan.Parcel@Sun.COM 	 *
166011529SJan.Parcel@Sun.COM 	 * This would not scale if any type of update was ever needed
166111529SJan.Parcel@Sun.COM 	 * from the daemon.
166211529SJan.Parcel@Sun.COM 	 */
16631676Sjpk 
16641676Sjpk 	/*
166511529SJan.Parcel@Sun.COM 	 * Write out devallocp along with the devalloc on/off string.
16661676Sjpk 	 */
16671676Sjpk 	_write_device_allocate(dapathp, tafp, head_devallocp);
16681676Sjpk 
16691676Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
16701676Sjpk 		goto out;
16711676Sjpk 
16721676Sjpk dmap_only:
16731676Sjpk 	if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
16741676Sjpk 		(void) close(tafd);
16751676Sjpk 		(void) unlink(apathp);
16761676Sjpk 		(void) close(lockfd);
16771676Sjpk 		return (-1);
16781676Sjpk 	}
16791676Sjpk 	(void) fchown(tmfd, DA_UID, DA_GID);
16801676Sjpk 	if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
16811676Sjpk 		(void) close(tafd);
16821676Sjpk 		(void) unlink(apathp);
16831676Sjpk 		(void) close(tmfd);
16841676Sjpk 		(void) unlink(mpathp);
16851676Sjpk 		(void) close(lockfd);
16861676Sjpk 		return (-1);
16871676Sjpk 	}
16881676Sjpk 
168911529SJan.Parcel@Sun.COM 	/*
169011529SJan.Parcel@Sun.COM 	 * Write back any non-removed pre-existing entries.
169111529SJan.Parcel@Sun.COM 	 */
16921676Sjpk 	if (head_devmapp != NULL)
16931676Sjpk 		_write_device_maps(tmfp, head_devmapp);
16941676Sjpk 
16951676Sjpk out:
169611529SJan.Parcel@Sun.COM 	/*
169711529SJan.Parcel@Sun.COM 	 * Add any new entries here.
169811529SJan.Parcel@Sun.COM 	 */
16991676Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
17001676Sjpk 		/* add any new entries */
17011676Sjpk 		rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
17021676Sjpk 		(void) fclose(tafp);
17031676Sjpk 
17041676Sjpk 		if (rc == 0)
17051676Sjpk 			rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
17061676Sjpk 		(void) fclose(tmfp);
17071676Sjpk 	} else {
17081676Sjpk 		if (tafp)
17091676Sjpk 			(void) fclose(tafp);
17101676Sjpk 		if (tmfp)
17111676Sjpk 			(void) fclose(tmfp);
17121676Sjpk 	}
17131676Sjpk 
17141676Sjpk 	rc = 0;
17151676Sjpk 	if (!(dargs->optflag & DA_MAPS_ONLY)) {
17161676Sjpk 		if (rename(apathp, dapathp) != 0) {
17171676Sjpk 			rc = -1;
17181676Sjpk 			(void) unlink(apathp);
17191676Sjpk 		}
17201676Sjpk 	}
17211676Sjpk 	if (!(dargs->optflag & DA_ALLOC_ONLY)) {
17221676Sjpk 		if (rename(mpathp, dmpathp) != 0) {
17231676Sjpk 			rc = -1;
17241676Sjpk 			(void) unlink(mpathp);
17251676Sjpk 		}
17261676Sjpk 	}
17271676Sjpk 
17281676Sjpk 	(void) close(lockfd);
17291676Sjpk 
17301676Sjpk 	return (rc);
17311676Sjpk }
17321676Sjpk 
17331676Sjpk /*
17341676Sjpk  * da_add_list -
17351676Sjpk  *	adds new /dev link name to the linked list of devices.
17361676Sjpk  *	returns 0 if link added successfully, -1 on error.
17371676Sjpk  */
17381676Sjpk int
da_add_list(devlist_t * dlist,char * link,int new_instance,int flag)17391676Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
17401676Sjpk {
17411676Sjpk 	int		instance;
17421676Sjpk 	int		nlen, plen;
17431676Sjpk 	int		new_entry = 0;
17441676Sjpk 	char		*dtype, *dexec, *tname, *kval;
17451676Sjpk 	char		*minstr = NULL, *maxstr = NULL;
174611529SJan.Parcel@Sun.COM 	char		dname[DA_MAXNAME + 1];
17471676Sjpk 	kva_t		*kva;
17481676Sjpk 	deventry_t	*dentry = NULL, *nentry = NULL, *pentry = NULL;
17491676Sjpk 	da_defs_t	*da_defs;
17501676Sjpk 
17511676Sjpk 	if (dlist == NULL || link == NULL)
17521676Sjpk 		return (-1);
17531676Sjpk 
17541676Sjpk 	dname[0] = '\0';
17551676Sjpk 	if (flag & DA_AUDIO) {
17561676Sjpk 		dentry = dlist->audio;
17571676Sjpk 		tname = DA_AUDIO_NAME;
17581676Sjpk 		dtype = DA_AUDIO_TYPE;
17591676Sjpk 		dexec = DA_DEFAULT_AUDIO_CLEAN;
17601676Sjpk 	} else if (flag & DA_CD) {
17611676Sjpk 		dentry = dlist->cd;
17621676Sjpk 		tname = DA_CD_NAME;
17631676Sjpk 		dtype = DA_CD_TYPE;
17641676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
17651676Sjpk 	} else if (flag & DA_FLOPPY) {
17661676Sjpk 		dentry = dlist->floppy;
17671676Sjpk 		tname = DA_FLOPPY_NAME;
17681676Sjpk 		dtype = DA_FLOPPY_TYPE;
17691676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
17701676Sjpk 	} else if (flag & DA_TAPE) {
17711676Sjpk 		dentry = dlist->tape;
17721676Sjpk 		tname = DA_TAPE_NAME;
17731676Sjpk 		dtype = DA_TAPE_TYPE;
17741676Sjpk 		dexec = DA_DEFAULT_TAPE_CLEAN;
17751676Sjpk 	} else if (flag & DA_RMDISK) {
17761676Sjpk 		dentry = dlist->rmdisk;
17771676Sjpk 		tname = DA_RMDISK_NAME;
17781676Sjpk 		dtype = DA_RMDISK_TYPE;
17791676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
17801676Sjpk 	} else {
17811676Sjpk 		return (-1);
17821676Sjpk 	}
17831676Sjpk 
17841676Sjpk 	for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
17851676Sjpk 		pentry = nentry;
17861676Sjpk 		(void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
17871676Sjpk 		if (nentry->devinfo.instance == new_instance)
17881676Sjpk 			/*
17891676Sjpk 			 * Add the new link name to the list of links
17901676Sjpk 			 * that the device 'dname' has.
17911676Sjpk 			 */
17921676Sjpk 			break;
17931676Sjpk 	}
17941676Sjpk 
17951676Sjpk 	if (nentry == NULL) {
17961676Sjpk 		/*
17971676Sjpk 		 * Either this is the first entry ever, or no matching entry
17981676Sjpk 		 * was found. Create a new one and add to the list.
17991676Sjpk 		 */
18001676Sjpk 		if (dentry == NULL)		/* first entry ever */
18011676Sjpk 			instance = 0;
18021676Sjpk 		else				/* no matching entry */
18031676Sjpk 			instance++;
18041676Sjpk 		(void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
18051676Sjpk 		if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
18061676Sjpk 		    NULL)
18071676Sjpk 			return (-1);
18081676Sjpk 		if (pentry != NULL)
18091676Sjpk 			pentry->next = nentry;
18101676Sjpk 		new_entry = 1;
18111676Sjpk 		nentry->devinfo.devname = strdup(dname);
18121676Sjpk 		nentry->devinfo.devtype = dtype;
18131676Sjpk 		nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
18141676Sjpk 		nentry->devinfo.devexec = dexec;
18151676Sjpk 		nentry->devinfo.instance = new_instance;
18161676Sjpk 		/*
18171676Sjpk 		 * Look for default label range, authorizations and cleaning
18181676Sjpk 		 * program in devalloc_defaults. If label range is not
18191676Sjpk 		 * specified in devalloc_defaults, assume it to be admin_low
18201676Sjpk 		 * to admin_high.
18211676Sjpk 		 */
18221676Sjpk 		minstr = DA_DEFAULT_MIN;
18231676Sjpk 		maxstr = DA_DEFAULT_MAX;
18241676Sjpk 		setdadefent();
18251676Sjpk 		if (da_defs = getdadeftype(nentry->devinfo.devtype)) {
18261676Sjpk 			kva = da_defs->devopts;
18271676Sjpk 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
18281676Sjpk 				minstr = strdup(kval);
18291676Sjpk 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
18301676Sjpk 				maxstr = strdup(kval);
18311676Sjpk 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
18321676Sjpk 				nentry->devinfo.devauths = strdup(kval);
18331676Sjpk 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
18341676Sjpk 				nentry->devinfo.devexec = strdup(kval);
18351676Sjpk 			freedadefent(da_defs);
18361676Sjpk 		}
18371676Sjpk 		enddadefent();
18381676Sjpk 		kval = NULL;
18391676Sjpk 		nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
18401676Sjpk 		    strlen(minstr) + strlen(KV_TOKEN_DELIMIT) +
18411676Sjpk 		    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr)
18421676Sjpk 		    + 1;			/* +1 for terminator */
18431676Sjpk 		if (kval = (char *)malloc(nlen))
18441676Sjpk 			(void) snprintf(kval, nlen, "%s%s%s%s%s%s%s",
18451676Sjpk 			    DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT,
18461676Sjpk 			    DAOPT_MAXLABEL, KV_ASSIGN, maxstr);
18471676Sjpk 		nentry->devinfo.devopts = kval;
18481676Sjpk 
18491676Sjpk 		nentry->devinfo.devlist = NULL;
18501676Sjpk 		nentry->next = NULL;
18511676Sjpk 	}
18521676Sjpk 
18531676Sjpk 	nlen = strlen(link) + 1;		/* +1 terminator */
18541676Sjpk 	if (nentry->devinfo.devlist) {
18551676Sjpk 		plen = strlen(nentry->devinfo.devlist);
18561676Sjpk 		nlen = nlen + plen + 1;	/* +1 for blank to separate entries */
18571676Sjpk 	} else {
18581676Sjpk 		plen = 0;
18591676Sjpk 	}
18601676Sjpk 
18611676Sjpk 	if ((nentry->devinfo.devlist =
18621676Sjpk 	    (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
18631676Sjpk 		if (new_entry) {
18641676Sjpk 			free(nentry->devinfo.devname);
18651676Sjpk 			free(nentry);
18661676Sjpk 			if (pentry != NULL)
18671676Sjpk 				pentry->next = NULL;
18681676Sjpk 		}
18691676Sjpk 		return (-1);
18701676Sjpk 	}
18711676Sjpk 
18721676Sjpk 	if (plen == 0)
18731676Sjpk 		(void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
18741676Sjpk 	else
18751676Sjpk 		(void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
18761676Sjpk 		    " %s", link);
18771676Sjpk 
18781676Sjpk 	if (pentry == NULL) {
18791676Sjpk 		/*
18801676Sjpk 		 * This is the first entry of this device type.
18811676Sjpk 		 */
18821676Sjpk 		if (flag & DA_AUDIO)
18831676Sjpk 			dlist->audio = nentry;
18841676Sjpk 		else if (flag & DA_CD)
18851676Sjpk 			dlist->cd = nentry;
18861676Sjpk 		else if (flag & DA_FLOPPY)
18871676Sjpk 			dlist->floppy = nentry;
18881676Sjpk 		else if (flag & DA_TAPE)
18891676Sjpk 			dlist->tape = nentry;
18901676Sjpk 		else if (flag & DA_RMDISK)
18911676Sjpk 			dlist->rmdisk = nentry;
18921676Sjpk 	}
18931676Sjpk 
18941676Sjpk 	return (0);
18951676Sjpk }
18961676Sjpk 
18971676Sjpk /*
18981676Sjpk  * da_remove_list -
18991676Sjpk  *	removes a /dev link name from the linked list of devices.
19001676Sjpk  *	returns type of device if link for that device removed
19011676Sjpk  *	successfully, else returns -1 on error.
19021676Sjpk  *	if all links for a device are removed, stores that device
19031676Sjpk  *	name in devname.
19041676Sjpk  */
19051676Sjpk int
da_remove_list(devlist_t * dlist,char * link,int type,char * devname,int size)19061676Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
19071676Sjpk {
19081676Sjpk 	int		flag;
19091676Sjpk 	int		remove_dev = 0;
19101676Sjpk 	int		nlen, plen, slen;
19111676Sjpk 	char		*lasts, *lname, *oldlist;
19121676Sjpk 	struct stat	rmstat;
19131676Sjpk 	deventry_t	*dentry, *current, *prev;
19141676Sjpk 
19151676Sjpk 	if (type != NULL)
19161676Sjpk 		flag = type;
19171676Sjpk 	else if (link == NULL)
19181676Sjpk 		return (-1);
19191676Sjpk 	else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
19201676Sjpk 		flag = DA_AUDIO;
19211676Sjpk 	else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
19221676Sjpk 	    strstr(link, "sr") || strstr(link, "rsr"))
19231676Sjpk 		flag = DA_CD;
19241676Sjpk 	else if (strstr(link, "fd") || strstr(link, "rfd") ||
19251676Sjpk 	    strstr(link, "diskette") || strstr(link, "rdiskette"))
19261676Sjpk 		flag = DA_FLOPPY;
19271676Sjpk 	else if (strstr(link, DA_TAPE_NAME))
19281676Sjpk 		flag = DA_TAPE;
19291676Sjpk 	else
19301676Sjpk 		flag = DA_RMDISK;
19311676Sjpk 
19321676Sjpk 	switch (type) {
19331676Sjpk 	case DA_AUDIO:
19341676Sjpk 		dentry = dlist->audio;
19351676Sjpk 		break;
19361676Sjpk 	case DA_CD:
19371676Sjpk 		dentry = dlist->cd;
19381676Sjpk 		break;
19391676Sjpk 	case DA_FLOPPY:
19401676Sjpk 		dentry = dlist->floppy;
19411676Sjpk 		break;
19421676Sjpk 	case DA_TAPE:
19431676Sjpk 		dentry = dlist->tape;
19441676Sjpk 		break;
19451676Sjpk 	case DA_RMDISK:
19461676Sjpk 		dentry = dlist->rmdisk;
19471676Sjpk 		break;
19481676Sjpk 	default:
19491676Sjpk 		return (-1);
19501676Sjpk 	}
19511676Sjpk 
19521676Sjpk 	if ((type != NULL) && (link == NULL)) {
19531676Sjpk 		for (current = dentry, prev = dentry; current != NULL;
19541676Sjpk 		    current = current->next) {
19551676Sjpk 			oldlist = strdup(current->devinfo.devlist);
19561676Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
19571676Sjpk 			    lname != NULL;
19581676Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
19591676Sjpk 				if (stat(lname, &rmstat) != 0) {
19601676Sjpk 					remove_dev = 1;
19611676Sjpk 					goto remove_dev;
19621676Sjpk 				}
19631676Sjpk 			}
19641676Sjpk 			prev = current;
19651676Sjpk 		}
19661676Sjpk 		return (-1);
19671676Sjpk 	}
19681676Sjpk 
19691676Sjpk 	for (current = dentry, prev = dentry; current != NULL;
19701676Sjpk 	    current = current->next) {
19711676Sjpk 		plen = strlen(current->devinfo.devlist);
19721676Sjpk 		nlen = strlen(link);
19731676Sjpk 		if (plen == nlen) {
19741676Sjpk 			if (strcmp(current->devinfo.devlist, link) == 0) {
19751676Sjpk 				/* last name in the list */
19761676Sjpk 				remove_dev = 1;
19771676Sjpk 				break;
19781676Sjpk 			}
19791676Sjpk 		}
19801676Sjpk 		if (strstr(current->devinfo.devlist, link)) {
19811676Sjpk 			nlen = plen - nlen + 1;
19821676Sjpk 			oldlist = strdup(current->devinfo.devlist);
19831676Sjpk 			if ((current->devinfo.devlist =
19841676Sjpk 			    (char *)realloc(current->devinfo.devlist,
19851676Sjpk 			    nlen)) == NULL) {
19861676Sjpk 				free(oldlist);
19871676Sjpk 				return (-1);
19881676Sjpk 			}
19891676Sjpk 			current->devinfo.devlist[0] = '\0';
19901676Sjpk 			nlen = plen = slen = 0;
19911676Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
19921676Sjpk 			    lname != NULL;
19931676Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
19941676Sjpk 				if (strcmp(lname, link) == 0)
19951676Sjpk 					continue;
19961676Sjpk 				nlen = strlen(lname) + plen + 1;
19971676Sjpk 				if (plen == 0) {
19981676Sjpk 					slen =
19991676Sjpk 					    snprintf(current->devinfo.devlist,
20004514Saj 					    nlen, "%s", lname);
20011676Sjpk 				} else {
20021676Sjpk 					slen =
20031676Sjpk 					    snprintf(current->devinfo.devlist +
20044514Saj 					    plen, nlen - plen, " %s", lname);
20051676Sjpk 				}
20061676Sjpk 				plen = plen + slen + 1;
20071676Sjpk 			}
20081676Sjpk 			free(oldlist);
20091676Sjpk 			break;
20101676Sjpk 		}
20111676Sjpk 		prev = current;
20121676Sjpk 	}
20131676Sjpk 
20141676Sjpk remove_dev:
20151676Sjpk 	if (remove_dev == 1) {
20161676Sjpk 		(void) strlcpy(devname, current->devinfo.devname, size);
20171676Sjpk 		free(current->devinfo.devname);
20181676Sjpk 		free(current->devinfo.devlist);
20191676Sjpk 		current->devinfo.devname = current->devinfo.devlist = NULL;
20201676Sjpk 		prev->next = current->next;
20211676Sjpk 		free(current);
20221676Sjpk 		current = NULL;
20231676Sjpk 	}
20241676Sjpk 	if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
20251676Sjpk 		if (prev->next) {
20261676Sjpk 			/*
20271676Sjpk 			 * what we removed above was the first entry
20281676Sjpk 			 * in the list. make the next entry to be the
20291676Sjpk 			 * first.
20301676Sjpk 			 */
20311676Sjpk 			current = prev->next;
20321676Sjpk 		} else {
20331676Sjpk 			/*
20341676Sjpk 			 * the matching entry was the only entry in the list
20351676Sjpk 			 * for this type.
20361676Sjpk 			 */
20371676Sjpk 			current = NULL;
20381676Sjpk 		}
20391676Sjpk 		if (flag & DA_AUDIO)
20401676Sjpk 			dlist->audio = current;
20411676Sjpk 		else if (flag & DA_CD)
20421676Sjpk 			dlist->cd = current;
20431676Sjpk 		else if (flag & DA_FLOPPY)
20441676Sjpk 			dlist->floppy = current;
20451676Sjpk 		else if (flag & DA_TAPE)
20461676Sjpk 			dlist->tape = current;
20471676Sjpk 		else if (flag & DA_RMDISK)
20481676Sjpk 			dlist->rmdisk = current;
20491676Sjpk 	}
20501676Sjpk 
20511676Sjpk 	return (flag);
20521676Sjpk }
20531676Sjpk 
20541676Sjpk /*
205511529SJan.Parcel@Sun.COM  * da_rm_list_entry -
205611529SJan.Parcel@Sun.COM  *
205711529SJan.Parcel@Sun.COM  *	The adding of devnames to a devlist and the removal of a
205811529SJan.Parcel@Sun.COM  *	device are not symmetrical -- hot_cleanup gives a /devices
205911529SJan.Parcel@Sun.COM  *	name which is used to remove the dentry whose links all point to
206011529SJan.Parcel@Sun.COM  *	that /devices entry.
206111529SJan.Parcel@Sun.COM  *
206211529SJan.Parcel@Sun.COM  *	The link argument is present if available to make debugging
206311529SJan.Parcel@Sun.COM  *	easier.
206411529SJan.Parcel@Sun.COM  *
206511529SJan.Parcel@Sun.COM  *	da_rm_list_entry removes an entry from the linked list of devices.
206611529SJan.Parcel@Sun.COM  *
206711529SJan.Parcel@Sun.COM  *	Returns 1 if the devname was removed successfully,
206811529SJan.Parcel@Sun.COM  *	0 if not found, -1 for error.
206911529SJan.Parcel@Sun.COM  */
207011529SJan.Parcel@Sun.COM /*ARGSUSED*/
207111529SJan.Parcel@Sun.COM int
da_rm_list_entry(devlist_t * dlist,char * link,int type,char * devname)207211529SJan.Parcel@Sun.COM da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname)
207311529SJan.Parcel@Sun.COM {
207411529SJan.Parcel@Sun.COM 	int		retval = 0;
207511529SJan.Parcel@Sun.COM 	deventry_t	**dentry, *current, *prev;
207611529SJan.Parcel@Sun.COM 
207711529SJan.Parcel@Sun.COM 	switch (type) {
207811529SJan.Parcel@Sun.COM 	case DA_AUDIO:
207911529SJan.Parcel@Sun.COM 		dentry = &(dlist->audio);
208011529SJan.Parcel@Sun.COM 		break;
208111529SJan.Parcel@Sun.COM 	case DA_CD:
208211529SJan.Parcel@Sun.COM 		dentry = &(dlist->cd);
208311529SJan.Parcel@Sun.COM 		break;
208411529SJan.Parcel@Sun.COM 	case DA_FLOPPY:
208511529SJan.Parcel@Sun.COM 		dentry = &(dlist->floppy);
208611529SJan.Parcel@Sun.COM 		break;
208711529SJan.Parcel@Sun.COM 	case DA_TAPE:
208811529SJan.Parcel@Sun.COM 		dentry = &(dlist->tape);
208911529SJan.Parcel@Sun.COM 		break;
209011529SJan.Parcel@Sun.COM 	case DA_RMDISK:
209111529SJan.Parcel@Sun.COM 		dentry = &(dlist->rmdisk);
209211529SJan.Parcel@Sun.COM 		break;
209311529SJan.Parcel@Sun.COM 	default:
209411529SJan.Parcel@Sun.COM 		return (-1);
209511529SJan.Parcel@Sun.COM 	}
209611529SJan.Parcel@Sun.COM 
209711529SJan.Parcel@Sun.COM 	/* Presumably in daemon mode, no need to remove entry, list is empty */
209811529SJan.Parcel@Sun.COM 	if (*dentry == (deventry_t *)NULL)
209911529SJan.Parcel@Sun.COM 		return (0);
210011529SJan.Parcel@Sun.COM 
210111529SJan.Parcel@Sun.COM 	prev = NULL;
210211529SJan.Parcel@Sun.COM 	for (current = *dentry; current != NULL;
210311529SJan.Parcel@Sun.COM 	    prev = current, current = current->next) {
210411529SJan.Parcel@Sun.COM 		if (strcmp(devname, current->devinfo.devname))
210511529SJan.Parcel@Sun.COM 			continue;
210611529SJan.Parcel@Sun.COM 		retval = 1;
210711529SJan.Parcel@Sun.COM 		break;
210811529SJan.Parcel@Sun.COM 	}
210911529SJan.Parcel@Sun.COM 	if (retval == 0)
211011529SJan.Parcel@Sun.COM 		return (0);
211111529SJan.Parcel@Sun.COM 	free(current->devinfo.devname);
211211529SJan.Parcel@Sun.COM 	if (current->devinfo.devlist != NULL)
211311529SJan.Parcel@Sun.COM 		free(current->devinfo.devlist);
211411529SJan.Parcel@Sun.COM 	if (current->devinfo.devopts != NULL)
211511529SJan.Parcel@Sun.COM 		free(current->devinfo.devopts);
211611529SJan.Parcel@Sun.COM 
211711529SJan.Parcel@Sun.COM 	if (prev == NULL)
211811529SJan.Parcel@Sun.COM 		*dentry = current->next;
211911529SJan.Parcel@Sun.COM 	else
212011529SJan.Parcel@Sun.COM 		prev->next = current->next;
212111529SJan.Parcel@Sun.COM 
212211529SJan.Parcel@Sun.COM 	free(current);
212311529SJan.Parcel@Sun.COM 	return (retval);
212411529SJan.Parcel@Sun.COM }
212511529SJan.Parcel@Sun.COM 
212611529SJan.Parcel@Sun.COM /*
21271676Sjpk  * da_is_on -
21281676Sjpk  *	checks if device allocation feature is turned on.
21291676Sjpk  *	returns 1 if on, 0 if off, -1 if status string not
21301676Sjpk  *	found in device_allocate.
21311676Sjpk  */
21321676Sjpk int
da_is_on()21331676Sjpk da_is_on()
21341676Sjpk {
21351676Sjpk 	return (getdaon());
21361676Sjpk }
21371676Sjpk 
21381676Sjpk /*
21391676Sjpk  * da_print_device -
21401676Sjpk  *	debug routine to print device entries.
21411676Sjpk  */
21421676Sjpk void
da_print_device(int flag,devlist_t * devlist)21431676Sjpk da_print_device(int flag, devlist_t *devlist)
21441676Sjpk {
21451676Sjpk 	deventry_t	*entry, *dentry;
21461676Sjpk 	devinfo_t	*devinfo;
21471676Sjpk 
21481676Sjpk 	if (flag & DA_AUDIO)
21491676Sjpk 		dentry = devlist->audio;
21501676Sjpk 	else if (flag & DA_CD)
21511676Sjpk 		dentry = devlist->cd;
21521676Sjpk 	else if (flag & DA_FLOPPY)
21531676Sjpk 		dentry = devlist->floppy;
21541676Sjpk 	else if (flag & DA_TAPE)
21551676Sjpk 		dentry = devlist->tape;
21561676Sjpk 	else if (flag & DA_RMDISK)
21571676Sjpk 		dentry = devlist->rmdisk;
21581676Sjpk 	else
21591676Sjpk 		return;
21601676Sjpk 
21611676Sjpk 	for (entry = dentry; entry != NULL; entry = entry->next) {
21621676Sjpk 		devinfo = &(entry->devinfo);
21631676Sjpk 		(void) fprintf(stdout, "name: %s\n", devinfo->devname);
21641676Sjpk 		(void) fprintf(stdout, "type: %s\n", devinfo->devtype);
21651676Sjpk 		(void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
21661676Sjpk 		(void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
21671676Sjpk 		(void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);
21681676Sjpk 	}
21691676Sjpk }
2170