xref: /minix3/lib/libc/gen/getcap.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: getcap.c,v 1.56 2014/09/24 13:18:52 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*-
42fe8fb19SBen Gras  * Copyright (c) 1992, 1993
52fe8fb19SBen Gras  *	The Regents of the University of California.  All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * This code is derived from software contributed to Berkeley by
82fe8fb19SBen Gras  * Casey Leedom of Lawrence Livermore National Laboratory.
92fe8fb19SBen Gras  *
102fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
112fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
122fe8fb19SBen Gras  * are met:
132fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
142fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
152fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
162fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
172fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
182fe8fb19SBen Gras  * 3. Neither the name of the University nor the names of its contributors
192fe8fb19SBen Gras  *    may be used to endorse or promote products derived from this software
202fe8fb19SBen Gras  *    without specific prior written permission.
212fe8fb19SBen Gras  *
222fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
232fe8fb19SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
242fe8fb19SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
252fe8fb19SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
262fe8fb19SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
272fe8fb19SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
282fe8fb19SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
292fe8fb19SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
302fe8fb19SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
312fe8fb19SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
322fe8fb19SBen Gras  * SUCH DAMAGE.
332fe8fb19SBen Gras  */
342fe8fb19SBen Gras 
352fe8fb19SBen Gras #if HAVE_NBTOOL_CONFIG_H
362fe8fb19SBen Gras #include "nbtool_config.h"
372fe8fb19SBen Gras #endif
382fe8fb19SBen Gras 
392fe8fb19SBen Gras #include <sys/cdefs.h>
402fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
412fe8fb19SBen Gras #if 0
422fe8fb19SBen Gras static char sccsid[] = "@(#)getcap.c	8.3 (Berkeley) 3/25/94";
432fe8fb19SBen Gras #else
44*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: getcap.c,v 1.56 2014/09/24 13:18:52 christos Exp $");
452fe8fb19SBen Gras #endif
462fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
472fe8fb19SBen Gras 
482fe8fb19SBen Gras #ifndef SMALL
492fe8fb19SBen Gras #include "namespace.h"
502fe8fb19SBen Gras #endif
512fe8fb19SBen Gras #include <sys/types.h>
522fe8fb19SBen Gras #include <sys/param.h>
532fe8fb19SBen Gras 
542fe8fb19SBen Gras #include <assert.h>
55f14fb602SLionel Sambuc #include <stddef.h>
562fe8fb19SBen Gras #include <ctype.h>
572fe8fb19SBen Gras #ifndef SMALL
582fe8fb19SBen Gras #include <db.h>
592fe8fb19SBen Gras #endif
602fe8fb19SBen Gras #include <errno.h>
612fe8fb19SBen Gras #include <fcntl.h>
622fe8fb19SBen Gras #include <limits.h>
632fe8fb19SBen Gras #include <stdio.h>
642fe8fb19SBen Gras #include <stdlib.h>
652fe8fb19SBen Gras #include <string.h>
662fe8fb19SBen Gras #include <unistd.h>
672fe8fb19SBen Gras 
68f14fb602SLionel Sambuc #if defined(__weak_alias) && !defined(SMALL)
692fe8fb19SBen Gras __weak_alias(cgetcap,_cgetcap)
702fe8fb19SBen Gras __weak_alias(cgetclose,_cgetclose)
712fe8fb19SBen Gras __weak_alias(cgetent,_cgetent)
722fe8fb19SBen Gras __weak_alias(cgetfirst,_cgetfirst)
732fe8fb19SBen Gras __weak_alias(cgetmatch,_cgetmatch)
742fe8fb19SBen Gras __weak_alias(cgetnext,_cgetnext)
752fe8fb19SBen Gras __weak_alias(cgetnum,_cgetnum)
762fe8fb19SBen Gras __weak_alias(cgetset,_cgetset)
772fe8fb19SBen Gras __weak_alias(cgetstr,_cgetstr)
782fe8fb19SBen Gras __weak_alias(cgetustr,_cgetustr)
792fe8fb19SBen Gras __weak_alias(csetexpandtc,_csetexpandtc)
802fe8fb19SBen Gras #endif
812fe8fb19SBen Gras 
822fe8fb19SBen Gras #define	BFRAG		1024
832fe8fb19SBen Gras #define	BSIZE		1024
842fe8fb19SBen Gras #define	ESC		('[' & 037)	/* ASCII ESC */
852fe8fb19SBen Gras #define	MAX_RECURSION	32		/* maximum getent recursion */
862fe8fb19SBen Gras #define	SFRAG		100		/* cgetstr mallocs in SFRAG chunks */
872fe8fb19SBen Gras 
882fe8fb19SBen Gras #define RECOK	(char)0
892fe8fb19SBen Gras #define TCERR	(char)1
902fe8fb19SBen Gras #define	SHADOW	(char)2
912fe8fb19SBen Gras 
922fe8fb19SBen Gras static size_t	 topreclen;	/* toprec length */
932fe8fb19SBen Gras static char	*toprec;	/* Additional record specified by cgetset() */
942fe8fb19SBen Gras static int	 gottoprec;	/* Flag indicating retrieval of toprecord */
952fe8fb19SBen Gras static int	 expandtc = 1;	/* flag to expand tc= or not */
962fe8fb19SBen Gras 
972fe8fb19SBen Gras #ifndef SMALL
982fe8fb19SBen Gras static int	cdbget(DB *, char **, const char *);
992fe8fb19SBen Gras #endif
1002fe8fb19SBen Gras static int 	getent(char **, size_t *, const char * const *, int,
1012fe8fb19SBen Gras     const char *, int, char *);
1022fe8fb19SBen Gras static int	nfcmp(char *, char *);
1032fe8fb19SBen Gras 
1042fe8fb19SBen Gras /*
1052fe8fb19SBen Gras  * Cgetset() allows the addition of a user specified buffer to be added
1062fe8fb19SBen Gras  * to the database array, in effect "pushing" the buffer on top of the
1072fe8fb19SBen Gras  * virtual database. 0 is returned on success, -1 on failure.
1082fe8fb19SBen Gras  */
1092fe8fb19SBen Gras int
cgetset(const char * ent)1102fe8fb19SBen Gras cgetset(const char *ent)
1112fe8fb19SBen Gras {
1122fe8fb19SBen Gras 	const char *source, *check;
1132fe8fb19SBen Gras 	char *dest;
1142fe8fb19SBen Gras 
1152fe8fb19SBen Gras 	if (ent == NULL) {
1162fe8fb19SBen Gras 		if (toprec != NULL)
1172fe8fb19SBen Gras 			free(toprec);
1182fe8fb19SBen Gras                 toprec = NULL;
1192fe8fb19SBen Gras                 topreclen = 0;
1202fe8fb19SBen Gras                 return 0;
1212fe8fb19SBen Gras         }
1222fe8fb19SBen Gras         topreclen = strlen(ent);
1232fe8fb19SBen Gras         if ((toprec = malloc(topreclen + 1)) == NULL) {
1242fe8fb19SBen Gras 		errno = ENOMEM;
1252fe8fb19SBen Gras                 return -1;
1262fe8fb19SBen Gras 	}
1272fe8fb19SBen Gras 	gottoprec = 0;
1282fe8fb19SBen Gras 
1292fe8fb19SBen Gras 	source = ent;
1302fe8fb19SBen Gras 	dest = toprec;
1312fe8fb19SBen Gras 	while (*source != '\0') { /* Strip whitespace */
1322fe8fb19SBen Gras 		*dest++ = *source++; /* Do not check first field */
1332fe8fb19SBen Gras 		while (*source == ':') {
1342fe8fb19SBen Gras 			check = source + 1;
1352fe8fb19SBen Gras 			while (*check && (isspace((unsigned char)*check) ||
1362fe8fb19SBen Gras 			    (*check=='\\' && isspace((unsigned char)check[1]))))
1372fe8fb19SBen Gras 				++check;
1382fe8fb19SBen Gras 			if (*check == ':')
1392fe8fb19SBen Gras 				source = check;
1402fe8fb19SBen Gras 			else
1412fe8fb19SBen Gras 				break;
1422fe8fb19SBen Gras 
1432fe8fb19SBen Gras 		}
1442fe8fb19SBen Gras 	}
1452fe8fb19SBen Gras 	*dest = 0;
1462fe8fb19SBen Gras 
1472fe8fb19SBen Gras         return 0;
1482fe8fb19SBen Gras }
1492fe8fb19SBen Gras 
1502fe8fb19SBen Gras /*
1512fe8fb19SBen Gras  * Cgetcap searches the capability record buf for the capability cap with
1522fe8fb19SBen Gras  * type `type'.  A pointer to the value of cap is returned on success, NULL
1532fe8fb19SBen Gras  * if the requested capability couldn't be found.
1542fe8fb19SBen Gras  *
1552fe8fb19SBen Gras  * Specifying a type of ':' means that nothing should follow cap (:cap:).
1562fe8fb19SBen Gras  * In this case a pointer to the terminating ':' or NUL will be returned if
1572fe8fb19SBen Gras  * cap is found.
1582fe8fb19SBen Gras  *
1592fe8fb19SBen Gras  * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
1602fe8fb19SBen Gras  * return NULL.
1612fe8fb19SBen Gras  */
1622fe8fb19SBen Gras char *
cgetcap(char * buf,const char * cap,int type)163f14fb602SLionel Sambuc cgetcap(char *buf, const char *cap, int type)
1642fe8fb19SBen Gras {
1652fe8fb19SBen Gras 	char *bp;
1662fe8fb19SBen Gras 	const char *cp;
1672fe8fb19SBen Gras 
1682fe8fb19SBen Gras 	_DIAGASSERT(buf != NULL);
1692fe8fb19SBen Gras 	_DIAGASSERT(cap != NULL);
1702fe8fb19SBen Gras 
1712fe8fb19SBen Gras 	bp = buf;
1722fe8fb19SBen Gras 	for (;;) {
1732fe8fb19SBen Gras 		/*
1742fe8fb19SBen Gras 		 * Skip past the current capability field - it's either the
1752fe8fb19SBen Gras 		 * name field if this is the first time through the loop, or
1762fe8fb19SBen Gras 		 * the remainder of a field whose name failed to match cap.
1772fe8fb19SBen Gras 		 */
1782fe8fb19SBen Gras 		for (;;)
1792fe8fb19SBen Gras 			if (*bp == '\0')
1802fe8fb19SBen Gras 				return NULL;
1812fe8fb19SBen Gras 			else if (*bp++ == ':')
1822fe8fb19SBen Gras 				break;
1832fe8fb19SBen Gras 
1842fe8fb19SBen Gras 		/*
1852fe8fb19SBen Gras 		 * Try to match (cap, type) in buf.
1862fe8fb19SBen Gras 		 */
1872fe8fb19SBen Gras 		for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
1882fe8fb19SBen Gras 			continue;
1892fe8fb19SBen Gras 		if (*cp != '\0')
1902fe8fb19SBen Gras 			continue;
1912fe8fb19SBen Gras 		if (*bp == '@')
1922fe8fb19SBen Gras 			return NULL;
1932fe8fb19SBen Gras 		if (type == ':') {
1942fe8fb19SBen Gras 			if (*bp != '\0' && *bp != ':')
1952fe8fb19SBen Gras 				continue;
1962fe8fb19SBen Gras 			return bp;
1972fe8fb19SBen Gras 		}
1982fe8fb19SBen Gras 		if (*bp != type)
1992fe8fb19SBen Gras 			continue;
2002fe8fb19SBen Gras 		bp++;
2012fe8fb19SBen Gras 		return *bp == '@' ? NULL : bp;
2022fe8fb19SBen Gras 	}
2032fe8fb19SBen Gras 	/* NOTREACHED */
2042fe8fb19SBen Gras }
2052fe8fb19SBen Gras 
2062fe8fb19SBen Gras /*
2072fe8fb19SBen Gras  * Cgetent extracts the capability record name from the NULL terminated file
2082fe8fb19SBen Gras  * array db_array and returns a pointer to a malloc'd copy of it in buf.
2092fe8fb19SBen Gras  * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
2102fe8fb19SBen Gras  * cgetflag, and cgetstr, but may then be free'd.  0 is returned on success,
2112fe8fb19SBen Gras  * -1 if the requested record couldn't be found, -2 if a system error was
2122fe8fb19SBen Gras  * encountered (couldn't open/read a file, etc.), and -3 if a potential
2132fe8fb19SBen Gras  * reference loop is detected.
2142fe8fb19SBen Gras  */
2152fe8fb19SBen Gras /* coverity[+alloc : arg-*0] */
2162fe8fb19SBen Gras int
cgetent(char ** buf,const char * const * db_array,const char * name)2172fe8fb19SBen Gras cgetent(char **buf, const char * const *db_array, const char *name)
2182fe8fb19SBen Gras {
2192fe8fb19SBen Gras 	size_t dummy;
2202fe8fb19SBen Gras 
2212fe8fb19SBen Gras 	_DIAGASSERT(buf != NULL);
2222fe8fb19SBen Gras 	_DIAGASSERT(db_array != NULL);
2232fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
2242fe8fb19SBen Gras 
2252fe8fb19SBen Gras 	return getent(buf, &dummy, db_array, -1, name, 0, NULL);
2262fe8fb19SBen Gras }
2272fe8fb19SBen Gras 
2282fe8fb19SBen Gras void
csetexpandtc(int etc)2292fe8fb19SBen Gras csetexpandtc(int etc)
2302fe8fb19SBen Gras {
2312fe8fb19SBen Gras 	expandtc = etc;
2322fe8fb19SBen Gras }
2332fe8fb19SBen Gras 
2342fe8fb19SBen Gras /*
2352fe8fb19SBen Gras  * Getent implements the functions of cgetent.  If fd is non-negative,
2362fe8fb19SBen Gras  * *db_array has already been opened and fd is the open file descriptor.  We
2372fe8fb19SBen Gras  * do this to save time and avoid using up file descriptors for tc=
2382fe8fb19SBen Gras  * recursions.
2392fe8fb19SBen Gras  *
2402fe8fb19SBen Gras  * Getent returns the same success/failure codes as cgetent.  On success, a
2412fe8fb19SBen Gras  * pointer to a malloc'ed capability record with all tc= capabilities fully
2422fe8fb19SBen Gras  * expanded and its length (not including trailing ASCII NUL) are left in
2432fe8fb19SBen Gras  * *cap and *len.
2442fe8fb19SBen Gras  *
2452fe8fb19SBen Gras  * Basic algorithm:
2462fe8fb19SBen Gras  *	+ Allocate memory incrementally as needed in chunks of size BFRAG
2472fe8fb19SBen Gras  *	  for capability buffer.
2482fe8fb19SBen Gras  *	+ Recurse for each tc=name and interpolate result.  Stop when all
2492fe8fb19SBen Gras  *	  names interpolated, a name can't be found, or depth exceeds
2502fe8fb19SBen Gras  *	  MAX_RECURSION.
2512fe8fb19SBen Gras  */
2522fe8fb19SBen Gras /* coverity[+alloc : arg-*0] */
2532fe8fb19SBen Gras static int
getent(char ** cap,size_t * len,const char * const * db_array,int fd,const char * name,int depth,char * nfield)2542fe8fb19SBen Gras getent(char **cap, size_t *len, const char * const *db_array, int fd,
2552fe8fb19SBen Gras     const char *name, int depth, char *nfield)
2562fe8fb19SBen Gras {
2572fe8fb19SBen Gras 	char *record, *newrecord;
2582fe8fb19SBen Gras 	char *r_end, *rp;	/* pacify gcc */
2592fe8fb19SBen Gras 	const char * const *db_p;
2602fe8fb19SBen Gras 	int myfd, eof, foundit;
2612fe8fb19SBen Gras 	int tc_not_resolved;
2622fe8fb19SBen Gras 
2632fe8fb19SBen Gras 	_DIAGASSERT(cap != NULL);
2642fe8fb19SBen Gras 	_DIAGASSERT(len != NULL);
2652fe8fb19SBen Gras 	_DIAGASSERT(db_array != NULL);
2662fe8fb19SBen Gras 	/* fd may be -1 */
2672fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
2682fe8fb19SBen Gras 	/* nfield may be NULL */
2692fe8fb19SBen Gras 
2702fe8fb19SBen Gras 	myfd = 0;
2712fe8fb19SBen Gras 	rp = NULL;
2722fe8fb19SBen Gras 
2732fe8fb19SBen Gras 	/*
2742fe8fb19SBen Gras 	 * Return with ``loop detected'' error if we've recursed more than
2752fe8fb19SBen Gras 	 * MAX_RECURSION times.
2762fe8fb19SBen Gras 	 */
2772fe8fb19SBen Gras 	if (depth > MAX_RECURSION)
2782fe8fb19SBen Gras 		return -3;
2792fe8fb19SBen Gras 
2802fe8fb19SBen Gras 	/*
2812fe8fb19SBen Gras 	 * Check if we have a top record from cgetset().
2822fe8fb19SBen Gras          */
2832fe8fb19SBen Gras 	if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
2842fe8fb19SBen Gras 		if ((record = malloc(topreclen + BFRAG)) == NULL) {
2852fe8fb19SBen Gras 			errno = ENOMEM;
2862fe8fb19SBen Gras 			return -2;
2872fe8fb19SBen Gras 		}
2882fe8fb19SBen Gras 		(void)strcpy(record, toprec);	/* XXX: strcpy is safe */
2892fe8fb19SBen Gras 		db_p = db_array;
2902fe8fb19SBen Gras 		rp = record + topreclen + 1;
2912fe8fb19SBen Gras 		r_end = rp + BFRAG;
2922fe8fb19SBen Gras 		goto tc_exp;
2932fe8fb19SBen Gras 	}
2942fe8fb19SBen Gras 	/*
2952fe8fb19SBen Gras 	 * Allocate first chunk of memory.
2962fe8fb19SBen Gras 	 */
2972fe8fb19SBen Gras 	if ((record = malloc(BFRAG)) == NULL) {
2982fe8fb19SBen Gras 		errno = ENOMEM;
2992fe8fb19SBen Gras 		return -2;
3002fe8fb19SBen Gras 	}
3012fe8fb19SBen Gras 	r_end = record + BFRAG;
3022fe8fb19SBen Gras 	foundit = 0;
3032fe8fb19SBen Gras 	/*
3042fe8fb19SBen Gras 	 * Loop through database array until finding the record.
3052fe8fb19SBen Gras 	 */
3062fe8fb19SBen Gras 
3072fe8fb19SBen Gras 	for (db_p = db_array; *db_p != NULL; db_p++) {
3082fe8fb19SBen Gras 		eof = 0;
3092fe8fb19SBen Gras 
3102fe8fb19SBen Gras 		/*
3112fe8fb19SBen Gras 		 * Open database if not already open.
3122fe8fb19SBen Gras 		 */
3132fe8fb19SBen Gras 
3142fe8fb19SBen Gras 		if (fd >= 0) {
3152fe8fb19SBen Gras 			(void)lseek(fd, (off_t)0, SEEK_SET);
3162fe8fb19SBen Gras 		} else {
3172fe8fb19SBen Gras #ifndef SMALL
318*0a6a1f1dSLionel Sambuc 			DB *capdbp;
319*0a6a1f1dSLionel Sambuc 			char pbuf[MAXPATHLEN];
320*0a6a1f1dSLionel Sambuc 			char *cbuf;
321*0a6a1f1dSLionel Sambuc 			int retval;
322*0a6a1f1dSLionel Sambuc 			size_t clen;
323*0a6a1f1dSLionel Sambuc 
3242fe8fb19SBen Gras 			(void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
325*0a6a1f1dSLionel Sambuc 			if ((capdbp = dbopen(pbuf, O_RDONLY | O_CLOEXEC, 0,
326*0a6a1f1dSLionel Sambuc 			    DB_HASH, 0)) != NULL) {
3272fe8fb19SBen Gras 				free(record);
3282fe8fb19SBen Gras 				retval = cdbget(capdbp, &record, name);
3292fe8fb19SBen Gras 				if (retval < 0) {
3302fe8fb19SBen Gras 					/* no record available */
3312fe8fb19SBen Gras 					(void)capdbp->close(capdbp);
3322fe8fb19SBen Gras 					return retval;
3332fe8fb19SBen Gras 				}
3342fe8fb19SBen Gras 				/* save the data; close frees it */
3352fe8fb19SBen Gras 				clen = strlen(record);
3362fe8fb19SBen Gras 				if ((cbuf = malloc(clen + 1)) == NULL) {
3372fe8fb19SBen Gras 					(void)capdbp->close(capdbp);
3382fe8fb19SBen Gras 					errno = ENOMEM;
3392fe8fb19SBen Gras 					return -2;
3402fe8fb19SBen Gras 				}
3412fe8fb19SBen Gras 				memmove(cbuf, record, clen + 1);
3422fe8fb19SBen Gras 				if (capdbp->close(capdbp) < 0) {
3432fe8fb19SBen Gras 					int serrno = errno;
3442fe8fb19SBen Gras 
3452fe8fb19SBen Gras 					free(cbuf);
3462fe8fb19SBen Gras 					errno = serrno;
3472fe8fb19SBen Gras 					return -2;
3482fe8fb19SBen Gras 				}
3492fe8fb19SBen Gras 				*len = clen;
3502fe8fb19SBen Gras 				*cap = cbuf;
3512fe8fb19SBen Gras 				return retval;
3522fe8fb19SBen Gras 			} else
3532fe8fb19SBen Gras #endif
3542fe8fb19SBen Gras 			{
355*0a6a1f1dSLionel Sambuc 				fd = open(*db_p, O_RDONLY | O_CLOEXEC, 0);
3562fe8fb19SBen Gras 				if (fd < 0) {
3572fe8fb19SBen Gras 					/* No error on unfound file. */
3582fe8fb19SBen Gras 					continue;
3592fe8fb19SBen Gras 				}
3602fe8fb19SBen Gras 				myfd = 1;
3612fe8fb19SBen Gras 			}
3622fe8fb19SBen Gras 		}
3632fe8fb19SBen Gras 		/*
3642fe8fb19SBen Gras 		 * Find the requested capability record ...
3652fe8fb19SBen Gras 		 */
3662fe8fb19SBen Gras 		{
3672fe8fb19SBen Gras 		char buf[BUFSIZ];
3682fe8fb19SBen Gras 		char *b_end, *bp, *cp;
3692fe8fb19SBen Gras 		int c, slash;
3702fe8fb19SBen Gras 
3712fe8fb19SBen Gras 		/*
3722fe8fb19SBen Gras 		 * Loop invariants:
3732fe8fb19SBen Gras 		 *	There is always room for one more character in record.
3742fe8fb19SBen Gras 		 *	R_end always points just past end of record.
3752fe8fb19SBen Gras 		 *	Rp always points just past last character in record.
3762fe8fb19SBen Gras 		 *	B_end always points just past last character in buf.
3772fe8fb19SBen Gras 		 *	Bp always points at next character in buf.
3782fe8fb19SBen Gras 		 *	Cp remembers where the last colon was.
3792fe8fb19SBen Gras 		 */
3802fe8fb19SBen Gras 		b_end = buf;
3812fe8fb19SBen Gras 		bp = buf;
3822fe8fb19SBen Gras 		cp = NULL;
3832fe8fb19SBen Gras 		slash = 0;
3842fe8fb19SBen Gras 		for (;;) {
3852fe8fb19SBen Gras 			/*
3862fe8fb19SBen Gras 			 * Read in a line implementing (\, newline)
3872fe8fb19SBen Gras 			 * line continuation.
3882fe8fb19SBen Gras 			 */
3892fe8fb19SBen Gras 			rp = record;
3902fe8fb19SBen Gras 			for (;;) {
3912fe8fb19SBen Gras 				if (bp >= b_end) {
392f14fb602SLionel Sambuc 					ssize_t n;
3932fe8fb19SBen Gras 
3942fe8fb19SBen Gras 					n = read(fd, buf, sizeof(buf));
3952fe8fb19SBen Gras 					if (n <= 0) {
3962fe8fb19SBen Gras 						if (myfd)
3972fe8fb19SBen Gras 							(void)close(fd);
3982fe8fb19SBen Gras 						if (n < 0) {
3992fe8fb19SBen Gras 							int serrno = errno;
4002fe8fb19SBen Gras 
4012fe8fb19SBen Gras 							free(record);
4022fe8fb19SBen Gras 							errno = serrno;
4032fe8fb19SBen Gras 							return -2;
4042fe8fb19SBen Gras 						} else {
4052fe8fb19SBen Gras 							fd = -1;
4062fe8fb19SBen Gras 							eof = 1;
4072fe8fb19SBen Gras 							break;
4082fe8fb19SBen Gras 						}
4092fe8fb19SBen Gras 					}
4102fe8fb19SBen Gras 					b_end = buf+n;
4112fe8fb19SBen Gras 					bp = buf;
4122fe8fb19SBen Gras 				}
4132fe8fb19SBen Gras 
4142fe8fb19SBen Gras 				c = *bp++;
4152fe8fb19SBen Gras 				if (c == '\n') {
4162fe8fb19SBen Gras 					if (slash) {
4172fe8fb19SBen Gras 						slash = 0;
4182fe8fb19SBen Gras 						rp--;
4192fe8fb19SBen Gras 						continue;
4202fe8fb19SBen Gras 					} else
4212fe8fb19SBen Gras 						break;
4222fe8fb19SBen Gras 				}
4232fe8fb19SBen Gras 				if (slash) {
4242fe8fb19SBen Gras 					slash = 0;
4252fe8fb19SBen Gras 					cp = 0;
4262fe8fb19SBen Gras 				}
4272fe8fb19SBen Gras 				if (c == ':') {
4282fe8fb19SBen Gras 					/*
4292fe8fb19SBen Gras 					 * If the field was `empty' (i.e.
4302fe8fb19SBen Gras 					 * contained only white space), back up
4312fe8fb19SBen Gras 					 * to the colon (eliminating the
4322fe8fb19SBen Gras 					 * field).
4332fe8fb19SBen Gras 					 */
4342fe8fb19SBen Gras 					if (cp != NULL)
4352fe8fb19SBen Gras 						rp = cp;
4362fe8fb19SBen Gras 					else
4372fe8fb19SBen Gras 						cp = rp;
4382fe8fb19SBen Gras 				} else if (c == '\\') {
4392fe8fb19SBen Gras 					slash = 1;
4402fe8fb19SBen Gras 				} else if (c != ' ' && c != '\t') {
4412fe8fb19SBen Gras 					/*
4422fe8fb19SBen Gras 					 * Forget where the colon was, as this
4432fe8fb19SBen Gras 					 * is not an empty field.
4442fe8fb19SBen Gras 					 */
4452fe8fb19SBen Gras 					cp = 0;
4462fe8fb19SBen Gras 				}
4472fe8fb19SBen Gras 				*rp++ = c;
4482fe8fb19SBen Gras 
4492fe8fb19SBen Gras 				/*
4502fe8fb19SBen Gras 				 * Enforce loop invariant: if no room
4512fe8fb19SBen Gras 				 * left in record buffer, try to get
4522fe8fb19SBen Gras 				 * some more.
4532fe8fb19SBen Gras 				 */
4542fe8fb19SBen Gras 				if (rp >= r_end) {
455f14fb602SLionel Sambuc 					ptrdiff_t pos;
4562fe8fb19SBen Gras 					size_t newsize;
4572fe8fb19SBen Gras 
4582fe8fb19SBen Gras 					pos = rp - record;
4592fe8fb19SBen Gras 					newsize = r_end - record + BFRAG;
4602fe8fb19SBen Gras 					newrecord = realloc(record, newsize);
4612fe8fb19SBen Gras 					if (newrecord == NULL) {
4622fe8fb19SBen Gras 						free(record);
4632fe8fb19SBen Gras 						if (myfd)
4642fe8fb19SBen Gras 							(void)close(fd);
4652fe8fb19SBen Gras 						errno = ENOMEM;
4662fe8fb19SBen Gras 						return -2;
4672fe8fb19SBen Gras 					}
4682fe8fb19SBen Gras 					record = newrecord;
4692fe8fb19SBen Gras 					r_end = record + newsize;
4702fe8fb19SBen Gras 					rp = record + pos;
4712fe8fb19SBen Gras 				}
4722fe8fb19SBen Gras 			}
4732fe8fb19SBen Gras 			/* Eliminate any white space after the last colon. */
4742fe8fb19SBen Gras 			if (cp)
4752fe8fb19SBen Gras 				rp = cp + 1;
4762fe8fb19SBen Gras 			/* Loop invariant lets us do this. */
4772fe8fb19SBen Gras 			*rp++ = '\0';
4782fe8fb19SBen Gras 
4792fe8fb19SBen Gras 			/*
4802fe8fb19SBen Gras 			 * If encountered eof check next file.
4812fe8fb19SBen Gras 			 */
4822fe8fb19SBen Gras 			if (eof)
4832fe8fb19SBen Gras 				break;
4842fe8fb19SBen Gras 
4852fe8fb19SBen Gras 			/*
4862fe8fb19SBen Gras 			 * Toss blank lines and comments.
4872fe8fb19SBen Gras 			 */
4882fe8fb19SBen Gras 			if (*record == '\0' || *record == '#')
4892fe8fb19SBen Gras 				continue;
4902fe8fb19SBen Gras 
4912fe8fb19SBen Gras 			/*
4922fe8fb19SBen Gras 			 * See if this is the record we want ...
4932fe8fb19SBen Gras 			 */
4942fe8fb19SBen Gras 			if (cgetmatch(record, name) == 0)
4952fe8fb19SBen Gras 				if (nfield == NULL || !nfcmp(nfield, record)) {
4962fe8fb19SBen Gras 					foundit = 1;
4972fe8fb19SBen Gras 					break;	/* found it! */
4982fe8fb19SBen Gras 				}
4992fe8fb19SBen Gras 		}
5002fe8fb19SBen Gras 		}
5012fe8fb19SBen Gras 		if (foundit)
5022fe8fb19SBen Gras 			break;
5032fe8fb19SBen Gras 	}
5042fe8fb19SBen Gras 
5052fe8fb19SBen Gras 	if (!foundit)
5062fe8fb19SBen Gras 		return -1;
5072fe8fb19SBen Gras 
5082fe8fb19SBen Gras 	/*
5092fe8fb19SBen Gras 	 * Got the capability record, but now we have to expand all tc=name
5102fe8fb19SBen Gras 	 * references in it ...
5112fe8fb19SBen Gras 	 */
5122fe8fb19SBen Gras tc_exp:
5132fe8fb19SBen Gras 	tc_not_resolved = 0;
5142fe8fb19SBen Gras 	if (expandtc) {
5152fe8fb19SBen Gras 		char *newicap, *s;
5162fe8fb19SBen Gras 		size_t ilen, newilen;
517f14fb602SLionel Sambuc 		int iret;
518f14fb602SLionel Sambuc 		ptrdiff_t diff, tclen;
5192fe8fb19SBen Gras 		char *icap, *scan, *tc, *tcstart, *tcend;
5202fe8fb19SBen Gras 
5212fe8fb19SBen Gras 		/*
5222fe8fb19SBen Gras 		 * Loop invariants:
5232fe8fb19SBen Gras 		 *	There is room for one more character in record.
5242fe8fb19SBen Gras 		 *	R_end points just past end of record.
5252fe8fb19SBen Gras 		 *	Rp points just past last character in record.
5262fe8fb19SBen Gras 		 *	Scan points at remainder of record that needs to be
5272fe8fb19SBen Gras 		 *	scanned for tc=name constructs.
5282fe8fb19SBen Gras 		 */
5292fe8fb19SBen Gras 		scan = record;
5302fe8fb19SBen Gras 		for (;;) {
5312fe8fb19SBen Gras 			if ((tc = cgetcap(scan, "tc", '=')) == NULL)
5322fe8fb19SBen Gras 				break;
5332fe8fb19SBen Gras 
5342fe8fb19SBen Gras 			/*
5352fe8fb19SBen Gras 			 * Find end of tc=name and stomp on the trailing `:'
5362fe8fb19SBen Gras 			 * (if present) so we can use it to call ourselves.
5372fe8fb19SBen Gras 			 */
5382fe8fb19SBen Gras 			s = tc;
5392fe8fb19SBen Gras 			for (;;)
5402fe8fb19SBen Gras 				if (*s == '\0')
5412fe8fb19SBen Gras 					break;
5422fe8fb19SBen Gras 				else
5432fe8fb19SBen Gras 					if (*s++ == ':') {
5442fe8fb19SBen Gras 						*(s - 1) = '\0';
5452fe8fb19SBen Gras 						break;
5462fe8fb19SBen Gras 					}
5472fe8fb19SBen Gras 			tcstart = tc - 3;
5482fe8fb19SBen Gras 			tclen = s - tcstart;
5492fe8fb19SBen Gras 			tcend = s;
5502fe8fb19SBen Gras 
5512fe8fb19SBen Gras 			iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
5522fe8fb19SBen Gras 				      NULL);
5532fe8fb19SBen Gras 			newicap = icap;		/* Put into a register. */
5542fe8fb19SBen Gras 			newilen = ilen;
5552fe8fb19SBen Gras 			if (iret != 0) {
5562fe8fb19SBen Gras 				/* an error */
5572fe8fb19SBen Gras 				if (iret < -1) {
5582fe8fb19SBen Gras 					if (myfd)
5592fe8fb19SBen Gras 						(void)close(fd);
5602fe8fb19SBen Gras 					free(record);
5612fe8fb19SBen Gras 					return iret;
5622fe8fb19SBen Gras 				}
5632fe8fb19SBen Gras 				if (iret == 1)
5642fe8fb19SBen Gras 					tc_not_resolved = 1;
5652fe8fb19SBen Gras 				/* couldn't resolve tc */
5662fe8fb19SBen Gras 				if (iret == -1) {
5672fe8fb19SBen Gras 					*(s - 1) = ':';
5682fe8fb19SBen Gras 					scan = s - 1;
5692fe8fb19SBen Gras 					tc_not_resolved = 1;
5702fe8fb19SBen Gras 					continue;
5712fe8fb19SBen Gras 
5722fe8fb19SBen Gras 				}
5732fe8fb19SBen Gras 			}
5742fe8fb19SBen Gras 			/* not interested in name field of tc'ed record */
5752fe8fb19SBen Gras 			s = newicap;
5762fe8fb19SBen Gras 			for (;;)
5772fe8fb19SBen Gras 				if (*s == '\0')
5782fe8fb19SBen Gras 					break;
5792fe8fb19SBen Gras 				else if (*s++ == ':')
5802fe8fb19SBen Gras 					break;
5812fe8fb19SBen Gras 			newilen -= s - newicap;
5822fe8fb19SBen Gras 			newicap = s;
5832fe8fb19SBen Gras 
5842fe8fb19SBen Gras 			/* make sure interpolated record is `:'-terminated */
5852fe8fb19SBen Gras 			s += newilen;
5862fe8fb19SBen Gras 			if (*(s - 1) != ':') {
5872fe8fb19SBen Gras 				*s = ':';	/* overwrite NUL with : */
5882fe8fb19SBen Gras 				newilen++;
5892fe8fb19SBen Gras 			}
5902fe8fb19SBen Gras 
5912fe8fb19SBen Gras 			/*
5922fe8fb19SBen Gras 			 * Make sure there's enough room to insert the
5932fe8fb19SBen Gras 			 * new record.
5942fe8fb19SBen Gras 			 */
5952fe8fb19SBen Gras 			diff = newilen - tclen;
5962fe8fb19SBen Gras 			if (diff >= r_end - rp) {
597f14fb602SLionel Sambuc 				ptrdiff_t pos, tcpos, tcposend;
5982fe8fb19SBen Gras 				size_t newsize;
5992fe8fb19SBen Gras 
6002fe8fb19SBen Gras 				pos = rp - record;
6012fe8fb19SBen Gras 				newsize = r_end - record + diff + BFRAG;
6022fe8fb19SBen Gras 				tcpos = tcstart - record;
6032fe8fb19SBen Gras 				tcposend = tcend - record;
6042fe8fb19SBen Gras 				newrecord = realloc(record, newsize);
6052fe8fb19SBen Gras 				if (newrecord == NULL) {
6062fe8fb19SBen Gras 					free(record);
6072fe8fb19SBen Gras 					if (myfd)
6082fe8fb19SBen Gras 						(void)close(fd);
6092fe8fb19SBen Gras 					free(icap);
6102fe8fb19SBen Gras 					errno = ENOMEM;
6112fe8fb19SBen Gras 					return -2;
6122fe8fb19SBen Gras 				}
6132fe8fb19SBen Gras 				record = newrecord;
6142fe8fb19SBen Gras 				r_end = record + newsize;
6152fe8fb19SBen Gras 				rp = record + pos;
6162fe8fb19SBen Gras 				tcstart = record + tcpos;
6172fe8fb19SBen Gras 				tcend = record + tcposend;
6182fe8fb19SBen Gras 			}
6192fe8fb19SBen Gras 
6202fe8fb19SBen Gras 			/*
6212fe8fb19SBen Gras 			 * Insert tc'ed record into our record.
6222fe8fb19SBen Gras 			 */
6232fe8fb19SBen Gras 			s = tcstart + newilen;
6242fe8fb19SBen Gras 			memmove(s, tcend,  (size_t)(rp - tcend));
6252fe8fb19SBen Gras 			memmove(tcstart, newicap, newilen);
6262fe8fb19SBen Gras 			rp += diff;
6272fe8fb19SBen Gras 			free(icap);
6282fe8fb19SBen Gras 
6292fe8fb19SBen Gras 			/*
6302fe8fb19SBen Gras 			 * Start scan on `:' so next cgetcap works properly
6312fe8fb19SBen Gras 			 * (cgetcap always skips first field).
6322fe8fb19SBen Gras 			 */
6332fe8fb19SBen Gras 			scan = s - 1;
6342fe8fb19SBen Gras 		}
6352fe8fb19SBen Gras 
6362fe8fb19SBen Gras 	}
6372fe8fb19SBen Gras 	/*
6382fe8fb19SBen Gras 	 * Close file (if we opened it), give back any extra memory, and
6392fe8fb19SBen Gras 	 * return capability, length and success.
6402fe8fb19SBen Gras 	 */
6412fe8fb19SBen Gras 	if (myfd)
6422fe8fb19SBen Gras 		(void)close(fd);
6432fe8fb19SBen Gras 	*len = rp - record - 1;	/* don't count NUL */
6442fe8fb19SBen Gras 	if (r_end > rp) {
6452fe8fb19SBen Gras 		if ((newrecord =
6462fe8fb19SBen Gras 		     realloc(record, (size_t)(rp - record))) == NULL) {
6472fe8fb19SBen Gras 			free(record);
6482fe8fb19SBen Gras 			errno = ENOMEM;
6492fe8fb19SBen Gras 			return -2;
6502fe8fb19SBen Gras 		}
6512fe8fb19SBen Gras 		record = newrecord;
6522fe8fb19SBen Gras 	}
6532fe8fb19SBen Gras 
6542fe8fb19SBen Gras 	*cap = record;
6552fe8fb19SBen Gras 	if (tc_not_resolved)
6562fe8fb19SBen Gras 		return 1;
6572fe8fb19SBen Gras 	return 0;
6582fe8fb19SBen Gras }
6592fe8fb19SBen Gras 
6602fe8fb19SBen Gras #ifndef SMALL
6612fe8fb19SBen Gras static int
cdbget(DB * capdbp,char ** bp,const char * name)6622fe8fb19SBen Gras cdbget(DB *capdbp, char **bp, const char *name)
6632fe8fb19SBen Gras {
6642fe8fb19SBen Gras 	DBT key;
6652fe8fb19SBen Gras 	DBT data;
6662fe8fb19SBen Gras 
6672fe8fb19SBen Gras 	_DIAGASSERT(capdbp != NULL);
6682fe8fb19SBen Gras 	_DIAGASSERT(bp != NULL);
6692fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
6702fe8fb19SBen Gras 
6712fe8fb19SBen Gras 	key.data = __UNCONST(name);
6722fe8fb19SBen Gras 	key.size = strlen(name);
6732fe8fb19SBen Gras 
6742fe8fb19SBen Gras 	for (;;) {
6752fe8fb19SBen Gras 		/* Get the reference. */
6762fe8fb19SBen Gras 		switch(capdbp->get(capdbp, &key, &data, 0)) {
6772fe8fb19SBen Gras 		case -1:
6782fe8fb19SBen Gras 			return -2;
6792fe8fb19SBen Gras 		case 1:
6802fe8fb19SBen Gras 			return -1;
6812fe8fb19SBen Gras 		}
6822fe8fb19SBen Gras 
6832fe8fb19SBen Gras 		/* If not an index to another record, leave. */
6842fe8fb19SBen Gras 		if (((char *)data.data)[0] != SHADOW)
6852fe8fb19SBen Gras 			break;
6862fe8fb19SBen Gras 
6872fe8fb19SBen Gras 		key.data = (char *)data.data + 1;
6882fe8fb19SBen Gras 		key.size = data.size - 1;
6892fe8fb19SBen Gras 	}
6902fe8fb19SBen Gras 
6912fe8fb19SBen Gras 	*bp = (char *)data.data + 1;
6922fe8fb19SBen Gras 	return ((char *)(data.data))[0] == TCERR ? 1 : 0;
6932fe8fb19SBen Gras }
6942fe8fb19SBen Gras #endif
6952fe8fb19SBen Gras 
6962fe8fb19SBen Gras /*
6972fe8fb19SBen Gras  * Cgetmatch will return 0 if name is one of the names of the capability
6982fe8fb19SBen Gras  * record buf, -1 if not.
6992fe8fb19SBen Gras  */
7002fe8fb19SBen Gras int
cgetmatch(const char * buf,const char * name)7012fe8fb19SBen Gras cgetmatch(const char *buf, const char *name)
7022fe8fb19SBen Gras {
7032fe8fb19SBen Gras 	const char *np, *bp;
7042fe8fb19SBen Gras 
7052fe8fb19SBen Gras 	_DIAGASSERT(buf != NULL);
7062fe8fb19SBen Gras 	_DIAGASSERT(name != NULL);
7072fe8fb19SBen Gras 
7082fe8fb19SBen Gras 	/*
7092fe8fb19SBen Gras 	 * Start search at beginning of record.
7102fe8fb19SBen Gras 	 */
7112fe8fb19SBen Gras 	bp = buf;
7122fe8fb19SBen Gras 	for (;;) {
7132fe8fb19SBen Gras 		/*
7142fe8fb19SBen Gras 		 * Try to match a record name.
7152fe8fb19SBen Gras 		 */
7162fe8fb19SBen Gras 		np = name;
7172fe8fb19SBen Gras 		for (;;)
7182fe8fb19SBen Gras 			if (*np == '\0') {
7192fe8fb19SBen Gras 				if (*bp == '|' || *bp == ':' || *bp == '\0')
7202fe8fb19SBen Gras 					return 0;
7212fe8fb19SBen Gras 				else
7222fe8fb19SBen Gras 					break;
7232fe8fb19SBen Gras 			} else if (*bp++ != *np++)
7242fe8fb19SBen Gras 				break;
7252fe8fb19SBen Gras 
7262fe8fb19SBen Gras 		/*
7272fe8fb19SBen Gras 		 * Match failed, skip to next name in record.
7282fe8fb19SBen Gras 		 */
7292fe8fb19SBen Gras 		if (bp > buf)
7302fe8fb19SBen Gras 			bp--;	/* a '|' or ':' may have stopped the match */
7312fe8fb19SBen Gras 		else
7322fe8fb19SBen Gras 			return -1;
7332fe8fb19SBen Gras 		for (;;)
7342fe8fb19SBen Gras 			if (*bp == '\0' || *bp == ':')
7352fe8fb19SBen Gras 				return -1;	/* match failed totally */
7362fe8fb19SBen Gras 			else if (*bp++ == '|')
7372fe8fb19SBen Gras 				break;		/* found next name */
7382fe8fb19SBen Gras 	}
7392fe8fb19SBen Gras }
7402fe8fb19SBen Gras 
7412fe8fb19SBen Gras int
cgetfirst(char ** buf,const char * const * db_array)7422fe8fb19SBen Gras cgetfirst(char **buf, const char * const *db_array)
7432fe8fb19SBen Gras {
7442fe8fb19SBen Gras 
7452fe8fb19SBen Gras 	_DIAGASSERT(buf != NULL);
7462fe8fb19SBen Gras 	_DIAGASSERT(db_array != NULL);
7472fe8fb19SBen Gras 
7482fe8fb19SBen Gras 	(void)cgetclose();
7492fe8fb19SBen Gras 	return cgetnext(buf, db_array);
7502fe8fb19SBen Gras }
7512fe8fb19SBen Gras 
7522fe8fb19SBen Gras static FILE *pfp;
7532fe8fb19SBen Gras static int slash;
7542fe8fb19SBen Gras static const char * const *dbp;
7552fe8fb19SBen Gras 
7562fe8fb19SBen Gras int
cgetclose(void)7572fe8fb19SBen Gras cgetclose(void)
7582fe8fb19SBen Gras {
7592fe8fb19SBen Gras 	if (pfp != NULL) {
7602fe8fb19SBen Gras 		(void)fclose(pfp);
7612fe8fb19SBen Gras 		pfp = NULL;
7622fe8fb19SBen Gras 	}
7632fe8fb19SBen Gras 	dbp = NULL;
7642fe8fb19SBen Gras 	gottoprec = 0;
7652fe8fb19SBen Gras 	slash = 0;
7662fe8fb19SBen Gras 	return 0;
7672fe8fb19SBen Gras }
7682fe8fb19SBen Gras 
7692fe8fb19SBen Gras /*
7702fe8fb19SBen Gras  * Cgetnext() gets either the first or next entry in the logical database
7712fe8fb19SBen Gras  * specified by db_array.  It returns 0 upon completion of the database, 1
7722fe8fb19SBen Gras  * upon returning an entry with more remaining, and -1 if an error occurs.
7732fe8fb19SBen Gras  */
7742fe8fb19SBen Gras /* coverity[+alloc : arg-*0] */
7752fe8fb19SBen Gras int
cgetnext(char ** bp,const char * const * db_array)7762fe8fb19SBen Gras cgetnext(char **bp, const char * const *db_array)
7772fe8fb19SBen Gras {
7782fe8fb19SBen Gras 	size_t len = 0;
7792fe8fb19SBen Gras 	int status, done;
7802fe8fb19SBen Gras 	char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
7812fe8fb19SBen Gras 	size_t dummy;
7822fe8fb19SBen Gras 
7832fe8fb19SBen Gras 	_DIAGASSERT(bp != NULL);
7842fe8fb19SBen Gras 	_DIAGASSERT(db_array != NULL);
7852fe8fb19SBen Gras 
7862fe8fb19SBen Gras 	if (dbp == NULL)
7872fe8fb19SBen Gras 		dbp = db_array;
7882fe8fb19SBen Gras 
789f14fb602SLionel Sambuc 	if (pfp == NULL && (pfp = fopen(*dbp, "re")) == NULL) {
7902fe8fb19SBen Gras 		(void)cgetclose();
7912fe8fb19SBen Gras 		return -1;
7922fe8fb19SBen Gras 	}
7932fe8fb19SBen Gras 	for (;;) {
7942fe8fb19SBen Gras 		if (toprec != NULL && !gottoprec) {
7952fe8fb19SBen Gras 			gottoprec = 1;
7962fe8fb19SBen Gras 			line = toprec;
7972fe8fb19SBen Gras 		} else {
7982fe8fb19SBen Gras 			line = fgetln(pfp, &len);
7992fe8fb19SBen Gras 			if (line == NULL) {
8002fe8fb19SBen Gras 				if (pfp == NULL)
8012fe8fb19SBen Gras 					return -1;
8022fe8fb19SBen Gras 				if (ferror(pfp)) {
8032fe8fb19SBen Gras 					(void)cgetclose();
8042fe8fb19SBen Gras 					return -1;
8052fe8fb19SBen Gras 				} else {
8062fe8fb19SBen Gras 					(void)fclose(pfp);
8072fe8fb19SBen Gras 					pfp = NULL;
8082fe8fb19SBen Gras 					if (*++dbp == NULL) {
8092fe8fb19SBen Gras 						(void)cgetclose();
8102fe8fb19SBen Gras 						return 0;
8112fe8fb19SBen Gras 					} else if ((pfp =
812f14fb602SLionel Sambuc 					    fopen(*dbp, "re")) == NULL) {
8132fe8fb19SBen Gras 						(void)cgetclose();
8142fe8fb19SBen Gras 						return -1;
8152fe8fb19SBen Gras 					} else
8162fe8fb19SBen Gras 						continue;
8172fe8fb19SBen Gras 				}
8182fe8fb19SBen Gras 			} else
8192fe8fb19SBen Gras 				line[len - 1] = '\0';
8202fe8fb19SBen Gras 			if (len == 1) {
8212fe8fb19SBen Gras 				slash = 0;
8222fe8fb19SBen Gras 				continue;
8232fe8fb19SBen Gras 			}
8242fe8fb19SBen Gras 			if (isspace((unsigned char)*line) ||
8252fe8fb19SBen Gras 			    *line == ':' || *line == '#' || slash) {
8262fe8fb19SBen Gras 				if (line[len - 2] == '\\')
8272fe8fb19SBen Gras 					slash = 1;
8282fe8fb19SBen Gras 				else
8292fe8fb19SBen Gras 					slash = 0;
8302fe8fb19SBen Gras 				continue;
8312fe8fb19SBen Gras 			}
8322fe8fb19SBen Gras 			if (line[len - 2] == '\\')
8332fe8fb19SBen Gras 				slash = 1;
8342fe8fb19SBen Gras 			else
8352fe8fb19SBen Gras 				slash = 0;
8362fe8fb19SBen Gras 		}
8372fe8fb19SBen Gras 
8382fe8fb19SBen Gras 
8392fe8fb19SBen Gras 		/*
8402fe8fb19SBen Gras 		 * Line points to a name line.
8412fe8fb19SBen Gras 		 */
8422fe8fb19SBen Gras 		if (len > sizeof(nbuf))
8432fe8fb19SBen Gras 			return -1;
8442fe8fb19SBen Gras 		done = 0;
8452fe8fb19SBen Gras 		np = nbuf;
8462fe8fb19SBen Gras 		for (;;) {
8472fe8fb19SBen Gras 			for (cp = line; *cp != '\0'; cp++) {
8482fe8fb19SBen Gras 				if (*cp == ':') {
8492fe8fb19SBen Gras 					*np++ = ':';
8502fe8fb19SBen Gras 					done = 1;
8512fe8fb19SBen Gras 					break;
8522fe8fb19SBen Gras 				}
8532fe8fb19SBen Gras 				if (*cp == '\\')
8542fe8fb19SBen Gras 					break;
8552fe8fb19SBen Gras 				*np++ = *cp;
8562fe8fb19SBen Gras 			}
8572fe8fb19SBen Gras 			if (done) {
8582fe8fb19SBen Gras 				*np = '\0';
8592fe8fb19SBen Gras 				break;
8602fe8fb19SBen Gras 			} else { /* name field extends beyond the line */
8612fe8fb19SBen Gras 				line = fgetln(pfp, &len);
8622fe8fb19SBen Gras 				if (line == NULL && pfp) {
8632fe8fb19SBen Gras 					if (ferror(pfp)) {
8642fe8fb19SBen Gras 						(void)cgetclose();
8652fe8fb19SBen Gras 						return -1;
8662fe8fb19SBen Gras 					}
8672fe8fb19SBen Gras 					(void)fclose(pfp);
8682fe8fb19SBen Gras 					pfp = NULL;
8692fe8fb19SBen Gras 					*np = '\0';
8702fe8fb19SBen Gras 					break;
8712fe8fb19SBen Gras 				} else
8722fe8fb19SBen Gras 					line[len - 1] = '\0';
8732fe8fb19SBen Gras 			}
8742fe8fb19SBen Gras 		}
8752fe8fb19SBen Gras 		if (len > sizeof(buf))
8762fe8fb19SBen Gras 			return -1;
8772fe8fb19SBen Gras 		rp = buf;
8782fe8fb19SBen Gras 		for (cp = nbuf; *cp != '\0'; cp++)
8792fe8fb19SBen Gras 			if (*cp == '|' || *cp == ':')
8802fe8fb19SBen Gras 				break;
8812fe8fb19SBen Gras 			else
8822fe8fb19SBen Gras 				*rp++ = *cp;
8832fe8fb19SBen Gras 
8842fe8fb19SBen Gras 		*rp = '\0';
8852fe8fb19SBen Gras 		/*
8862fe8fb19SBen Gras 		 * XXX
8872fe8fb19SBen Gras 		 * Last argument of getent here should be nbuf if we want true
8882fe8fb19SBen Gras 		 * sequential access in the case of duplicates.
8892fe8fb19SBen Gras 		 * With NULL, getent will return the first entry found
8902fe8fb19SBen Gras 		 * rather than the duplicate entry record.  This is a
8912fe8fb19SBen Gras 		 * matter of semantics that should be resolved.
8922fe8fb19SBen Gras 		 */
8932fe8fb19SBen Gras 		status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
8942fe8fb19SBen Gras 		if (status == -2 || status == -3)
8952fe8fb19SBen Gras 			(void)cgetclose();
8962fe8fb19SBen Gras 
8972fe8fb19SBen Gras 		return status + 1;
8982fe8fb19SBen Gras 	}
8992fe8fb19SBen Gras 	/* NOTREACHED */
9002fe8fb19SBen Gras }
9012fe8fb19SBen Gras 
9022fe8fb19SBen Gras /*
9032fe8fb19SBen Gras  * Cgetstr retrieves the value of the string capability cap from the
9042fe8fb19SBen Gras  * capability record pointed to by buf.  A pointer to a decoded, NUL
9052fe8fb19SBen Gras  * terminated, malloc'd copy of the string is returned in the char *
9062fe8fb19SBen Gras  * pointed to by str.  The length of the string not including the trailing
9072fe8fb19SBen Gras  * NUL is returned on success, -1 if the requested string capability
9082fe8fb19SBen Gras  * couldn't be found, -2 if a system error was encountered (storage
9092fe8fb19SBen Gras  * allocation failure).
9102fe8fb19SBen Gras  */
9112fe8fb19SBen Gras int
cgetstr(char * buf,const char * cap,char ** str)9122fe8fb19SBen Gras cgetstr(char *buf, const char *cap, char **str)
9132fe8fb19SBen Gras {
9142fe8fb19SBen Gras 	u_int m_room;
9152fe8fb19SBen Gras 	const char *bp;
9162fe8fb19SBen Gras 	char *mp;
917f14fb602SLionel Sambuc 	ptrdiff_t len;
9182fe8fb19SBen Gras 	char *mem, *newmem;
9192fe8fb19SBen Gras 
9202fe8fb19SBen Gras 	_DIAGASSERT(buf != NULL);
9212fe8fb19SBen Gras 	_DIAGASSERT(cap != NULL);
9222fe8fb19SBen Gras 	_DIAGASSERT(str != NULL);
9232fe8fb19SBen Gras 
9242fe8fb19SBen Gras 	/*
9252fe8fb19SBen Gras 	 * Find string capability cap
9262fe8fb19SBen Gras 	 */
9272fe8fb19SBen Gras 	bp = cgetcap(buf, cap, '=');
9282fe8fb19SBen Gras 	if (bp == NULL)
9292fe8fb19SBen Gras 		return -1;
9302fe8fb19SBen Gras 
9312fe8fb19SBen Gras 	/*
9322fe8fb19SBen Gras 	 * Conversion / storage allocation loop ...  Allocate memory in
9332fe8fb19SBen Gras 	 * chunks SFRAG in size.
9342fe8fb19SBen Gras 	 */
9352fe8fb19SBen Gras 	if ((mem = malloc(SFRAG)) == NULL) {
9362fe8fb19SBen Gras 		errno = ENOMEM;
9372fe8fb19SBen Gras 		return -2;	/* couldn't even allocate the first fragment */
9382fe8fb19SBen Gras 	}
9392fe8fb19SBen Gras 	m_room = SFRAG;
9402fe8fb19SBen Gras 	mp = mem;
9412fe8fb19SBen Gras 
9422fe8fb19SBen Gras 	while (*bp != ':' && *bp != '\0') {
9432fe8fb19SBen Gras 		/*
9442fe8fb19SBen Gras 		 * Loop invariants:
9452fe8fb19SBen Gras 		 *	There is always room for one more character in mem.
9462fe8fb19SBen Gras 		 *	Mp always points just past last character in mem.
9472fe8fb19SBen Gras 		 *	Bp always points at next character in buf.
9482fe8fb19SBen Gras 		 */
9492fe8fb19SBen Gras 		if (*bp == '^') {
9502fe8fb19SBen Gras 			bp++;
9512fe8fb19SBen Gras 			if (*bp == ':' || *bp == '\0')
9522fe8fb19SBen Gras 				break;	/* drop unfinished escape */
9532fe8fb19SBen Gras 			*mp++ = *bp++ & 037;
9542fe8fb19SBen Gras 		} else if (*bp == '\\') {
9552fe8fb19SBen Gras 			bp++;
9562fe8fb19SBen Gras 			if (*bp == ':' || *bp == '\0')
9572fe8fb19SBen Gras 				break;	/* drop unfinished escape */
9582fe8fb19SBen Gras 			if ('0' <= *bp && *bp <= '7') {
9592fe8fb19SBen Gras 				int n, i;
9602fe8fb19SBen Gras 
9612fe8fb19SBen Gras 				n = 0;
9622fe8fb19SBen Gras 				i = 3;	/* maximum of three octal digits */
9632fe8fb19SBen Gras 				do {
9642fe8fb19SBen Gras 					n = n * 8 + (*bp++ - '0');
9652fe8fb19SBen Gras 				} while (--i && '0' <= *bp && *bp <= '7');
9662fe8fb19SBen Gras 				*mp++ = n;
9672fe8fb19SBen Gras 			}
9682fe8fb19SBen Gras 			else switch (*bp++) {
9692fe8fb19SBen Gras 				case 'b': case 'B':
9702fe8fb19SBen Gras 					*mp++ = '\b';
9712fe8fb19SBen Gras 					break;
9722fe8fb19SBen Gras 				case 't': case 'T':
9732fe8fb19SBen Gras 					*mp++ = '\t';
9742fe8fb19SBen Gras 					break;
9752fe8fb19SBen Gras 				case 'n': case 'N':
9762fe8fb19SBen Gras 					*mp++ = '\n';
9772fe8fb19SBen Gras 					break;
9782fe8fb19SBen Gras 				case 'f': case 'F':
9792fe8fb19SBen Gras 					*mp++ = '\f';
9802fe8fb19SBen Gras 					break;
9812fe8fb19SBen Gras 				case 'r': case 'R':
9822fe8fb19SBen Gras 					*mp++ = '\r';
9832fe8fb19SBen Gras 					break;
9842fe8fb19SBen Gras 				case 'e': case 'E':
9852fe8fb19SBen Gras 					*mp++ = ESC;
9862fe8fb19SBen Gras 					break;
9872fe8fb19SBen Gras 				case 'c': case 'C':
9882fe8fb19SBen Gras 					*mp++ = ':';
9892fe8fb19SBen Gras 					break;
9902fe8fb19SBen Gras 				default:
9912fe8fb19SBen Gras 					/*
9922fe8fb19SBen Gras 					 * Catches '\', '^', and
9932fe8fb19SBen Gras 					 *  everything else.
9942fe8fb19SBen Gras 					 */
9952fe8fb19SBen Gras 					*mp++ = *(bp-1);
9962fe8fb19SBen Gras 					break;
9972fe8fb19SBen Gras 			}
9982fe8fb19SBen Gras 		} else
9992fe8fb19SBen Gras 			*mp++ = *bp++;
10002fe8fb19SBen Gras 		m_room--;
10012fe8fb19SBen Gras 
10022fe8fb19SBen Gras 		/*
10032fe8fb19SBen Gras 		 * Enforce loop invariant: if no room left in current
10042fe8fb19SBen Gras 		 * buffer, try to get some more.
10052fe8fb19SBen Gras 		 */
10062fe8fb19SBen Gras 		if (m_room == 0) {
10072fe8fb19SBen Gras 			size_t size = mp - mem;
10082fe8fb19SBen Gras 
10092fe8fb19SBen Gras 			if ((newmem = realloc(mem, size + SFRAG)) == NULL) {
10102fe8fb19SBen Gras 				free(mem);
10112fe8fb19SBen Gras 				return -2;
10122fe8fb19SBen Gras 			}
10132fe8fb19SBen Gras 			mem = newmem;
10142fe8fb19SBen Gras 			m_room = SFRAG;
10152fe8fb19SBen Gras 			mp = mem + size;
10162fe8fb19SBen Gras 		}
10172fe8fb19SBen Gras 	}
10182fe8fb19SBen Gras 	*mp++ = '\0';	/* loop invariant let's us do this */
10192fe8fb19SBen Gras 	m_room--;
10202fe8fb19SBen Gras 	len = mp - mem - 1;
10212fe8fb19SBen Gras 
10222fe8fb19SBen Gras 	/*
10232fe8fb19SBen Gras 	 * Give back any extra memory and return value and success.
10242fe8fb19SBen Gras 	 */
10252fe8fb19SBen Gras 	if (m_room != 0) {
10262fe8fb19SBen Gras 		if ((newmem = realloc(mem, (size_t)(mp - mem))) == NULL) {
10272fe8fb19SBen Gras 			free(mem);
10282fe8fb19SBen Gras 			return -2;
10292fe8fb19SBen Gras 		}
10302fe8fb19SBen Gras 		mem = newmem;
10312fe8fb19SBen Gras 	}
10322fe8fb19SBen Gras 	*str = mem;
1033f14fb602SLionel Sambuc 	_DIAGASSERT(__type_fit(int, len));
1034f14fb602SLionel Sambuc 	return (int)len;
10352fe8fb19SBen Gras }
10362fe8fb19SBen Gras 
10372fe8fb19SBen Gras /*
10382fe8fb19SBen Gras  * Cgetustr retrieves the value of the string capability cap from the
10392fe8fb19SBen Gras  * capability record pointed to by buf.  The difference between cgetustr()
10402fe8fb19SBen Gras  * and cgetstr() is that cgetustr does not decode escapes but rather treats
10412fe8fb19SBen Gras  * all characters literally.  A pointer to a  NUL terminated malloc'd
10422fe8fb19SBen Gras  * copy of the string is returned in the char pointed to by str.  The
10432fe8fb19SBen Gras  * length of the string not including the trailing NUL is returned on success,
10442fe8fb19SBen Gras  * -1 if the requested string capability couldn't be found, -2 if a system
10452fe8fb19SBen Gras  * error was encountered (storage allocation failure).
10462fe8fb19SBen Gras  */
10472fe8fb19SBen Gras int
cgetustr(char * buf,const char * cap,char ** str)10482fe8fb19SBen Gras cgetustr(char *buf, const char *cap, char **str)
10492fe8fb19SBen Gras {
10502fe8fb19SBen Gras 	u_int m_room;
10512fe8fb19SBen Gras 	const char *bp;
10522fe8fb19SBen Gras 	char *mp;
1053f14fb602SLionel Sambuc 	size_t len;
10542fe8fb19SBen Gras 	char *mem, *newmem;
10552fe8fb19SBen Gras 
10562fe8fb19SBen Gras 	_DIAGASSERT(buf != NULL);
10572fe8fb19SBen Gras 	_DIAGASSERT(cap != NULL);
10582fe8fb19SBen Gras 	_DIAGASSERT(str != NULL);
10592fe8fb19SBen Gras 
10602fe8fb19SBen Gras 	/*
10612fe8fb19SBen Gras 	 * Find string capability cap
10622fe8fb19SBen Gras 	 */
10632fe8fb19SBen Gras 	if ((bp = cgetcap(buf, cap, '=')) == NULL)
10642fe8fb19SBen Gras 		return -1;
10652fe8fb19SBen Gras 
10662fe8fb19SBen Gras 	/*
10672fe8fb19SBen Gras 	 * Conversion / storage allocation loop ...  Allocate memory in
10682fe8fb19SBen Gras 	 * chunks SFRAG in size.
10692fe8fb19SBen Gras 	 */
10702fe8fb19SBen Gras 	if ((mem = malloc(SFRAG)) == NULL) {
10712fe8fb19SBen Gras 		errno = ENOMEM;
10722fe8fb19SBen Gras 		return -2;	/* couldn't even allocate the first fragment */
10732fe8fb19SBen Gras 	}
10742fe8fb19SBen Gras 	m_room = SFRAG;
10752fe8fb19SBen Gras 	mp = mem;
10762fe8fb19SBen Gras 
10772fe8fb19SBen Gras 	while (*bp != ':' && *bp != '\0') {
10782fe8fb19SBen Gras 		/*
10792fe8fb19SBen Gras 		 * Loop invariants:
10802fe8fb19SBen Gras 		 *	There is always room for one more character in mem.
10812fe8fb19SBen Gras 		 *	Mp always points just past last character in mem.
10822fe8fb19SBen Gras 		 *	Bp always points at next character in buf.
10832fe8fb19SBen Gras 		 */
10842fe8fb19SBen Gras 		*mp++ = *bp++;
10852fe8fb19SBen Gras 		m_room--;
10862fe8fb19SBen Gras 
10872fe8fb19SBen Gras 		/*
10882fe8fb19SBen Gras 		 * Enforce loop invariant: if no room left in current
10892fe8fb19SBen Gras 		 * buffer, try to get some more.
10902fe8fb19SBen Gras 		 */
10912fe8fb19SBen Gras 		if (m_room == 0) {
10922fe8fb19SBen Gras 			size_t size = mp - mem;
10932fe8fb19SBen Gras 
10942fe8fb19SBen Gras 			if ((newmem = realloc(mem, size + SFRAG)) == NULL) {
10952fe8fb19SBen Gras 				free(mem);
10962fe8fb19SBen Gras 				return -2;
10972fe8fb19SBen Gras 			}
10982fe8fb19SBen Gras 			mem = newmem;
10992fe8fb19SBen Gras 			m_room = SFRAG;
11002fe8fb19SBen Gras 			mp = mem + size;
11012fe8fb19SBen Gras 		}
11022fe8fb19SBen Gras 	}
11032fe8fb19SBen Gras 	*mp++ = '\0';	/* loop invariant let's us do this */
11042fe8fb19SBen Gras 	m_room--;
11052fe8fb19SBen Gras 	len = mp - mem - 1;
11062fe8fb19SBen Gras 
11072fe8fb19SBen Gras 	/*
11082fe8fb19SBen Gras 	 * Give back any extra memory and return value and success.
11092fe8fb19SBen Gras 	 */
11102fe8fb19SBen Gras 	if (m_room != 0) {
11112fe8fb19SBen Gras 		if ((newmem = realloc(mem, (size_t)(mp - mem))) == NULL) {
11122fe8fb19SBen Gras 			free(mem);
11132fe8fb19SBen Gras 			return -2;
11142fe8fb19SBen Gras 		}
11152fe8fb19SBen Gras 		mem = newmem;
11162fe8fb19SBen Gras 	}
11172fe8fb19SBen Gras 	*str = mem;
1118f14fb602SLionel Sambuc 	_DIAGASSERT(__type_fit(int, len));
1119f14fb602SLionel Sambuc 	return (int)len;
11202fe8fb19SBen Gras }
11212fe8fb19SBen Gras 
11222fe8fb19SBen Gras /*
11232fe8fb19SBen Gras  * Cgetnum retrieves the value of the numeric capability cap from the
11242fe8fb19SBen Gras  * capability record pointed to by buf.  The numeric value is returned in
11252fe8fb19SBen Gras  * the long pointed to by num.  0 is returned on success, -1 if the requested
11262fe8fb19SBen Gras  * numeric capability couldn't be found.
11272fe8fb19SBen Gras  */
11282fe8fb19SBen Gras int
cgetnum(char * buf,const char * cap,long * num)11292fe8fb19SBen Gras cgetnum(char *buf, const char *cap, long *num)
11302fe8fb19SBen Gras {
11312fe8fb19SBen Gras 	long n;
11322fe8fb19SBen Gras 	int base, digit;
11332fe8fb19SBen Gras 	const char *bp;
11342fe8fb19SBen Gras 
11352fe8fb19SBen Gras 	_DIAGASSERT(buf != NULL);
11362fe8fb19SBen Gras 	_DIAGASSERT(cap != NULL);
11372fe8fb19SBen Gras 	_DIAGASSERT(num != NULL);
11382fe8fb19SBen Gras 
11392fe8fb19SBen Gras 	/*
11402fe8fb19SBen Gras 	 * Find numeric capability cap
11412fe8fb19SBen Gras 	 */
11422fe8fb19SBen Gras 	bp = cgetcap(buf, cap, '#');
11432fe8fb19SBen Gras 	if (bp == NULL)
11442fe8fb19SBen Gras 		return -1;
11452fe8fb19SBen Gras 
11462fe8fb19SBen Gras 	/*
11472fe8fb19SBen Gras 	 * Look at value and determine numeric base:
11482fe8fb19SBen Gras 	 *	0x... or 0X...	hexadecimal,
11492fe8fb19SBen Gras 	 * else	0...		octal,
11502fe8fb19SBen Gras 	 * else			decimal.
11512fe8fb19SBen Gras 	 */
11522fe8fb19SBen Gras 	if (*bp == '0') {
11532fe8fb19SBen Gras 		bp++;
11542fe8fb19SBen Gras 		if (*bp == 'x' || *bp == 'X') {
11552fe8fb19SBen Gras 			bp++;
11562fe8fb19SBen Gras 			base = 16;
11572fe8fb19SBen Gras 		} else
11582fe8fb19SBen Gras 			base = 8;
11592fe8fb19SBen Gras 	} else
11602fe8fb19SBen Gras 		base = 10;
11612fe8fb19SBen Gras 
11622fe8fb19SBen Gras 	/*
11632fe8fb19SBen Gras 	 * Conversion loop ...
11642fe8fb19SBen Gras 	 */
11652fe8fb19SBen Gras 	n = 0;
11662fe8fb19SBen Gras 	for (;;) {
11672fe8fb19SBen Gras 		if ('0' <= *bp && *bp <= '9')
11682fe8fb19SBen Gras 			digit = *bp - '0';
11692fe8fb19SBen Gras 		else if ('a' <= *bp && *bp <= 'f')
11702fe8fb19SBen Gras 			digit = 10 + *bp - 'a';
11712fe8fb19SBen Gras 		else if ('A' <= *bp && *bp <= 'F')
11722fe8fb19SBen Gras 			digit = 10 + *bp - 'A';
11732fe8fb19SBen Gras 		else
11742fe8fb19SBen Gras 			break;
11752fe8fb19SBen Gras 
11762fe8fb19SBen Gras 		if (digit >= base)
11772fe8fb19SBen Gras 			break;
11782fe8fb19SBen Gras 
11792fe8fb19SBen Gras 		n = n * base + digit;
11802fe8fb19SBen Gras 		bp++;
11812fe8fb19SBen Gras 	}
11822fe8fb19SBen Gras 
11832fe8fb19SBen Gras 	/*
11842fe8fb19SBen Gras 	 * Return value and success.
11852fe8fb19SBen Gras 	 */
11862fe8fb19SBen Gras 	*num = n;
11872fe8fb19SBen Gras 	return 0;
11882fe8fb19SBen Gras }
11892fe8fb19SBen Gras 
11902fe8fb19SBen Gras 
11912fe8fb19SBen Gras /*
11922fe8fb19SBen Gras  * Compare name field of record.
11932fe8fb19SBen Gras  */
11942fe8fb19SBen Gras static int
nfcmp(char * nf,char * rec)11952fe8fb19SBen Gras nfcmp(char *nf, char *rec)
11962fe8fb19SBen Gras {
11972fe8fb19SBen Gras 	char *cp, tmp;
11982fe8fb19SBen Gras 	int ret;
11992fe8fb19SBen Gras 
12002fe8fb19SBen Gras 	_DIAGASSERT(nf != NULL);
12012fe8fb19SBen Gras 	_DIAGASSERT(rec != NULL);
12022fe8fb19SBen Gras 
12032fe8fb19SBen Gras 	for (cp = rec; *cp != ':'; cp++)
12042fe8fb19SBen Gras 		continue;
12052fe8fb19SBen Gras 
12062fe8fb19SBen Gras 	tmp = *(cp + 1);
12072fe8fb19SBen Gras 	*(cp + 1) = '\0';
12082fe8fb19SBen Gras 	ret = strcmp(nf, rec);
12092fe8fb19SBen Gras 	*(cp + 1) = tmp;
12102fe8fb19SBen Gras 
12112fe8fb19SBen Gras 	return ret;
12122fe8fb19SBen Gras }
1213