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*11529SJan.Parcel@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
241676Sjpk  * Use is subject to license terms.
251676Sjpk  */
261676Sjpk 
271676Sjpk #include <stdlib.h>
281676Sjpk #include <ctype.h>
291676Sjpk #include <unistd.h>
301676Sjpk #include <limits.h>
311676Sjpk #include <fcntl.h>
321676Sjpk #include <sys/types.h>
331676Sjpk #include <sys/stat.h>
341676Sjpk #include <utime.h>
351676Sjpk #include <synch.h>
361676Sjpk #include <strings.h>
371676Sjpk #include <string.h>
381676Sjpk #include <libintl.h>
391676Sjpk #include <errno.h>
401676Sjpk #include <auth_list.h>
41*11529SJan.Parcel@Sun.COM #include <syslog.h>
421676Sjpk #include <bsm/devices.h>
431676Sjpk #include <bsm/devalloc.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 *);
55*11529SJan.Parcel@Sun.COM extern int dmap_matchtype(devmap_t *dmap, char *type);
56*11529SJan.Parcel@Sun.COM extern int dmap_matchdev(devmap_t *dmap, char *dev);
57*11529SJan.Parcel@Sun.COM extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num);
58*11529SJan.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
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
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
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
338*11529SJan.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 *
362*11529SJan.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);
368*11529SJan.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
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
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 *
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
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 *
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
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*11529SJan.Parcel@Sun.COM  * _rebuild_lists -
569*11529SJan.Parcel@Sun.COM  *
570*11529SJan.Parcel@Sun.COM  *      If dargs->optflag & DA_EVENT, does not assume the dargs list is
571*11529SJan.Parcel@Sun.COM  *      complete or completely believable, since devfsadm caches
572*11529SJan.Parcel@Sun.COM  *      ONLY what it has been exposed to via syseventd.
573*11529SJan.Parcel@Sun.COM  *
574*11529SJan.Parcel@Sun.COM  *	Cycles through all the entries in the /etc files, stores them
575*11529SJan.Parcel@Sun.COM  *      in memory, takes note of device->dname numbers (i.e. rmdisk0,
576*11529SJan.Parcel@Sun.COM  *      rmdisk12)
577*11529SJan.Parcel@Sun.COM  *
578*11529SJan.Parcel@Sun.COM  *      Cycles through again, adds dargs entry
579*11529SJan.Parcel@Sun.COM  *	with the name tname%d (lowest unused number for the device type)
580*11529SJan.Parcel@Sun.COM  *	to the list of things for the caller to write out to a file,
581*11529SJan.Parcel@Sun.COM  *      IFF it is a new entry.
582*11529SJan.Parcel@Sun.COM  *
583*11529SJan.Parcel@Sun.COM  *      It is an error for it to already be there.
584*11529SJan.Parcel@Sun.COM  *
585*11529SJan.Parcel@Sun.COM  *	Add:
586*11529SJan.Parcel@Sun.COM  *         Returns 0 if successful and 2 on error.
587*11529SJan.Parcel@Sun.COM  *      Remove:
588*11529SJan.Parcel@Sun.COM  *         Returns 0 if not found, 1 if found,  2 on error.
589*11529SJan.Parcel@Sun.COM  */
590*11529SJan.Parcel@Sun.COM static int
591*11529SJan.Parcel@Sun.COM _rebuild_lists(da_args *dargs, strentry_t **head_devallocp,
592*11529SJan.Parcel@Sun.COM     strentry_t **head_devmapp)
593*11529SJan.Parcel@Sun.COM {
594*11529SJan.Parcel@Sun.COM 	int		rc = 0;
595*11529SJan.Parcel@Sun.COM 	devalloc_t	*devallocp;
596*11529SJan.Parcel@Sun.COM 	devmap_t	*devmapp;
597*11529SJan.Parcel@Sun.COM 	strentry_t	*tail_str;
598*11529SJan.Parcel@Sun.COM 	strentry_t	*tmp_str;
599*11529SJan.Parcel@Sun.COM 	uint64_t	tmp_bitmap = 0;
600*11529SJan.Parcel@Sun.COM 	int		tmp = 0;
601*11529SJan.Parcel@Sun.COM 	char		new_devname[DA_MAXNAME + 1];
602*11529SJan.Parcel@Sun.COM 	char		errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80];
603*11529SJan.Parcel@Sun.COM 	char		*realname;
604*11529SJan.Parcel@Sun.COM 	int		suffix = DA_MAX_DEVNO + 1;
605*11529SJan.Parcel@Sun.COM 	int		found = 0;
606*11529SJan.Parcel@Sun.COM 
607*11529SJan.Parcel@Sun.COM 	if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY))
608*11529SJan.Parcel@Sun.COM 		return (2);
609*11529SJan.Parcel@Sun.COM 
610*11529SJan.Parcel@Sun.COM 	if (dargs->optflag & DA_FORCE)
611*11529SJan.Parcel@Sun.COM 		return (2);
612*11529SJan.Parcel@Sun.COM 
613*11529SJan.Parcel@Sun.COM 	/* read both files, maps first so we can compare actual devices */
614*11529SJan.Parcel@Sun.COM 
615*11529SJan.Parcel@Sun.COM 	/* build device_maps */
616*11529SJan.Parcel@Sun.COM 	setdmapent();
617*11529SJan.Parcel@Sun.COM 	while ((devmapp = getdmapent()) != NULL) {
618*11529SJan.Parcel@Sun.COM 		if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype))
619*11529SJan.Parcel@Sun.COM 		    == 1) {
620*11529SJan.Parcel@Sun.COM 			if (dargs->optflag & DA_REMOVE) {
621*11529SJan.Parcel@Sun.COM 				if ((devmapp->dmap_devarray == NULL) ||
622*11529SJan.Parcel@Sun.COM 				    (devmapp->dmap_devarray[0] == NULL)) {
623*11529SJan.Parcel@Sun.COM 					freedmapent(devmapp);
624*11529SJan.Parcel@Sun.COM 					enddmapent();
625*11529SJan.Parcel@Sun.COM 					return (2);
626*11529SJan.Parcel@Sun.COM 				}
627*11529SJan.Parcel@Sun.COM 				realname = dmap_physname(devmapp);
628*11529SJan.Parcel@Sun.COM 				if (realname == NULL) {
629*11529SJan.Parcel@Sun.COM 					freedmapent(devmapp);
630*11529SJan.Parcel@Sun.COM 					enddmapent();
631*11529SJan.Parcel@Sun.COM 					return (2);
632*11529SJan.Parcel@Sun.COM 				}
633*11529SJan.Parcel@Sun.COM 				if (strstr(realname, dargs->devinfo->devlist)
634*11529SJan.Parcel@Sun.COM 				    != NULL) {
635*11529SJan.Parcel@Sun.COM 					if (dargs->devinfo->devname != NULL)
636*11529SJan.Parcel@Sun.COM 						free(dargs->devinfo->devname);
637*11529SJan.Parcel@Sun.COM 					dargs->devinfo->devname =
638*11529SJan.Parcel@Sun.COM 					    strdup(devmapp->dmap_devname);
639*11529SJan.Parcel@Sun.COM 					found = 1;
640*11529SJan.Parcel@Sun.COM 					freedmapent(devmapp);
641*11529SJan.Parcel@Sun.COM 					continue; /* don't retain */
642*11529SJan.Parcel@Sun.COM 				}
643*11529SJan.Parcel@Sun.COM 			} else if (dargs->optflag & DA_ADD) {
644*11529SJan.Parcel@Sun.COM 				/*
645*11529SJan.Parcel@Sun.COM 				 * Need to know which suffixes are in use
646*11529SJan.Parcel@Sun.COM 				 */
647*11529SJan.Parcel@Sun.COM 				rc = (dmap_exact_dev(devmapp,
648*11529SJan.Parcel@Sun.COM 				    dargs->devinfo->devlist, &suffix));
649*11529SJan.Parcel@Sun.COM 
650*11529SJan.Parcel@Sun.COM 				if (rc == 0) {
651*11529SJan.Parcel@Sun.COM 					/*
652*11529SJan.Parcel@Sun.COM 					 * Same type, different device.  Record
653*11529SJan.Parcel@Sun.COM 					 * device suffix already in use.
654*11529SJan.Parcel@Sun.COM 					 */
655*11529SJan.Parcel@Sun.COM 					if (suffix > DA_MAX_DEVNO) {
656*11529SJan.Parcel@Sun.COM 						freedmapent(devmapp);
657*11529SJan.Parcel@Sun.COM 						enddmapent();
658*11529SJan.Parcel@Sun.COM 						return (2);
659*11529SJan.Parcel@Sun.COM 					}
660*11529SJan.Parcel@Sun.COM 					tmp_bitmap |= (uint64_t)(1LL << suffix);
661*11529SJan.Parcel@Sun.COM 				} else {
662*11529SJan.Parcel@Sun.COM 					/*
663*11529SJan.Parcel@Sun.COM 					 * Match on add is an error
664*11529SJan.Parcel@Sun.COM 					 * or mapping attempt returned error
665*11529SJan.Parcel@Sun.COM 					 */
666*11529SJan.Parcel@Sun.COM 					freedmapent(devmapp);
667*11529SJan.Parcel@Sun.COM 					enddmapent();
668*11529SJan.Parcel@Sun.COM 					return (2);
669*11529SJan.Parcel@Sun.COM 				}
670*11529SJan.Parcel@Sun.COM 			} else
671*11529SJan.Parcel@Sun.COM 				/* add other transaction types as needed */
672*11529SJan.Parcel@Sun.COM 				return (2);
673*11529SJan.Parcel@Sun.COM 
674*11529SJan.Parcel@Sun.COM 		}  /* if same type */
675*11529SJan.Parcel@Sun.COM 
676*11529SJan.Parcel@Sun.COM 		tmp_str = _dmap2strentry(devmapp);
677*11529SJan.Parcel@Sun.COM 		if (tmp_str == NULL) {
678*11529SJan.Parcel@Sun.COM 			freedmapent(devmapp);
679*11529SJan.Parcel@Sun.COM 			enddmapent();
680*11529SJan.Parcel@Sun.COM 			return (2);
681*11529SJan.Parcel@Sun.COM 		}
682*11529SJan.Parcel@Sun.COM 		/* retaining devmap entry: tmp_str->se_str */
683*11529SJan.Parcel@Sun.COM 		tmp_str->se_next = NULL;
684*11529SJan.Parcel@Sun.COM 		if (*head_devmapp == NULL) {
685*11529SJan.Parcel@Sun.COM 			*head_devmapp = tail_str = tmp_str;
686*11529SJan.Parcel@Sun.COM 		} else {
687*11529SJan.Parcel@Sun.COM 			tail_str->se_next = tmp_str;
688*11529SJan.Parcel@Sun.COM 			tail_str = tmp_str;
689*11529SJan.Parcel@Sun.COM 		}
690*11529SJan.Parcel@Sun.COM 		freedmapent(devmapp);
691*11529SJan.Parcel@Sun.COM 	}
692*11529SJan.Parcel@Sun.COM 	enddmapent();
693*11529SJan.Parcel@Sun.COM 
694*11529SJan.Parcel@Sun.COM 	/*
695*11529SJan.Parcel@Sun.COM 	 * No need to rewrite the files if the item to be removed is not
696*11529SJan.Parcel@Sun.COM 	 * in the files -- wait for another call on another darg.
697*11529SJan.Parcel@Sun.COM 	 */
698*11529SJan.Parcel@Sun.COM 	if ((dargs->optflag & DA_REMOVE) && !found)
699*11529SJan.Parcel@Sun.COM 		return (0);
700*11529SJan.Parcel@Sun.COM 
701*11529SJan.Parcel@Sun.COM 
702*11529SJan.Parcel@Sun.COM 	if (dargs->optflag & DA_ADD) {
703*11529SJan.Parcel@Sun.COM 		/*
704*11529SJan.Parcel@Sun.COM 		 * Since we got here from an event, we know the stored
705*11529SJan.Parcel@Sun.COM 		 * devname is a useless guess, since the files had not
706*11529SJan.Parcel@Sun.COM 		 * been read when the name was chosen, and we don't keep
707*11529SJan.Parcel@Sun.COM 		 * them anywhere else that is sufficiently definitive.
708*11529SJan.Parcel@Sun.COM 		 */
709*11529SJan.Parcel@Sun.COM 
710*11529SJan.Parcel@Sun.COM 		for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++)
711*11529SJan.Parcel@Sun.COM 			if (!(tmp_bitmap & (1LL << tmp)))
712*11529SJan.Parcel@Sun.COM 				break;
713*11529SJan.Parcel@Sun.COM 		/* Future: support more than 64 hotplug devices per type? */
714*11529SJan.Parcel@Sun.COM 		if (tmp > DA_MAX_DEVNO)
715*11529SJan.Parcel@Sun.COM 			return (2);
716*11529SJan.Parcel@Sun.COM 
717*11529SJan.Parcel@Sun.COM 		(void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u",
718*11529SJan.Parcel@Sun.COM 		    dargs->devinfo->devtype, tmp);
719*11529SJan.Parcel@Sun.COM 		if (dargs->devinfo->devname != NULL)
720*11529SJan.Parcel@Sun.COM 			free(dargs->devinfo->devname);
721*11529SJan.Parcel@Sun.COM 		dargs->devinfo->devname = strdup(new_devname);
722*11529SJan.Parcel@Sun.COM 	}
723*11529SJan.Parcel@Sun.COM 
724*11529SJan.Parcel@Sun.COM 	/*
725*11529SJan.Parcel@Sun.COM 	 * Now adjust devalloc list to match devmaps
726*11529SJan.Parcel@Sun.COM 	 * Note we now have the correct devname for da_match to use.
727*11529SJan.Parcel@Sun.COM 	 */
728*11529SJan.Parcel@Sun.COM 	setdaent();
729*11529SJan.Parcel@Sun.COM 	while ((devallocp = getdaent()) != NULL) {
730*11529SJan.Parcel@Sun.COM 		rc = da_match(devallocp, dargs);
731*11529SJan.Parcel@Sun.COM 		if (rc == 1) {
732*11529SJan.Parcel@Sun.COM 			if (dargs->optflag & DA_ADD) {
733*11529SJan.Parcel@Sun.COM 				/* logging is on if DA_EVENT is set */
734*11529SJan.Parcel@Sun.COM 				if (dargs->optflag & DA_EVENT) {
735*11529SJan.Parcel@Sun.COM 					(void) snprintf(errmsg, sizeof (errmsg),
736*11529SJan.Parcel@Sun.COM 					    "%s and %s out of sync,"
737*11529SJan.Parcel@Sun.COM 					    "%s only in %s.",
738*11529SJan.Parcel@Sun.COM 					    DEVALLOC, DEVMAP,
739*11529SJan.Parcel@Sun.COM 					    devallocp->da_devname, DEVALLOC);
740*11529SJan.Parcel@Sun.COM 					syslog(LOG_ERR, "%s", errmsg);
741*11529SJan.Parcel@Sun.COM 				}
742*11529SJan.Parcel@Sun.COM 				freedaent(devallocp);
743*11529SJan.Parcel@Sun.COM 				enddaent();
744*11529SJan.Parcel@Sun.COM 				return (2);
745*11529SJan.Parcel@Sun.COM 			} else if (dargs->optflag & DA_REMOVE) {
746*11529SJan.Parcel@Sun.COM 				/* make list w/o this entry */
747*11529SJan.Parcel@Sun.COM 				freedaent(devallocp);
748*11529SJan.Parcel@Sun.COM 				continue;
749*11529SJan.Parcel@Sun.COM 			}
750*11529SJan.Parcel@Sun.COM 		}
751*11529SJan.Parcel@Sun.COM 		tmp_str = _da2strentry(dargs, devallocp);
752*11529SJan.Parcel@Sun.COM 		if (tmp_str == NULL) {
753*11529SJan.Parcel@Sun.COM 			freedaent(devallocp);
754*11529SJan.Parcel@Sun.COM 			enddaent();
755*11529SJan.Parcel@Sun.COM 			return (2);
756*11529SJan.Parcel@Sun.COM 		}
757*11529SJan.Parcel@Sun.COM 		/* retaining devalloc entry: tmp_str->se_str */
758*11529SJan.Parcel@Sun.COM 		tmp_str->se_next = NULL;
759*11529SJan.Parcel@Sun.COM 		if (*head_devallocp == NULL) {
760*11529SJan.Parcel@Sun.COM 			*head_devallocp = tail_str = tmp_str;
761*11529SJan.Parcel@Sun.COM 		} else {
762*11529SJan.Parcel@Sun.COM 			tail_str->se_next = tmp_str;
763*11529SJan.Parcel@Sun.COM 			tail_str = tmp_str;
764*11529SJan.Parcel@Sun.COM 		}
765*11529SJan.Parcel@Sun.COM 		freedaent(devallocp);
766*11529SJan.Parcel@Sun.COM 	}
767*11529SJan.Parcel@Sun.COM 	enddaent();
768*11529SJan.Parcel@Sun.COM 
769*11529SJan.Parcel@Sun.COM 	/* the caller needs to know if a remove needs to rewrite files */
770*11529SJan.Parcel@Sun.COM 	if (dargs->optflag & DA_REMOVE)
771*11529SJan.Parcel@Sun.COM 		return (1);  /* 0 and 2 cases returned earlier */
772*11529SJan.Parcel@Sun.COM 
773*11529SJan.Parcel@Sun.COM 	return (0);  /* Successful DA_ADD */
774*11529SJan.Parcel@Sun.COM }
775*11529SJan.Parcel@Sun.COM /*
7761676Sjpk  * _build_lists -
777*11529SJan.Parcel@Sun.COM  *	Cycles through all the entries, stores them in memory. removes entries
7781676Sjpk  *	with the given search_key (device name or type).
7791676Sjpk  *	returns 0 if given entry not found, 1 if given entry removed, 2 on
7801676Sjpk  *	error.
7811676Sjpk  */
7821676Sjpk static int
7831676Sjpk _build_lists(da_args *dargs, strentry_t **head_devallocp,
7841676Sjpk     strentry_t **head_devmapp)
7851676Sjpk {
7861676Sjpk 	int		rc = 0;
7871676Sjpk 	devalloc_t	*devallocp;
7881676Sjpk 	devmap_t	*devmapp;
7891676Sjpk 	strentry_t	*tail_str;
7901676Sjpk 	strentry_t	*tmp_str;
7911676Sjpk 
7921676Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
7931676Sjpk 		goto dmap_only;
7941676Sjpk 
7951676Sjpk 	/* build device_allocate */
7961676Sjpk 	setdaent();
7971676Sjpk 	while ((devallocp = getdaent()) != NULL) {
7981676Sjpk 		rc = da_match(devallocp, dargs);
7991676Sjpk 		if (rc && dargs->optflag & DA_ADD &&
8001676Sjpk 		    !(dargs->optflag & DA_FORCE)) {
8011676Sjpk 			/*
8021676Sjpk 			 * During DA_ADD, we keep an existing entry unless
8031676Sjpk 			 * we have DA_FORCE set to override that entry.
8041676Sjpk 			 */
8051676Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
8061676Sjpk 			rc = 0;
8071676Sjpk 		}
8081676Sjpk 		if (rc == 0) {
8091676Sjpk 			tmp_str = _da2strentry(dargs, devallocp);
8101676Sjpk 			if (tmp_str == NULL) {
8111676Sjpk 				freedaent(devallocp);
8121676Sjpk 				enddaent();
8131676Sjpk 				return (2);
8141676Sjpk 			}
8151676Sjpk 			/* retaining devalloc entry: tmp_str->se_str */
8161676Sjpk 			tmp_str->se_next = NULL;
8171676Sjpk 			if (*head_devallocp == NULL) {
8181676Sjpk 				*head_devallocp = tail_str = tmp_str;
8191676Sjpk 			} else {
8201676Sjpk 				tail_str->se_next = tmp_str;
8211676Sjpk 				tail_str = tmp_str;
8221676Sjpk 			}
8231676Sjpk 		}
8241676Sjpk 		freedaent(devallocp);
8251676Sjpk 	}
8261676Sjpk 	enddaent();
8271676Sjpk 
8281676Sjpk dmap_only:
8291676Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
8301676Sjpk 		return (rc);
8311676Sjpk 
8321676Sjpk 	/* build device_maps */
8331676Sjpk 	rc = 0;
8341676Sjpk 	setdmapent();
8351676Sjpk 	while ((devmapp = getdmapent()) != NULL) {
8361676Sjpk 		rc = dm_match(devmapp, dargs);
8371676Sjpk 		if (rc && dargs->optflag & DA_ADD &&
8381676Sjpk 		    !(dargs->optflag & DA_FORCE)) {
8391676Sjpk 			/*
8401676Sjpk 			 * During DA_ADD, we keep an existing entry unless
8411676Sjpk 			 * we have DA_FORCE set to override that entry.
8421676Sjpk 			 */
8431676Sjpk 			dargs->optflag |= DA_NO_OVERRIDE;
8441676Sjpk 			rc = 0;
8451676Sjpk 		}
8461676Sjpk 		if (rc == 0) {
847*11529SJan.Parcel@Sun.COM 			tmp_str = _dmap2strentry(devmapp);
8481676Sjpk 			if (tmp_str == NULL) {
8491676Sjpk 				freedmapent(devmapp);
8501676Sjpk 				enddmapent();
8511676Sjpk 				return (2);
8521676Sjpk 			}
8531676Sjpk 			/* retaining devmap entry: tmp_str->se_str */
8541676Sjpk 			tmp_str->se_next = NULL;
8551676Sjpk 			if (*head_devmapp == NULL) {
8561676Sjpk 				*head_devmapp = tail_str = tmp_str;
8571676Sjpk 			} else {
8581676Sjpk 				tail_str->se_next = tmp_str;
8591676Sjpk 				tail_str = tmp_str;
8601676Sjpk 			}
8611676Sjpk 		}
8621676Sjpk 		freedmapent(devmapp);
8631676Sjpk 	}
8641676Sjpk 	enddmapent();
8651676Sjpk 
8661676Sjpk 	return (rc);
8671676Sjpk }
8681676Sjpk 
8691676Sjpk /*
8701676Sjpk  * _write_defattrs
8711676Sjpk  *	writes current entries to devalloc_defaults.
8721676Sjpk  */
8731676Sjpk static void
8741676Sjpk _write_defattrs(FILE *fp, strentry_t *head_defent)
8751676Sjpk {
8761676Sjpk 	strentry_t *tmp_str;
8771676Sjpk 
8781676Sjpk 	for (tmp_str = head_defent; tmp_str != NULL;
8791676Sjpk 	    tmp_str = tmp_str->se_next) {
8801676Sjpk 		(void) fputs(tmp_str->se_str, fp);
8811676Sjpk 		(void) fputs("\n", fp);
8821676Sjpk 	}
8831676Sjpk 
8841676Sjpk }
8851676Sjpk 
8861676Sjpk /*
8871676Sjpk  * _write_device_allocate -
8881676Sjpk  *	writes current entries in the list to device_allocate.
889*11529SJan.Parcel@Sun.COM  *	frees the strings
8901676Sjpk  */
8911676Sjpk static void
8921676Sjpk _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
8931676Sjpk {
8941676Sjpk 	int		is_on = -1;
895*11529SJan.Parcel@Sun.COM 	strentry_t	*tmp_str, *old_str;
8961676Sjpk 	struct stat	dastat;
8971676Sjpk 
8981676Sjpk 	(void) fseek(dafp, (off_t)0, SEEK_SET);
8991676Sjpk 
9001676Sjpk 	/*
9011676Sjpk 	 * if the devalloc on/off string existed before,
9021676Sjpk 	 * put it back before anything else.
9031676Sjpk 	 * we need to check for the string only if the file
9041676Sjpk 	 * exists.
9051676Sjpk 	 */
9061676Sjpk 	if (stat(odevalloc, &dastat) == 0) {
9071676Sjpk 		is_on = da_is_on();
9081676Sjpk 		if (is_on == 0)
9091676Sjpk 			(void) fputs(DA_OFF_STR, dafp);
9101676Sjpk 		else if (is_on == 1)
9111676Sjpk 			(void) fputs(DA_ON_STR, dafp);
9121676Sjpk 	}
9131676Sjpk 	tmp_str = head_devallocp;
9141676Sjpk 	while (tmp_str) {
9151676Sjpk 		(void) fputs(tmp_str->se_str, dafp);
9161676Sjpk 		(void) fputs("\n", dafp);
917*11529SJan.Parcel@Sun.COM 		old_str = tmp_str;
9181676Sjpk 		tmp_str = tmp_str->se_next;
919*11529SJan.Parcel@Sun.COM 		free(old_str);
9201676Sjpk 	}
9211676Sjpk }
9221676Sjpk 
9231676Sjpk /*
9241676Sjpk  * _write_device_maps -
9251676Sjpk  *	writes current entries in the list to device_maps.
926*11529SJan.Parcel@Sun.COM  *	and frees the strings
9271676Sjpk  */
9281676Sjpk static void
9291676Sjpk _write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
9301676Sjpk {
931*11529SJan.Parcel@Sun.COM 	strentry_t	*tmp_str, *old_str;
9321676Sjpk 
9331676Sjpk 	(void) fseek(dmfp, (off_t)0, SEEK_SET);
9341676Sjpk 
9351676Sjpk 	tmp_str = head_devmapp;
9361676Sjpk 	while (tmp_str) {
9371676Sjpk 		(void) fputs(tmp_str->se_str, dmfp);
9381676Sjpk 		(void) fputs("\n", dmfp);
939*11529SJan.Parcel@Sun.COM 		old_str = tmp_str;
9401676Sjpk 		tmp_str = tmp_str->se_next;
941*11529SJan.Parcel@Sun.COM 		free(old_str);
9421676Sjpk 	}
9431676Sjpk }
9441676Sjpk 
9451676Sjpk /*
9461676Sjpk  * _write_new_defattrs
9471676Sjpk  *	writes the new entry to devalloc_defaults.
9481676Sjpk  *	returns 0 on success, -1 on error.
9491676Sjpk  */
9501676Sjpk static int
9511676Sjpk _write_new_defattrs(FILE *fp, da_args *dargs)
9521676Sjpk {
9531676Sjpk 	int		count;
9541676Sjpk 	char		*tok = NULL, *tokp = NULL;
9551676Sjpk 	char		*lasts;
9561676Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
9571676Sjpk 
9581676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
9591676Sjpk 		return (-1);
9601676Sjpk 	if (!devinfo->devopts)
9611676Sjpk 		return (0);
9621676Sjpk 	(void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
9631676Sjpk 	    KV_TOKEN_DELIMIT);
964*11529SJan.Parcel@Sun.COM 	if ((tokp = (char *)malloc(strlen(devinfo->devopts) +1)) != NULL) {
9651676Sjpk 		(void) strcpy(tokp, devinfo->devopts);
9661676Sjpk 		if ((tok = strtok_r(tokp, KV_DELIMITER, &lasts)) != NULL) {
9671676Sjpk 			(void) fprintf(fp, "%s", tok);
9681676Sjpk 			count = 1;
9691676Sjpk 		}
9701676Sjpk 		while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
9711676Sjpk 			if (count)
9721676Sjpk 				(void) fprintf(fp, "%s", KV_DELIMITER);
9731676Sjpk 			(void) fprintf(fp, "%s", tok);
9741676Sjpk 			count++;
9751676Sjpk 		}
9761676Sjpk 	} else {
9771676Sjpk 		(void) fprintf(fp, "%s", devinfo->devopts);
9781676Sjpk 	}
9791676Sjpk 
9801676Sjpk 	return (0);
9811676Sjpk }
9821676Sjpk 
9831676Sjpk /*
9841676Sjpk  * _write_new_entry -
9851676Sjpk  *	writes the new devalloc_t to device_allocate or the new devmap_t to
9861676Sjpk  *	device_maps.
9871676Sjpk  *	returns 0 on success, -1 on error.
9881676Sjpk  */
9891676Sjpk static int
9901676Sjpk _write_new_entry(FILE *fp, da_args *dargs, int flag)
9911676Sjpk {
9921676Sjpk 	int		count;
9931676Sjpk 	char		*tok = NULL, *tokp = NULL;
9941676Sjpk 	char		*lasts;
9951676Sjpk 	devinfo_t	*devinfo = dargs->devinfo;
9961676Sjpk 
9971676Sjpk 	if (flag & DA_MAPS_ONLY)
9981676Sjpk 		goto dmap_only;
9991676Sjpk 
10001676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
10011676Sjpk 		return (-1);
10021676Sjpk 
10031676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
10041676Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
10051676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
10061676Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
10071676Sjpk 	if (devinfo->devopts == NULL) {
10081676Sjpk 		(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
10091676Sjpk 		    KV_DELIMITER);
10101676Sjpk 	} else {
1011*11529SJan.Parcel@Sun.COM 		if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1))
1012*11529SJan.Parcel@Sun.COM 		    != NULL) {
10131676Sjpk 			(void) strcpy(tokp, devinfo->devopts);
10141676Sjpk 			if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
10151676Sjpk 			    NULL) {
10161676Sjpk 				(void) fprintf(fp, "%s", tok);
10171676Sjpk 				count = 1;
10181676Sjpk 			}
10191676Sjpk 			while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
10201676Sjpk 			    &lasts)) != NULL) {
10211676Sjpk 				if (count)
10221676Sjpk 					(void) fprintf(fp, "%s",
10231676Sjpk 					    KV_TOKEN_DELIMIT "\\\n\t");
10241676Sjpk 				(void) fprintf(fp, "%s", tok);
10251676Sjpk 				count++;
10261676Sjpk 			}
10271676Sjpk 			if (count)
10281676Sjpk 				(void) fprintf(fp, "%s",
10291676Sjpk 				    KV_DELIMITER "\\\n\t");
10301676Sjpk 		} else {
10311676Sjpk 			(void) fprintf(fp, "%s%s", devinfo->devopts,
10321676Sjpk 			    KV_DELIMITER "\\\n\t");
10331676Sjpk 		}
10341676Sjpk 	}
10351676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
10361676Sjpk 	(void) fprintf(fp, "%s%s\\\n\t",
10371676Sjpk 	    (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
10381676Sjpk 	    KV_DELIMITER);
10391676Sjpk 	(void) fprintf(fp, "%s\n",
10401676Sjpk 	    (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
10411676Sjpk 
10421676Sjpk dmap_only:
10431676Sjpk 	if (flag & DA_ALLOC_ONLY)
10441676Sjpk 		return (0);
10451676Sjpk 
10461676Sjpk 	if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
10471676Sjpk 		return (-1);
10481676Sjpk 
10491676Sjpk 	(void) fprintf(fp, "%s%s\\\n",
10501676Sjpk 	    (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
10511676Sjpk 	(void) fprintf(fp, "\t%s%s\\\n",
10521676Sjpk 	    (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
10531676Sjpk 	(void) fprintf(fp, "\t%s\n",
10541676Sjpk 	    (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
10551676Sjpk 
10561676Sjpk 	return (0);
10571676Sjpk }
10581676Sjpk 
10591676Sjpk /*
10601676Sjpk  * _da_lock_devdb -
10611676Sjpk  *	locks the database files; lock can be either broken explicitly by
10621676Sjpk  *	closing the fd of the lock file, or it expires automatically at process
10631676Sjpk  *	termination.
10641676Sjpk  * 	returns fd of the lock file or -1 on error.
10651676Sjpk  */
10661676Sjpk int
10671676Sjpk _da_lock_devdb(char *rootdir)
10681676Sjpk {
10691676Sjpk 	int		lockfd = -1;
10704514Saj 	int		ret;
10714514Saj 	int		count = 0;
10724514Saj 	int		retry = 10;
10734514Saj 	int		retry_sleep;
10744514Saj 	uint_t		seed;
10751676Sjpk 	char		*lockfile;
10761676Sjpk 	char		path[MAXPATHLEN];
10771676Sjpk 	int		size = sizeof (path);
10781676Sjpk 
10791676Sjpk 	if (rootdir == NULL) {
10801676Sjpk 		lockfile = DA_DB_LOCK;
10811676Sjpk 	} else {
10821676Sjpk 		path[0] = '\0';
10831676Sjpk 		if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
10841676Sjpk 			return (-1);
10851676Sjpk 		lockfile = path;
10861676Sjpk 	}
10871676Sjpk 
10881676Sjpk 	if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
10891676Sjpk 		/* cannot open lock file */
10901676Sjpk 		return (-1);
10911676Sjpk 
10921676Sjpk 	(void) fchown(lockfd, DA_UID, DA_GID);
10931676Sjpk 
10941676Sjpk 	if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
10951676Sjpk 		/* cannot position lock file */
10961676Sjpk 		(void) close(lockfd);
10971676Sjpk 		return (-1);
10981676Sjpk 	}
10994514Saj 	errno = 0;
11004514Saj 	while (retry > 0) {
11014514Saj 		count++;
11024514Saj 		seed = (uint_t)gethrtime();
11034514Saj 		ret = lockf(lockfd, F_TLOCK, 0);
11044514Saj 		if (ret == 0) {
11054514Saj 			(void) utime(lockfile, NULL);
11064514Saj 			return (lockfd);
11074514Saj 		}
11084514Saj 		if ((errno != EACCES) && (errno != EAGAIN)) {
11094514Saj 			/* cannot set lock */
11104514Saj 			(void) close(lockfd);
11114514Saj 			return (-1);
11124514Saj 		}
11134514Saj 		retry--;
11144514Saj 		retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count;
11154514Saj 		(void) sleep(retry_sleep);
11164514Saj 		errno = 0;
11171676Sjpk 	}
11181676Sjpk 
11194514Saj 	return (-1);
11201676Sjpk }
11211676Sjpk 
11221676Sjpk /*
11231676Sjpk  * da_open_devdb -
11241676Sjpk  *	opens one or both database files - device_allocate, device_maps - in
11251676Sjpk  *	the specified mode.
11261676Sjpk  *	locks the database files; lock is either broken explicitly by the
11271676Sjpk  *	caller by closing the lock file fd, or it expires automatically at
11281676Sjpk  *	process termination.
11291676Sjpk  *	writes the file pointer of opened file in the input args - dafp, dmfp.
11301676Sjpk  *	returns fd of the lock file on success, -2 if database file does not
11311676Sjpk  *	exist, -1 on other errors.
11321676Sjpk  */
11331676Sjpk int
11341676Sjpk da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
11351676Sjpk {
11361676Sjpk 	int	oflag = 0;
11371676Sjpk 	int	fda = -1;
11381676Sjpk 	int	fdm = -1;
11391676Sjpk 	int	lockfd = -1;
11401676Sjpk 	char	*fname;
11411676Sjpk 	char	*fmode;
11421676Sjpk 	char	path[MAXPATHLEN];
11431676Sjpk 	FILE	*devfile;
11441676Sjpk 
11451676Sjpk 	if ((dafp == NULL) && (dmfp == NULL))
11461676Sjpk 		return (-1);
11471676Sjpk 
11481676Sjpk 	if (flag & DA_RDWR) {
11491676Sjpk 		oflag = DA_RDWR;
11501914Scasper 		fmode = "r+F";
11511676Sjpk 	} else if (flag & DA_RDONLY) {
11521676Sjpk 		oflag = DA_RDONLY;
11531914Scasper 		fmode = "rF";
11541676Sjpk 	}
11551676Sjpk 
11561676Sjpk 	if ((lockfd = _da_lock_devdb(rootdir)) == -1)
11571676Sjpk 		return (-1);
11581676Sjpk 
11591676Sjpk 	if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
11601676Sjpk 		goto dmap_only;
11611676Sjpk 
11621676Sjpk 	path[0] = '\0';
11631676Sjpk 
11641676Sjpk 	/*
11651676Sjpk 	 * open the device allocation file
11661676Sjpk 	 */
11671676Sjpk 	if (rootdir == NULL) {
11681676Sjpk 		fname = DEVALLOC;
11691676Sjpk 	} else {
11701676Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
11711676Sjpk 		    DEVALLOC) >= sizeof (path)) {
11721676Sjpk 			if (lockfd != -1)
11731676Sjpk 				(void) close(lockfd);
11741676Sjpk 			return (-1);
11751676Sjpk 		}
11761676Sjpk 		fname = path;
11771676Sjpk 	}
11781676Sjpk 	if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
11791676Sjpk 		if (lockfd != -1)
11801676Sjpk 			(void) close(lockfd);
11811676Sjpk 		return ((errno == ENOENT) ? -2 : -1);
11821676Sjpk 	}
11831676Sjpk 	if ((devfile = fdopen(fda, fmode)) == NULL) {
11841676Sjpk 		(void) close(fda);
11851676Sjpk 		if (lockfd != -1)
11861676Sjpk 			(void) close(lockfd);
11871676Sjpk 		return (-1);
11881676Sjpk 	}
11891676Sjpk 	*dafp = devfile;
11901676Sjpk 	(void) fchmod(fda, DA_DBMODE);
11911676Sjpk 
11921676Sjpk 	if ((flag & DA_ALLOC_ONLY))
11931676Sjpk 		goto out;
11941676Sjpk 
11951676Sjpk dmap_only:
11961676Sjpk 	path[0] = '\0';
11971676Sjpk 	/*
11981676Sjpk 	 * open the device map file
11991676Sjpk 	 */
12001676Sjpk 	if (rootdir == NULL) {
12011676Sjpk 		fname = DEVMAP;
12021676Sjpk 	} else {
12031676Sjpk 		if (snprintf(path, sizeof (path), "%s%s", rootdir,
12041676Sjpk 		    DEVMAP) >= sizeof (path)) {
12051676Sjpk 			(void) close(fda);
12061676Sjpk 			if (lockfd != -1)
12071676Sjpk 				(void) close(lockfd);
12081676Sjpk 			return (-1);
12091676Sjpk 		}
12101676Sjpk 		fname = path;
12111676Sjpk 	}
12121676Sjpk 
12131676Sjpk 	if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
12141676Sjpk 		if (lockfd != -1)
12151676Sjpk 			(void) close(lockfd);
12161676Sjpk 		return ((errno == ENOENT) ? -2 : -1);
12171676Sjpk 	}
12181676Sjpk 
12191676Sjpk 	if ((devfile = fdopen(fdm, fmode)) == NULL) {
12201676Sjpk 		(void) close(fdm);
12211676Sjpk 		(void) close(fda);
12221676Sjpk 		if (lockfd != -1)
12231676Sjpk 			(void) close(lockfd);
12241676Sjpk 		return (-1);
12251676Sjpk 	}
12261676Sjpk 	*dmfp = devfile;
12271676Sjpk 	(void) fchmod(fdm, DA_DBMODE);
12281676Sjpk 
12291676Sjpk out:
12301676Sjpk 	return (lockfd);
12311676Sjpk }
12321676Sjpk 
12331676Sjpk /*
12341676Sjpk  * _record_on_off -
12351676Sjpk  *	adds either DA_ON_STR or DA_OFF_STR to device_allocate
12361676Sjpk  *	returns 0 on success, -1 on error.
12371676Sjpk  */
12381676Sjpk static int
12391676Sjpk _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
12401676Sjpk {
12411676Sjpk 	int		dafd;
12421676Sjpk 	int		nsize;
12431676Sjpk 	int		nitems = 1;
12441676Sjpk 	int		actionlen;
12451676Sjpk 	int		str_found = 0;
12461676Sjpk 	int		len = 0, nlen = 0, plen = 0;
12471676Sjpk 	char		*ptr = NULL;
12481676Sjpk 	char		*actionstr;
12491676Sjpk 	char		*nbuf = NULL;
12501676Sjpk 	char		line[MAX_CANON];
12511676Sjpk 	struct stat	dastat;
12521676Sjpk 
12531676Sjpk 	if (dargs->optflag & DA_ON)
12541676Sjpk 		actionstr = DA_ON_STR;
12551676Sjpk 	else
12561676Sjpk 		actionstr = DA_OFF_STR;
12571676Sjpk 	actionlen = strlen(actionstr);
12581676Sjpk 	dafd = fileno(dafp);
12591676Sjpk 	if (fstat(dafd, &dastat) == -1)
12601676Sjpk 		return (-1);
12611676Sjpk 
12621676Sjpk 	/* check the old device_allocate for on/off string */
12631676Sjpk 	ptr = fgets(line, MAX_CANON, dafp);
12641676Sjpk 	if (ptr != NULL) {
12651676Sjpk 		if ((strcmp(line, DA_ON_STR) == 0) ||
12661676Sjpk 		    (strcmp(line, DA_OFF_STR) == 0)) {
12671676Sjpk 			str_found = 1;
12681676Sjpk 			nsize = dastat.st_size;
12691676Sjpk 		}
12701676Sjpk 	}
12711676Sjpk 	if (!ptr || !str_found) {
12721676Sjpk 		/*
12731676Sjpk 		 * the file never had either the on or the off string;
12741676Sjpk 		 * make room for it.
12751676Sjpk 		 */
12761676Sjpk 		str_found = 0;
12771676Sjpk 		nsize = dastat.st_size + actionlen + 1;
12781676Sjpk 	}
1279*11529SJan.Parcel@Sun.COM 	if ((nbuf = (char *)malloc(nsize + 1)) == NULL)
12801676Sjpk 		return (-1);
12811676Sjpk 	nbuf[0] = '\0';
12821676Sjpk 	/* put the on/off string */
12831676Sjpk 	(void) strcpy(nbuf, actionstr);
12841676Sjpk 	nlen = strlen(nbuf);
12851676Sjpk 	plen = nlen;
12861676Sjpk 	if (ptr && !str_found) {
12871676Sjpk 		/* now put the first line that we read in fgets */
12881676Sjpk 		nlen = plen + strlen(line) + 1;
12891676Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
12901676Sjpk 		if (len >= nsize) {
12911676Sjpk 			free(nbuf);
12921676Sjpk 			return (-1);
12931676Sjpk 		}
12941676Sjpk 		plen += len;
12951676Sjpk 	}
12961676Sjpk 
12971676Sjpk 	/* now get the rest of the old file */
12981676Sjpk 	while (fgets(line, MAX_CANON, dafp) != NULL) {
12991676Sjpk 		nlen = plen + strlen(line) + 1;
13001676Sjpk 		len = snprintf(nbuf + plen, nlen - plen, "%s", line);
13011676Sjpk 		if (len >= nsize) {
13021676Sjpk 			free(nbuf);
13031676Sjpk 			return (-1);
13041676Sjpk 		}
13051676Sjpk 		plen += len;
13061676Sjpk 	}
13071676Sjpk 	len = strlen(nbuf) + 1;
13081676Sjpk 	if (len < nsize)
13091676Sjpk 		nbuf[len] = '\n';
13101676Sjpk 
13111676Sjpk 	/* write the on/off str + the old device_allocate to the temp file */
13121676Sjpk 	if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
13131676Sjpk 		free(nbuf);
13141676Sjpk 		return (-1);
13151676Sjpk 	}
13161676Sjpk 
13171676Sjpk 	free(nbuf);
13181676Sjpk 
13191676Sjpk 	return (0);
13201676Sjpk }
13211676Sjpk 
13221676Sjpk /*
13231676Sjpk  * da_update_defattrs -
13241676Sjpk  *	writes default attributes to devalloc_defaults
13251676Sjpk  *	returns 0 on success, -1 on error.
13261676Sjpk  */
13271676Sjpk int
13281676Sjpk da_update_defattrs(da_args *dargs)
13291676Sjpk {
13301676Sjpk 	int		rc = 0, lockfd = 0, tmpfd = 0;
13311676Sjpk 	char		*defpath = DEFATTRS;
13321676Sjpk 	char		*tmpdefpath = TMPATTRS;
13331676Sjpk 	FILE		*tmpfp = NULL;
13341676Sjpk 	struct stat	dstat;
13351676Sjpk 	strentry_t	*head_defent = NULL;
13361676Sjpk 
13371676Sjpk 	if (dargs == NULL)
13381676Sjpk 		return (0);
13391676Sjpk 	if ((lockfd = _da_lock_devdb(NULL)) == -1)
13401676Sjpk 		return (-1);
13411676Sjpk 	if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
13421676Sjpk 		(void) close(lockfd);
13431676Sjpk 		return (-1);
13441676Sjpk 	}
13451676Sjpk 	(void) fchown(tmpfd, DA_UID, DA_GID);
13461676Sjpk 	if ((tmpfp = fdopen(tmpfd, "r+")) == NULL) {
13471676Sjpk 		(void) close(tmpfd);
13481676Sjpk 		(void) unlink(tmpdefpath);
13491676Sjpk 		(void) close(lockfd);
13501676Sjpk 		return (-1);
13511676Sjpk 	}
13521676Sjpk 	/*
13531676Sjpk 	 * examine all entries, remove an old one if required, check
13541676Sjpk 	 * if a new one needs to be added.
13551676Sjpk 	 */
13561676Sjpk 	if (stat(defpath, &dstat) == 0) {
13571676Sjpk 		if ((rc = _build_defattrs(dargs, &head_defent)) != 0) {
13581676Sjpk 			if (rc == 1) {
13591676Sjpk 				(void) close(tmpfd);
13601676Sjpk 				(void) unlink(tmpdefpath);
13611676Sjpk 				(void) close(lockfd);
13621676Sjpk 				return (rc);
13631676Sjpk 			}
13641676Sjpk 		}
13651676Sjpk 	}
13661676Sjpk 	/*
13671676Sjpk 	 * write back any existing entries.
13681676Sjpk 	 */
13691676Sjpk 	_write_defattrs(tmpfp, head_defent);
13701676Sjpk 
13711676Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
13721676Sjpk 		/* add new entries */
13731676Sjpk 		rc = _write_new_defattrs(tmpfp, dargs);
13741676Sjpk 		(void) fclose(tmpfp);
13751676Sjpk 	} else {
13761676Sjpk 		(void) fclose(tmpfp);
13771676Sjpk 	}
13781676Sjpk 	if (rename(tmpdefpath, defpath) != 0) {
13791676Sjpk 		rc = -1;
13801676Sjpk 		(void) unlink(tmpdefpath);
13811676Sjpk 	}
13821676Sjpk 	(void) close(lockfd);
13831676Sjpk 
13841676Sjpk 	return (rc);
13851676Sjpk }
13861676Sjpk 
13871676Sjpk /*
13881676Sjpk  * da_update_device -
1389*11529SJan.Parcel@Sun.COM  *	Writes existing entries and the SINGLE change requested by da_args,
1390*11529SJan.Parcel@Sun.COM  *      to device_allocate and device_maps.
1391*11529SJan.Parcel@Sun.COM  * 	Returns 0 on success, -1 on error.
13921676Sjpk  */
13931676Sjpk int
13941676Sjpk da_update_device(da_args *dargs)
13951676Sjpk {
13961676Sjpk 	int		rc;
13971676Sjpk 	int		tafd = -1, tmfd = -1;
13981676Sjpk 	int		lockfd = -1;
13991676Sjpk 	char		*rootdir = NULL;
14004514Saj 	char		*apathp = NULL, *mpathp = NULL;
14014514Saj 	char		*dapathp = NULL, *dmpathp = NULL;
14024514Saj 	char		apath[MAXPATHLEN], mpath[MAXPATHLEN];
14034514Saj 	char		dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
14041676Sjpk 	FILE		*tafp = NULL, *tmfp = NULL, *dafp = NULL;
14051676Sjpk 	struct stat	dastat;
14061676Sjpk 	devinfo_t	*devinfo;
14071676Sjpk 	strentry_t	*head_devmapp = NULL;
14081676Sjpk 	strentry_t	*head_devallocp = NULL;
14091676Sjpk 
14101676Sjpk 	if (dargs == NULL)
14111676Sjpk 		return (0);
14121676Sjpk 
14131676Sjpk 	rootdir = dargs->rootdir;
14141676Sjpk 	devinfo = dargs->devinfo;
14151676Sjpk 
14161676Sjpk 	/*
14171676Sjpk 	 * adding/removing entries should be done in both
14181676Sjpk 	 * device_allocate and device_maps. updates can be
14191676Sjpk 	 * done in both or either of the files.
14201676Sjpk 	 */
14211676Sjpk 	if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
14221676Sjpk 		if (dargs->optflag & DA_ALLOC_ONLY ||
14231676Sjpk 		    dargs->optflag & DA_MAPS_ONLY)
14241676Sjpk 			return (0);
14251676Sjpk 	}
14261676Sjpk 
14271676Sjpk 	/*
14281676Sjpk 	 * name, type and list are required fields for adding a new
14291676Sjpk 	 * device.
14301676Sjpk 	 */
14311676Sjpk 	if ((dargs->optflag & DA_ADD) &&
14321676Sjpk 	    ((devinfo->devname == NULL) ||
14331676Sjpk 	    (devinfo->devtype == NULL) ||
14341676Sjpk 	    (devinfo->devlist == NULL))) {
14351676Sjpk 		return (-1);
14361676Sjpk 	}
14371676Sjpk 
14381676Sjpk 	if (rootdir != NULL) {
14391676Sjpk 		if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
14401676Sjpk 		    TMPALLOC) >= sizeof (apath))
14411676Sjpk 			return (-1);
14421676Sjpk 		apathp = apath;
14431676Sjpk 		if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
14441676Sjpk 		    DEVALLOC) >= sizeof (dapath))
14451676Sjpk 			return (-1);
14461676Sjpk 		dapathp = dapath;
14471676Sjpk 		if (!(dargs->optflag & DA_ALLOC_ONLY)) {
14481676Sjpk 			if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
14491676Sjpk 			    TMPMAP) >= sizeof (mpath))
14501676Sjpk 				return (-1);
14511676Sjpk 			mpathp = mpath;
14521676Sjpk 			if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
14531676Sjpk 			    DEVMAP) >= sizeof (dmpath))
14541676Sjpk 				return (-1);
14551676Sjpk 			dmpathp = dmpath;
14561676Sjpk 		}
14571676Sjpk 	} else {
14581676Sjpk 		apathp = TMPALLOC;
14591676Sjpk 		dapathp = DEVALLOC;
14601676Sjpk 		mpathp = TMPMAP;
14611676Sjpk 		dmpathp = DEVMAP;
14621676Sjpk 	}
14631676Sjpk 
14641676Sjpk 	if (dargs->optflag & DA_MAPS_ONLY)
14651676Sjpk 		goto dmap_only;
14661676Sjpk 
14671676Sjpk 	/*
14681676Sjpk 	 * Check if we are here just to record on/off status of
14691676Sjpk 	 * device_allocation.
14701676Sjpk 	 */
14711676Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
14721676Sjpk 		lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
14731676Sjpk 		    DA_RDONLY|DA_ALLOC_ONLY);
14741676Sjpk 	else
14751676Sjpk 		lockfd = _da_lock_devdb(rootdir);
14761676Sjpk 	if (lockfd == -1)
14771676Sjpk 		return (-1);
14781676Sjpk 
14791676Sjpk 	if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
14801676Sjpk 		(void) close(lockfd);
14811676Sjpk 		(void) fclose(dafp);
14821676Sjpk 		return (-1);
14831676Sjpk 	}
14841676Sjpk 	(void) fchown(tafd, DA_UID, DA_GID);
14851676Sjpk 	if ((tafp = fdopen(tafd, "r+")) == NULL) {
14861676Sjpk 		(void) close(tafd);
14871676Sjpk 		(void) unlink(apathp);
14881676Sjpk 		(void) fclose(dafp);
14891676Sjpk 		(void) close(lockfd);
14901676Sjpk 		return (-1);
14911676Sjpk 	}
14921676Sjpk 
14931676Sjpk 	/*
14941676Sjpk 	 * We don't need to parse the file if we are here just to record
14951676Sjpk 	 * on/off status of device_allocation.
14961676Sjpk 	 */
14971676Sjpk 	if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
14981676Sjpk 		if (_record_on_off(dargs, tafp, dafp) == -1) {
14991676Sjpk 			(void) close(tafd);
15001676Sjpk 			(void) unlink(apathp);
15011676Sjpk 			(void) fclose(dafp);
15021676Sjpk 			(void) close(lockfd);
15031676Sjpk 			return (-1);
15041676Sjpk 		}
15051676Sjpk 		(void) fclose(dafp);
15061676Sjpk 		goto out;
15071676Sjpk 	}
15081676Sjpk 
15091676Sjpk 	/*
1510*11529SJan.Parcel@Sun.COM 	 * If reacting to a hotplug, read the file entries,
1511*11529SJan.Parcel@Sun.COM 	 * figure out what dname (tname + a new number) goes to the
1512*11529SJan.Parcel@Sun.COM 	 * device being added/removed, and create a good head_devallocp and
1513*11529SJan.Parcel@Sun.COM 	 * head_devmapp with everything good still in it (_rebuild_lists)
1514*11529SJan.Parcel@Sun.COM 	 *
1515*11529SJan.Parcel@Sun.COM 	 * Else examine all the entries, remove an old one if it is
1516*11529SJan.Parcel@Sun.COM 	 * a duplicate with a device being added, returning the
1517*11529SJan.Parcel@Sun.COM 	 * remaining list (_build_lists.)
1518*11529SJan.Parcel@Sun.COM 	 *
1519*11529SJan.Parcel@Sun.COM 	 * We need to do this only if the file exists already.
1520*11529SJan.Parcel@Sun.COM 	 *
1521*11529SJan.Parcel@Sun.COM 	 * Once we have built these lists, we need to free the strings
1522*11529SJan.Parcel@Sun.COM 	 * in the head_* arrays before returning.
15231676Sjpk 	 */
15241676Sjpk 	if (stat(dapathp, &dastat) == 0) {
1525*11529SJan.Parcel@Sun.COM 		/* for device allocation, the /etc files are the "master" */
1526*11529SJan.Parcel@Sun.COM 		if ((dargs->optflag & (DA_ADD| DA_EVENT)) &&
1527*11529SJan.Parcel@Sun.COM 		    (!(dargs->optflag & DA_FORCE)))
1528*11529SJan.Parcel@Sun.COM 			rc = _rebuild_lists(dargs, &head_devallocp,
1529*11529SJan.Parcel@Sun.COM 			    &head_devmapp);
1530*11529SJan.Parcel@Sun.COM 		else
1531*11529SJan.Parcel@Sun.COM 			rc = _build_lists(dargs, &head_devallocp,
1532*11529SJan.Parcel@Sun.COM 			    &head_devmapp);
1533*11529SJan.Parcel@Sun.COM 
1534*11529SJan.Parcel@Sun.COM 		if (rc != 0 && rc != 1) {
1535*11529SJan.Parcel@Sun.COM 			(void) close(tafd);
1536*11529SJan.Parcel@Sun.COM 			(void) unlink(apathp);
1537*11529SJan.Parcel@Sun.COM 			(void) close(lockfd);
1538*11529SJan.Parcel@Sun.COM 			return (-1);
15391676Sjpk 		}
1540*11529SJan.Parcel@Sun.COM 	} else
1541*11529SJan.Parcel@Sun.COM 		rc = 0;
1542*11529SJan.Parcel@Sun.COM 
1543*11529SJan.Parcel@Sun.COM 	if ((dargs->optflag & DA_REMOVE) && (rc == 0)) {
1544*11529SJan.Parcel@Sun.COM 		(void) close(tafd);
1545*11529SJan.Parcel@Sun.COM 		(void) unlink(apathp);
1546*11529SJan.Parcel@Sun.COM 		(void) close(lockfd);
1547*11529SJan.Parcel@Sun.COM 		return (0);
15481676Sjpk 	}
1549*11529SJan.Parcel@Sun.COM 	/*
1550*11529SJan.Parcel@Sun.COM 	 * TODO: clean up the workings of DA_UPDATE.
1551*11529SJan.Parcel@Sun.COM 	 * Due to da_match looking at fields that are missing
1552*11529SJan.Parcel@Sun.COM 	 * in dargs for DA_UPDATE, the da_match call returns no match,
1553*11529SJan.Parcel@Sun.COM 	 * but due to the way _da2str combines the devalloc_t info with
1554*11529SJan.Parcel@Sun.COM 	 * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work.
1555*11529SJan.Parcel@Sun.COM 	 *
1556*11529SJan.Parcel@Sun.COM 	 * This would not scale if any type of update was ever needed
1557*11529SJan.Parcel@Sun.COM 	 * from the daemon.
1558*11529SJan.Parcel@Sun.COM 	 */
15591676Sjpk 
15601676Sjpk 	/*
1561*11529SJan.Parcel@Sun.COM 	 * Write out devallocp along with the devalloc on/off string.
15621676Sjpk 	 */
15631676Sjpk 	_write_device_allocate(dapathp, tafp, head_devallocp);
15641676Sjpk 
15651676Sjpk 	if (dargs->optflag & DA_ALLOC_ONLY)
15661676Sjpk 		goto out;
15671676Sjpk 
15681676Sjpk dmap_only:
15691676Sjpk 	if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
15701676Sjpk 		(void) close(tafd);
15711676Sjpk 		(void) unlink(apathp);
15721676Sjpk 		(void) close(lockfd);
15731676Sjpk 		return (-1);
15741676Sjpk 	}
15751676Sjpk 	(void) fchown(tmfd, DA_UID, DA_GID);
15761676Sjpk 	if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
15771676Sjpk 		(void) close(tafd);
15781676Sjpk 		(void) unlink(apathp);
15791676Sjpk 		(void) close(tmfd);
15801676Sjpk 		(void) unlink(mpathp);
15811676Sjpk 		(void) close(lockfd);
15821676Sjpk 		return (-1);
15831676Sjpk 	}
15841676Sjpk 
1585*11529SJan.Parcel@Sun.COM 	/*
1586*11529SJan.Parcel@Sun.COM 	 * Write back any non-removed pre-existing entries.
1587*11529SJan.Parcel@Sun.COM 	 */
15881676Sjpk 	if (head_devmapp != NULL)
15891676Sjpk 		_write_device_maps(tmfp, head_devmapp);
15901676Sjpk 
15911676Sjpk out:
1592*11529SJan.Parcel@Sun.COM 	/*
1593*11529SJan.Parcel@Sun.COM 	 * Add any new entries here.
1594*11529SJan.Parcel@Sun.COM 	 */
15951676Sjpk 	if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
15961676Sjpk 		/* add any new entries */
15971676Sjpk 		rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
15981676Sjpk 		(void) fclose(tafp);
15991676Sjpk 
16001676Sjpk 		if (rc == 0)
16011676Sjpk 			rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
16021676Sjpk 		(void) fclose(tmfp);
16031676Sjpk 	} else {
16041676Sjpk 		if (tafp)
16051676Sjpk 			(void) fclose(tafp);
16061676Sjpk 		if (tmfp)
16071676Sjpk 			(void) fclose(tmfp);
16081676Sjpk 	}
16091676Sjpk 
16101676Sjpk 	rc = 0;
16111676Sjpk 	if (!(dargs->optflag & DA_MAPS_ONLY)) {
16121676Sjpk 		if (rename(apathp, dapathp) != 0) {
16131676Sjpk 			rc = -1;
16141676Sjpk 			(void) unlink(apathp);
16151676Sjpk 		}
16161676Sjpk 	}
16171676Sjpk 	if (!(dargs->optflag & DA_ALLOC_ONLY)) {
16181676Sjpk 		if (rename(mpathp, dmpathp) != 0) {
16191676Sjpk 			rc = -1;
16201676Sjpk 			(void) unlink(mpathp);
16211676Sjpk 		}
16221676Sjpk 	}
16231676Sjpk 
16241676Sjpk 	(void) close(lockfd);
16251676Sjpk 
16261676Sjpk 	return (rc);
16271676Sjpk }
16281676Sjpk 
16291676Sjpk /*
16301676Sjpk  * da_add_list -
16311676Sjpk  *	adds new /dev link name to the linked list of devices.
16321676Sjpk  *	returns 0 if link added successfully, -1 on error.
16331676Sjpk  */
16341676Sjpk int
16351676Sjpk da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
16361676Sjpk {
16371676Sjpk 	int		instance;
16381676Sjpk 	int		nlen, plen;
16391676Sjpk 	int		new_entry = 0;
16401676Sjpk 	char		*dtype, *dexec, *tname, *kval;
16411676Sjpk 	char		*minstr = NULL, *maxstr = NULL;
1642*11529SJan.Parcel@Sun.COM 	char		dname[DA_MAXNAME + 1];
16431676Sjpk 	kva_t		*kva;
16441676Sjpk 	deventry_t	*dentry = NULL, *nentry = NULL, *pentry = NULL;
16451676Sjpk 	da_defs_t	*da_defs;
16461676Sjpk 
16471676Sjpk 	if (dlist == NULL || link == NULL)
16481676Sjpk 		return (-1);
16491676Sjpk 
16501676Sjpk 	dname[0] = '\0';
16511676Sjpk 	if (flag & DA_AUDIO) {
16521676Sjpk 		dentry = dlist->audio;
16531676Sjpk 		tname = DA_AUDIO_NAME;
16541676Sjpk 		dtype = DA_AUDIO_TYPE;
16551676Sjpk 		dexec = DA_DEFAULT_AUDIO_CLEAN;
16561676Sjpk 	} else if (flag & DA_CD) {
16571676Sjpk 		dentry = dlist->cd;
16581676Sjpk 		tname = DA_CD_NAME;
16591676Sjpk 		dtype = DA_CD_TYPE;
16601676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
16611676Sjpk 	} else if (flag & DA_FLOPPY) {
16621676Sjpk 		dentry = dlist->floppy;
16631676Sjpk 		tname = DA_FLOPPY_NAME;
16641676Sjpk 		dtype = DA_FLOPPY_TYPE;
16651676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
16661676Sjpk 	} else if (flag & DA_TAPE) {
16671676Sjpk 		dentry = dlist->tape;
16681676Sjpk 		tname = DA_TAPE_NAME;
16691676Sjpk 		dtype = DA_TAPE_TYPE;
16701676Sjpk 		dexec = DA_DEFAULT_TAPE_CLEAN;
16711676Sjpk 	} else if (flag & DA_RMDISK) {
16721676Sjpk 		dentry = dlist->rmdisk;
16731676Sjpk 		tname = DA_RMDISK_NAME;
16741676Sjpk 		dtype = DA_RMDISK_TYPE;
16751676Sjpk 		dexec = DA_DEFAULT_DISK_CLEAN;
16761676Sjpk 	} else {
16771676Sjpk 		return (-1);
16781676Sjpk 	}
16791676Sjpk 
16801676Sjpk 	for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
16811676Sjpk 		pentry = nentry;
16821676Sjpk 		(void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
16831676Sjpk 		if (nentry->devinfo.instance == new_instance)
16841676Sjpk 			/*
16851676Sjpk 			 * Add the new link name to the list of links
16861676Sjpk 			 * that the device 'dname' has.
16871676Sjpk 			 */
16881676Sjpk 			break;
16891676Sjpk 	}
16901676Sjpk 
16911676Sjpk 	if (nentry == NULL) {
16921676Sjpk 		/*
16931676Sjpk 		 * Either this is the first entry ever, or no matching entry
16941676Sjpk 		 * was found. Create a new one and add to the list.
16951676Sjpk 		 */
16961676Sjpk 		if (dentry == NULL)		/* first entry ever */
16971676Sjpk 			instance = 0;
16981676Sjpk 		else				/* no matching entry */
16991676Sjpk 			instance++;
17001676Sjpk 		(void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
17011676Sjpk 		if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
17021676Sjpk 		    NULL)
17031676Sjpk 			return (-1);
17041676Sjpk 		if (pentry != NULL)
17051676Sjpk 			pentry->next = nentry;
17061676Sjpk 		new_entry = 1;
17071676Sjpk 		nentry->devinfo.devname = strdup(dname);
17081676Sjpk 		nentry->devinfo.devtype = dtype;
17091676Sjpk 		nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
17101676Sjpk 		nentry->devinfo.devexec = dexec;
17111676Sjpk 		nentry->devinfo.instance = new_instance;
17121676Sjpk 		/*
17131676Sjpk 		 * Look for default label range, authorizations and cleaning
17141676Sjpk 		 * program in devalloc_defaults. If label range is not
17151676Sjpk 		 * specified in devalloc_defaults, assume it to be admin_low
17161676Sjpk 		 * to admin_high.
17171676Sjpk 		 */
17181676Sjpk 		minstr = DA_DEFAULT_MIN;
17191676Sjpk 		maxstr = DA_DEFAULT_MAX;
17201676Sjpk 		setdadefent();
17211676Sjpk 		if (da_defs = getdadeftype(nentry->devinfo.devtype)) {
17221676Sjpk 			kva = da_defs->devopts;
17231676Sjpk 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
17241676Sjpk 				minstr = strdup(kval);
17251676Sjpk 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
17261676Sjpk 				maxstr = strdup(kval);
17271676Sjpk 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
17281676Sjpk 				nentry->devinfo.devauths = strdup(kval);
17291676Sjpk 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
17301676Sjpk 				nentry->devinfo.devexec = strdup(kval);
17311676Sjpk 			freedadefent(da_defs);
17321676Sjpk 		}
17331676Sjpk 		enddadefent();
17341676Sjpk 		kval = NULL;
17351676Sjpk 		nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
17361676Sjpk 		    strlen(minstr) + strlen(KV_TOKEN_DELIMIT) +
17371676Sjpk 		    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) + strlen(maxstr)
17381676Sjpk 		    + 1;			/* +1 for terminator */
17391676Sjpk 		if (kval = (char *)malloc(nlen))
17401676Sjpk 			(void) snprintf(kval, nlen, "%s%s%s%s%s%s%s",
17411676Sjpk 			    DAOPT_MINLABEL, KV_ASSIGN, minstr, KV_TOKEN_DELIMIT,
17421676Sjpk 			    DAOPT_MAXLABEL, KV_ASSIGN, maxstr);
17431676Sjpk 		nentry->devinfo.devopts = kval;
17441676Sjpk 
17451676Sjpk 		nentry->devinfo.devlist = NULL;
17461676Sjpk 		nentry->next = NULL;
17471676Sjpk 	}
17481676Sjpk 
17491676Sjpk 	nlen = strlen(link) + 1;		/* +1 terminator */
17501676Sjpk 	if (nentry->devinfo.devlist) {
17511676Sjpk 		plen = strlen(nentry->devinfo.devlist);
17521676Sjpk 		nlen = nlen + plen + 1;	/* +1 for blank to separate entries */
17531676Sjpk 	} else {
17541676Sjpk 		plen = 0;
17551676Sjpk 	}
17561676Sjpk 
17571676Sjpk 	if ((nentry->devinfo.devlist =
17581676Sjpk 	    (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
17591676Sjpk 		if (new_entry) {
17601676Sjpk 			free(nentry->devinfo.devname);
17611676Sjpk 			free(nentry);
17621676Sjpk 			if (pentry != NULL)
17631676Sjpk 				pentry->next = NULL;
17641676Sjpk 		}
17651676Sjpk 		return (-1);
17661676Sjpk 	}
17671676Sjpk 
17681676Sjpk 	if (plen == 0)
17691676Sjpk 		(void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
17701676Sjpk 	else
17711676Sjpk 		(void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
17721676Sjpk 		    " %s", link);
17731676Sjpk 
17741676Sjpk 	if (pentry == NULL) {
17751676Sjpk 		/*
17761676Sjpk 		 * This is the first entry of this device type.
17771676Sjpk 		 */
17781676Sjpk 		if (flag & DA_AUDIO)
17791676Sjpk 			dlist->audio = nentry;
17801676Sjpk 		else if (flag & DA_CD)
17811676Sjpk 			dlist->cd = nentry;
17821676Sjpk 		else if (flag & DA_FLOPPY)
17831676Sjpk 			dlist->floppy = nentry;
17841676Sjpk 		else if (flag & DA_TAPE)
17851676Sjpk 			dlist->tape = nentry;
17861676Sjpk 		else if (flag & DA_RMDISK)
17871676Sjpk 			dlist->rmdisk = nentry;
17881676Sjpk 	}
17891676Sjpk 
17901676Sjpk 	return (0);
17911676Sjpk }
17921676Sjpk 
17931676Sjpk /*
17941676Sjpk  * da_remove_list -
17951676Sjpk  *	removes a /dev link name from the linked list of devices.
17961676Sjpk  *	returns type of device if link for that device removed
17971676Sjpk  *	successfully, else returns -1 on error.
17981676Sjpk  *	if all links for a device are removed, stores that device
17991676Sjpk  *	name in devname.
18001676Sjpk  */
18011676Sjpk int
18021676Sjpk da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
18031676Sjpk {
18041676Sjpk 	int		flag;
18051676Sjpk 	int		remove_dev = 0;
18061676Sjpk 	int		nlen, plen, slen;
18071676Sjpk 	char		*lasts, *lname, *oldlist;
18081676Sjpk 	struct stat	rmstat;
18091676Sjpk 	deventry_t	*dentry, *current, *prev;
18101676Sjpk 
18111676Sjpk 	if (type != NULL)
18121676Sjpk 		flag = type;
18131676Sjpk 	else if (link == NULL)
18141676Sjpk 		return (-1);
18151676Sjpk 	else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
18161676Sjpk 		flag = DA_AUDIO;
18171676Sjpk 	else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
18181676Sjpk 	    strstr(link, "sr") || strstr(link, "rsr"))
18191676Sjpk 		flag = DA_CD;
18201676Sjpk 	else if (strstr(link, "fd") || strstr(link, "rfd") ||
18211676Sjpk 	    strstr(link, "diskette") || strstr(link, "rdiskette"))
18221676Sjpk 		flag = DA_FLOPPY;
18231676Sjpk 	else if (strstr(link, DA_TAPE_NAME))
18241676Sjpk 		flag = DA_TAPE;
18251676Sjpk 	else
18261676Sjpk 		flag = DA_RMDISK;
18271676Sjpk 
18281676Sjpk 	switch (type) {
18291676Sjpk 	case DA_AUDIO:
18301676Sjpk 		dentry = dlist->audio;
18311676Sjpk 		break;
18321676Sjpk 	case DA_CD:
18331676Sjpk 		dentry = dlist->cd;
18341676Sjpk 		break;
18351676Sjpk 	case DA_FLOPPY:
18361676Sjpk 		dentry = dlist->floppy;
18371676Sjpk 		break;
18381676Sjpk 	case DA_TAPE:
18391676Sjpk 		dentry = dlist->tape;
18401676Sjpk 		break;
18411676Sjpk 	case DA_RMDISK:
18421676Sjpk 		dentry = dlist->rmdisk;
18431676Sjpk 		break;
18441676Sjpk 	default:
18451676Sjpk 		return (-1);
18461676Sjpk 	}
18471676Sjpk 
18481676Sjpk 	if ((type != NULL) && (link == NULL)) {
18491676Sjpk 		for (current = dentry, prev = dentry; current != NULL;
18501676Sjpk 		    current = current->next) {
18511676Sjpk 			oldlist = strdup(current->devinfo.devlist);
18521676Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
18531676Sjpk 			    lname != NULL;
18541676Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
18551676Sjpk 				if (stat(lname, &rmstat) != 0) {
18561676Sjpk 					remove_dev = 1;
18571676Sjpk 					goto remove_dev;
18581676Sjpk 				}
18591676Sjpk 			}
18601676Sjpk 			prev = current;
18611676Sjpk 		}
18621676Sjpk 		return (-1);
18631676Sjpk 	}
18641676Sjpk 
18651676Sjpk 	for (current = dentry, prev = dentry; current != NULL;
18661676Sjpk 	    current = current->next) {
18671676Sjpk 		plen = strlen(current->devinfo.devlist);
18681676Sjpk 		nlen = strlen(link);
18691676Sjpk 		if (plen == nlen) {
18701676Sjpk 			if (strcmp(current->devinfo.devlist, link) == 0) {
18711676Sjpk 				/* last name in the list */
18721676Sjpk 				remove_dev = 1;
18731676Sjpk 				break;
18741676Sjpk 			}
18751676Sjpk 		}
18761676Sjpk 		if (strstr(current->devinfo.devlist, link)) {
18771676Sjpk 			nlen = plen - nlen + 1;
18781676Sjpk 			oldlist = strdup(current->devinfo.devlist);
18791676Sjpk 			if ((current->devinfo.devlist =
18801676Sjpk 			    (char *)realloc(current->devinfo.devlist,
18811676Sjpk 			    nlen)) == NULL) {
18821676Sjpk 				free(oldlist);
18831676Sjpk 				return (-1);
18841676Sjpk 			}
18851676Sjpk 			current->devinfo.devlist[0] = '\0';
18861676Sjpk 			nlen = plen = slen = 0;
18871676Sjpk 			for (lname = strtok_r(oldlist, " ", &lasts);
18881676Sjpk 			    lname != NULL;
18891676Sjpk 			    lname = strtok_r(NULL, " ", &lasts)) {
18901676Sjpk 				if (strcmp(lname, link) == 0)
18911676Sjpk 					continue;
18921676Sjpk 				nlen = strlen(lname) + plen + 1;
18931676Sjpk 				if (plen == 0) {
18941676Sjpk 					slen =
18951676Sjpk 					    snprintf(current->devinfo.devlist,
18964514Saj 					    nlen, "%s", lname);
18971676Sjpk 				} else {
18981676Sjpk 					slen =
18991676Sjpk 					    snprintf(current->devinfo.devlist +
19004514Saj 					    plen, nlen - plen, " %s", lname);
19011676Sjpk 				}
19021676Sjpk 				plen = plen + slen + 1;
19031676Sjpk 			}
19041676Sjpk 			free(oldlist);
19051676Sjpk 			break;
19061676Sjpk 		}
19071676Sjpk 		prev = current;
19081676Sjpk 	}
19091676Sjpk 
19101676Sjpk remove_dev:
19111676Sjpk 	if (remove_dev == 1) {
19121676Sjpk 		(void) strlcpy(devname, current->devinfo.devname, size);
19131676Sjpk 		free(current->devinfo.devname);
19141676Sjpk 		free(current->devinfo.devlist);
19151676Sjpk 		current->devinfo.devname = current->devinfo.devlist = NULL;
19161676Sjpk 		prev->next = current->next;
19171676Sjpk 		free(current);
19181676Sjpk 		current = NULL;
19191676Sjpk 	}
19201676Sjpk 	if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
19211676Sjpk 		if (prev->next) {
19221676Sjpk 			/*
19231676Sjpk 			 * what we removed above was the first entry
19241676Sjpk 			 * in the list. make the next entry to be the
19251676Sjpk 			 * first.
19261676Sjpk 			 */
19271676Sjpk 			current = prev->next;
19281676Sjpk 		} else {
19291676Sjpk 			/*
19301676Sjpk 			 * the matching entry was the only entry in the list
19311676Sjpk 			 * for this type.
19321676Sjpk 			 */
19331676Sjpk 			current = NULL;
19341676Sjpk 		}
19351676Sjpk 		if (flag & DA_AUDIO)
19361676Sjpk 			dlist->audio = current;
19371676Sjpk 		else if (flag & DA_CD)
19381676Sjpk 			dlist->cd = current;
19391676Sjpk 		else if (flag & DA_FLOPPY)
19401676Sjpk 			dlist->floppy = current;
19411676Sjpk 		else if (flag & DA_TAPE)
19421676Sjpk 			dlist->tape = current;
19431676Sjpk 		else if (flag & DA_RMDISK)
19441676Sjpk 			dlist->rmdisk = current;
19451676Sjpk 	}
19461676Sjpk 
19471676Sjpk 	return (flag);
19481676Sjpk }
19491676Sjpk 
19501676Sjpk /*
1951*11529SJan.Parcel@Sun.COM  * da_rm_list_entry -
1952*11529SJan.Parcel@Sun.COM  *
1953*11529SJan.Parcel@Sun.COM  *	The adding of devnames to a devlist and the removal of a
1954*11529SJan.Parcel@Sun.COM  *	device are not symmetrical -- hot_cleanup gives a /devices
1955*11529SJan.Parcel@Sun.COM  *	name which is used to remove the dentry whose links all point to
1956*11529SJan.Parcel@Sun.COM  *	that /devices entry.
1957*11529SJan.Parcel@Sun.COM  *
1958*11529SJan.Parcel@Sun.COM  *	The link argument is present if available to make debugging
1959*11529SJan.Parcel@Sun.COM  *	easier.
1960*11529SJan.Parcel@Sun.COM  *
1961*11529SJan.Parcel@Sun.COM  *	da_rm_list_entry removes an entry from the linked list of devices.
1962*11529SJan.Parcel@Sun.COM  *
1963*11529SJan.Parcel@Sun.COM  *	Returns 1 if the devname was removed successfully,
1964*11529SJan.Parcel@Sun.COM  *	0 if not found, -1 for error.
1965*11529SJan.Parcel@Sun.COM  */
1966*11529SJan.Parcel@Sun.COM /*ARGSUSED*/
1967*11529SJan.Parcel@Sun.COM int
1968*11529SJan.Parcel@Sun.COM da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname)
1969*11529SJan.Parcel@Sun.COM {
1970*11529SJan.Parcel@Sun.COM 	int		retval = 0;
1971*11529SJan.Parcel@Sun.COM 	deventry_t	**dentry, *current, *prev;
1972*11529SJan.Parcel@Sun.COM 
1973*11529SJan.Parcel@Sun.COM 	switch (type) {
1974*11529SJan.Parcel@Sun.COM 	case DA_AUDIO:
1975*11529SJan.Parcel@Sun.COM 		dentry = &(dlist->audio);
1976*11529SJan.Parcel@Sun.COM 		break;
1977*11529SJan.Parcel@Sun.COM 	case DA_CD:
1978*11529SJan.Parcel@Sun.COM 		dentry = &(dlist->cd);
1979*11529SJan.Parcel@Sun.COM 		break;
1980*11529SJan.Parcel@Sun.COM 	case DA_FLOPPY:
1981*11529SJan.Parcel@Sun.COM 		dentry = &(dlist->floppy);
1982*11529SJan.Parcel@Sun.COM 		break;
1983*11529SJan.Parcel@Sun.COM 	case DA_TAPE:
1984*11529SJan.Parcel@Sun.COM 		dentry = &(dlist->tape);
1985*11529SJan.Parcel@Sun.COM 		break;
1986*11529SJan.Parcel@Sun.COM 	case DA_RMDISK:
1987*11529SJan.Parcel@Sun.COM 		dentry = &(dlist->rmdisk);
1988*11529SJan.Parcel@Sun.COM 		break;
1989*11529SJan.Parcel@Sun.COM 	default:
1990*11529SJan.Parcel@Sun.COM 		return (-1);
1991*11529SJan.Parcel@Sun.COM 	}
1992*11529SJan.Parcel@Sun.COM 
1993*11529SJan.Parcel@Sun.COM 	/* Presumably in daemon mode, no need to remove entry, list is empty */
1994*11529SJan.Parcel@Sun.COM 	if (*dentry == (deventry_t *)NULL)
1995*11529SJan.Parcel@Sun.COM 		return (0);
1996*11529SJan.Parcel@Sun.COM 
1997*11529SJan.Parcel@Sun.COM 	prev = NULL;
1998*11529SJan.Parcel@Sun.COM 	for (current = *dentry; current != NULL;
1999*11529SJan.Parcel@Sun.COM 	    prev = current, current = current->next) {
2000*11529SJan.Parcel@Sun.COM 		if (strcmp(devname, current->devinfo.devname))
2001*11529SJan.Parcel@Sun.COM 			continue;
2002*11529SJan.Parcel@Sun.COM 		retval = 1;
2003*11529SJan.Parcel@Sun.COM 		break;
2004*11529SJan.Parcel@Sun.COM 	}
2005*11529SJan.Parcel@Sun.COM 	if (retval == 0)
2006*11529SJan.Parcel@Sun.COM 		return (0);
2007*11529SJan.Parcel@Sun.COM 	free(current->devinfo.devname);
2008*11529SJan.Parcel@Sun.COM 	if (current->devinfo.devlist != NULL)
2009*11529SJan.Parcel@Sun.COM 		free(current->devinfo.devlist);
2010*11529SJan.Parcel@Sun.COM 	if (current->devinfo.devopts != NULL)
2011*11529SJan.Parcel@Sun.COM 		free(current->devinfo.devopts);
2012*11529SJan.Parcel@Sun.COM 
2013*11529SJan.Parcel@Sun.COM 	if (prev == NULL)
2014*11529SJan.Parcel@Sun.COM 		*dentry = current->next;
2015*11529SJan.Parcel@Sun.COM 	else
2016*11529SJan.Parcel@Sun.COM 		prev->next = current->next;
2017*11529SJan.Parcel@Sun.COM 
2018*11529SJan.Parcel@Sun.COM 	free(current);
2019*11529SJan.Parcel@Sun.COM 	return (retval);
2020*11529SJan.Parcel@Sun.COM }
2021*11529SJan.Parcel@Sun.COM 
2022*11529SJan.Parcel@Sun.COM /*
20231676Sjpk  * da_is_on -
20241676Sjpk  *	checks if device allocation feature is turned on.
20251676Sjpk  *	returns 1 if on, 0 if off, -1 if status string not
20261676Sjpk  *	found in device_allocate.
20271676Sjpk  */
20281676Sjpk int
20291676Sjpk da_is_on()
20301676Sjpk {
20311676Sjpk 	return (getdaon());
20321676Sjpk }
20331676Sjpk 
20341676Sjpk /*
20351676Sjpk  * da_print_device -
20361676Sjpk  *	debug routine to print device entries.
20371676Sjpk  */
20381676Sjpk void
20391676Sjpk da_print_device(int flag, devlist_t *devlist)
20401676Sjpk {
20411676Sjpk 	deventry_t	*entry, *dentry;
20421676Sjpk 	devinfo_t	*devinfo;
20431676Sjpk 
20441676Sjpk 	if (flag & DA_AUDIO)
20451676Sjpk 		dentry = devlist->audio;
20461676Sjpk 	else if (flag & DA_CD)
20471676Sjpk 		dentry = devlist->cd;
20481676Sjpk 	else if (flag & DA_FLOPPY)
20491676Sjpk 		dentry = devlist->floppy;
20501676Sjpk 	else if (flag & DA_TAPE)
20511676Sjpk 		dentry = devlist->tape;
20521676Sjpk 	else if (flag & DA_RMDISK)
20531676Sjpk 		dentry = devlist->rmdisk;
20541676Sjpk 	else
20551676Sjpk 		return;
20561676Sjpk 
20571676Sjpk 	for (entry = dentry; entry != NULL; entry = entry->next) {
20581676Sjpk 		devinfo = &(entry->devinfo);
20591676Sjpk 		(void) fprintf(stdout, "name: %s\n", devinfo->devname);
20601676Sjpk 		(void) fprintf(stdout, "type: %s\n", devinfo->devtype);
20611676Sjpk 		(void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
20621676Sjpk 		(void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
20631676Sjpk 		(void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);
20641676Sjpk 	}
20651676Sjpk }
2066