xref: /original-bsd/lib/libc/gen/getcap.c (revision eaff8629)
1cd4b894aSbostic /*-
2bac379f5Sbostic  * Copyright (c) 1992, 1993
3bac379f5Sbostic  *	The Regents of the University of California.  All rights reserved.
4cd4b894aSbostic  *
5cd4b894aSbostic  * This code is derived from software contributed to Berkeley by
6cd4b894aSbostic  * Casey Leedom of Lawrence Livermore National Laboratory.
7cd4b894aSbostic  *
8b9edf1bcSralph  * %sccs.include.redist.c%
9cd4b894aSbostic  */
10cd4b894aSbostic 
11cd4b894aSbostic #if defined(LIBC_SCCS) && !defined(lint)
12*eaff8629Sbostic static char sccsid[] = "@(#)getcap.c	8.3 (Berkeley) 03/25/94";
13cd4b894aSbostic #endif /* LIBC_SCCS and not lint */
14cd4b894aSbostic 
15cd4b894aSbostic #include <sys/types.h>
16cd4b894aSbostic 
17cd4b894aSbostic #include <ctype.h>
18f032f707Selan #include <db.h>
19cd4b894aSbostic #include <errno.h>
20cd4b894aSbostic #include <fcntl.h>
21f032f707Selan #include <limits.h>
22cd4b894aSbostic #include <stdio.h>
23cd4b894aSbostic #include <stdlib.h>
24cd4b894aSbostic #include <string.h>
25cd4b894aSbostic #include <unistd.h>
26cd4b894aSbostic 
27cd4b894aSbostic #define	BFRAG		1024
285e4d7f0dSelan #define	BSIZE		1024
29cd4b894aSbostic #define	ESC		('[' & 037)	/* ASCII ESC */
30cd4b894aSbostic #define	MAX_RECURSION	32		/* maximum getent recursion */
31cd4b894aSbostic #define	SFRAG		100		/* cgetstr mallocs in SFRAG chunks */
32cd4b894aSbostic 
33c2d10093Selan #define RECOK	(char)0
34c2d10093Selan #define TCERR	(char)1
35f3be1ef2Sbostic #define	SHADOW	(char)2
36f032f707Selan 
37cd4b894aSbostic static size_t	 topreclen;	/* toprec length */
38cd4b894aSbostic static char	*toprec;	/* Additional record specified by cgetset() */
39f6291f8aSelan static int	 gottoprec;	/* Flag indicating retrieval of toprecord */
40cd4b894aSbostic 
41f032f707Selan static int	cdbget __P((DB *, char **, char *));
425e4d7f0dSelan static int 	getent __P((char **, u_int *, char **, int, char *, int, char *));
435e4d7f0dSelan static int	nfcmp __P((char *, char *));
44cd4b894aSbostic 
45cd4b894aSbostic /*
46cd4b894aSbostic  * Cgetset() allows the addition of a user specified buffer to be added
47cd4b894aSbostic  * to the database array, in effect "pushing" the buffer on top of the
48cd4b894aSbostic  * virtual database. 0 is returned on success, -1 on failure.
49cd4b894aSbostic  */
50cd4b894aSbostic int
cgetset(ent)51cd4b894aSbostic cgetset(ent)
52cd4b894aSbostic 	char *ent;
53cd4b894aSbostic {
54cd4b894aSbostic 	if (ent == NULL) {
55cd4b894aSbostic 		if (toprec)
56cd4b894aSbostic 			free(toprec);
57cd4b894aSbostic                 toprec = NULL;
58cd4b894aSbostic                 topreclen = 0;
59cd4b894aSbostic                 return (0);
60cd4b894aSbostic         }
61cd4b894aSbostic         topreclen = strlen(ent);
62cd4b894aSbostic         if ((toprec = malloc (topreclen + 1)) == NULL) {
63cd4b894aSbostic 		errno = ENOMEM;
64cd4b894aSbostic                 return (-1);
65cd4b894aSbostic 	}
66366565adSelan 	gottoprec = 0;
67cd4b894aSbostic         (void)strcpy(toprec, ent);
68cd4b894aSbostic         return (0);
69cd4b894aSbostic }
70cd4b894aSbostic 
71cd4b894aSbostic /*
72cd4b894aSbostic  * Cgetcap searches the capability record buf for the capability cap with
73cd4b894aSbostic  * type `type'.  A pointer to the value of cap is returned on success, NULL
74cd4b894aSbostic  * if the requested capability couldn't be found.
75cd4b894aSbostic  *
76cd4b894aSbostic  * Specifying a type of ':' means that nothing should follow cap (:cap:).
77cd4b894aSbostic  * In this case a pointer to the terminating ':' or NUL will be returned if
78cd4b894aSbostic  * cap is found.
79cd4b894aSbostic  *
80cd4b894aSbostic  * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
81cd4b894aSbostic  * return NULL.
82cd4b894aSbostic  */
83cd4b894aSbostic char *
cgetcap(buf,cap,type)84cd4b894aSbostic cgetcap(buf, cap, type)
85cd4b894aSbostic 	char *buf, *cap;
86cd4b894aSbostic 	int type;
87cd4b894aSbostic {
88cd4b894aSbostic 	register char *bp, *cp;
89cd4b894aSbostic 
90cd4b894aSbostic 	bp = buf;
91cd4b894aSbostic 	for (;;) {
92cd4b894aSbostic 		/*
93cd4b894aSbostic 		 * Skip past the current capability field - it's either the
94cd4b894aSbostic 		 * name field if this is the first time through the loop, or
95cd4b894aSbostic 		 * the remainder of a field whose name failed to match cap.
96cd4b894aSbostic 		 */
97cd4b894aSbostic 		for (;;)
98cd4b894aSbostic 			if (*bp == '\0')
99cd4b894aSbostic 				return (NULL);
100cd4b894aSbostic 			else
101cd4b894aSbostic 				if (*bp++ == ':')
102cd4b894aSbostic 					break;
103cd4b894aSbostic 
104cd4b894aSbostic 		/*
105cd4b894aSbostic 		 * Try to match (cap, type) in buf.
106cd4b894aSbostic 		 */
107cd4b894aSbostic 		for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
108cd4b894aSbostic 			continue;
109cd4b894aSbostic 		if (*cp != '\0')
110cd4b894aSbostic 			continue;
111cd4b894aSbostic 		if (*bp == '@')
112cd4b894aSbostic 			return (NULL);
113cd4b894aSbostic 		if (type == ':') {
114cd4b894aSbostic 			if (*bp != '\0' && *bp != ':')
115cd4b894aSbostic 				continue;
116cd4b894aSbostic 			return(bp);
117cd4b894aSbostic 		}
118cd4b894aSbostic 		if (*bp != type)
119cd4b894aSbostic 			continue;
120cd4b894aSbostic 		bp++;
121cd4b894aSbostic 		return (*bp == '@' ? NULL : bp);
122cd4b894aSbostic 	}
123cd4b894aSbostic 	/* NOTREACHED */
124cd4b894aSbostic }
125cd4b894aSbostic 
126cd4b894aSbostic /*
127cd4b894aSbostic  * Cgetent extracts the capability record name from the NULL terminated file
128cd4b894aSbostic  * array db_array and returns a pointer to a malloc'd copy of it in buf.
129cd4b894aSbostic  * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
130cd4b894aSbostic  * cgetflag, and cgetstr, but may then be free'd.  0 is returned on success,
131cd4b894aSbostic  * -1 if the requested record couldn't be found, -2 if a system error was
132cd4b894aSbostic  * encountered (couldn't open/read a file, etc.), and -3 if a potential
133cd4b894aSbostic  * reference loop is detected.
134cd4b894aSbostic  */
135cd4b894aSbostic int
cgetent(buf,db_array,name)136cd4b894aSbostic cgetent(buf, db_array, name)
137cd4b894aSbostic 	char **buf, **db_array, *name;
138cd4b894aSbostic {
139cd4b894aSbostic 	u_int dummy;
140cd4b894aSbostic 
1415e4d7f0dSelan 	return (getent(buf, &dummy, db_array, -1, name, 0, NULL));
142cd4b894aSbostic }
143cd4b894aSbostic 
144cd4b894aSbostic /*
145cd4b894aSbostic  * Getent implements the functions of cgetent.  If fd is non-negative,
146cd4b894aSbostic  * *db_array has already been opened and fd is the open file descriptor.  We
147cd4b894aSbostic  * do this to save time and avoid using up file descriptors for tc=
148cd4b894aSbostic  * recursions.
149cd4b894aSbostic  *
150cd4b894aSbostic  * Getent returns the same success/failure codes as cgetent.  On success, a
151cd4b894aSbostic  * pointer to a malloc'ed capability record with all tc= capabilities fully
152cd4b894aSbostic  * expanded and its length (not including trailing ASCII NUL) are left in
153cd4b894aSbostic  * *cap and *len.
154cd4b894aSbostic  *
155cd4b894aSbostic  * Basic algorithm:
156cd4b894aSbostic  *	+ Allocate memory incrementally as needed in chunks of size BFRAG
157cd4b894aSbostic  *	  for capability buffer.
158cd4b894aSbostic  *	+ Recurse for each tc=name and interpolate result.  Stop when all
159cd4b894aSbostic  *	  names interpolated, a name can't be found, or depth exceeds
160cd4b894aSbostic  *	  MAX_RECURSION.
161cd4b894aSbostic  */
162cd4b894aSbostic static int
getent(cap,len,db_array,fd,name,depth,nfield)1635e4d7f0dSelan getent(cap, len, db_array, fd, name, depth, nfield)
1645e4d7f0dSelan 	char **cap, **db_array, *name, *nfield;
165cd4b894aSbostic 	u_int *len;
166cd4b894aSbostic 	int fd, depth;
167cd4b894aSbostic {
168f032f707Selan 	DB *capdbp;
169f032f707Selan 	DBT key, data;
170cd4b894aSbostic 	register char *r_end, *rp, **db_p;
171*eaff8629Sbostic 	int myfd, eof, foundit, retval, clen;
172*eaff8629Sbostic 	char *record, *cbuf;
173f032f707Selan 	int tc_not_resolved;
174f032f707Selan 	char pbuf[_POSIX_PATH_MAX];
175cd4b894aSbostic 
176cd4b894aSbostic 	/*
177cd4b894aSbostic 	 * Return with ``loop detected'' error if we've recursed more than
178cd4b894aSbostic 	 * MAX_RECURSION times.
179cd4b894aSbostic 	 */
180cd4b894aSbostic 	if (depth > MAX_RECURSION)
181cd4b894aSbostic 		return (-3);
182cd4b894aSbostic 
183cd4b894aSbostic 	/*
184cd4b894aSbostic 	 * Check if we have a top record from cgetset().
185cd4b894aSbostic          */
186366565adSelan 	if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
187cd4b894aSbostic 		if ((record = malloc (topreclen + BFRAG)) == NULL) {
188cd4b894aSbostic 			errno = ENOMEM;
189cd4b894aSbostic 			return (-2);
190cd4b894aSbostic 		}
191cd4b894aSbostic 		(void)strcpy(record, toprec);
192cd4b894aSbostic 		myfd = 0;
193cd4b894aSbostic 		db_p = db_array;
194cd4b894aSbostic 		rp = record + topreclen + 1;
195cd4b894aSbostic 		r_end = rp + BFRAG;
196cd4b894aSbostic 		goto tc_exp;
197cd4b894aSbostic 	}
198cd4b894aSbostic 	/*
199cd4b894aSbostic 	 * Allocate first chunk of memory.
200cd4b894aSbostic 	 */
201cd4b894aSbostic 	if ((record = malloc(BFRAG)) == NULL) {
202cd4b894aSbostic 		errno = ENOMEM;
203cd4b894aSbostic 		return (-2);
204cd4b894aSbostic 	}
205cd4b894aSbostic 	r_end = record + BFRAG;
206cd4b894aSbostic 	foundit = 0;
207cd4b894aSbostic 	/*
208cd4b894aSbostic 	 * Loop through database array until finding the record.
209cd4b894aSbostic 	 */
210cd4b894aSbostic 
211cd4b894aSbostic 	for (db_p = db_array; *db_p != NULL; db_p++) {
212cd4b894aSbostic 		eof = 0;
213cd4b894aSbostic 
214cd4b894aSbostic 		/*
215cd4b894aSbostic 		 * Open database if not already open.
216cd4b894aSbostic 		 */
217f032f707Selan 
218cd4b894aSbostic 		if (fd >= 0) {
21919cbfad9Sbostic 			(void)lseek(fd, (off_t)0, L_SET);
220cd4b894aSbostic 			myfd = 0;
221cd4b894aSbostic 		} else {
22219cbfad9Sbostic 			(void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
223f032f707Selan 			if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))
224f032f707Selan 			     != NULL) {
225f032f707Selan 				free(record);
226f032f707Selan 				retval = cdbget(capdbp, &record, name);
227*eaff8629Sbostic 				if (retval < 0) {
228*eaff8629Sbostic 					/* no record available */
229*eaff8629Sbostic 					(void)capdbp->close(capdbp);
230*eaff8629Sbostic 					return (retval);
231*eaff8629Sbostic 				}
232*eaff8629Sbostic 				/* save the data; close frees it */
233*eaff8629Sbostic 				clen = strlen(record);
234*eaff8629Sbostic 				cbuf = malloc(clen + 1);
235*eaff8629Sbostic 				memcpy(cbuf, record, clen + 1);
236*eaff8629Sbostic 				if (capdbp->close(capdbp) < 0) {
237*eaff8629Sbostic 					free(cbuf);
238f032f707Selan 					return (-2);
239*eaff8629Sbostic 				}
240*eaff8629Sbostic 				*len = clen;
241*eaff8629Sbostic 				*cap = cbuf;
242f032f707Selan 				return (retval);
243f032f707Selan 			} else {
244cd4b894aSbostic 				fd = open(*db_p, O_RDONLY, 0);
245cd4b894aSbostic 				if (fd < 0) {
246b45e9a50Selan 					/* No error on unfound file. */
247b45e9a50Selan 					if (errno == ENOENT)
248b45e9a50Selan 						continue;
249cd4b894aSbostic 					free(record);
250cd4b894aSbostic 					return (-2);
251cd4b894aSbostic 				}
252cd4b894aSbostic 				myfd = 1;
253cd4b894aSbostic 			}
254f032f707Selan 		}
255cd4b894aSbostic 		/*
256cd4b894aSbostic 		 * Find the requested capability record ...
257cd4b894aSbostic 		 */
258cd4b894aSbostic 		{
259cd4b894aSbostic 		char buf[BUFSIZ];
260cd4b894aSbostic 		register char *b_end, *bp;
261cd4b894aSbostic 		register int c;
262cd4b894aSbostic 
263cd4b894aSbostic 		/*
264cd4b894aSbostic 		 * Loop invariants:
265cd4b894aSbostic 		 *	There is always room for one more character in record.
266cd4b894aSbostic 		 *	R_end always points just past end of record.
267cd4b894aSbostic 		 *	Rp always points just past last character in record.
268cd4b894aSbostic 		 *	B_end always points just past last character in buf.
269cd4b894aSbostic 		 *	Bp always points at next character in buf.
270cd4b894aSbostic 		 */
271cd4b894aSbostic 		b_end = buf;
272cd4b894aSbostic 		bp = buf;
273cd4b894aSbostic 		for (;;) {
274cd4b894aSbostic 
275cd4b894aSbostic 			/*
276cd4b894aSbostic 			 * Read in a line implementing (\, newline)
277cd4b894aSbostic 			 * line continuation.
278cd4b894aSbostic 			 */
279cd4b894aSbostic 			rp = record;
280cd4b894aSbostic 			for (;;) {
281cd4b894aSbostic 				if (bp >= b_end) {
282cd4b894aSbostic 					int n;
283cd4b894aSbostic 
284cd4b894aSbostic 					n = read(fd, buf, sizeof(buf));
285cd4b894aSbostic 					if (n <= 0) {
286cd4b894aSbostic 						if (myfd)
287cd4b894aSbostic 							(void)close(fd);
288cd4b894aSbostic 						if (n < 0) {
289cd4b894aSbostic 							free(record);
290cd4b894aSbostic 							return (-2);
291cd4b894aSbostic 						} else {
292cd4b894aSbostic 							fd = -1;
293cd4b894aSbostic 							eof = 1;
294cd4b894aSbostic 							break;
295cd4b894aSbostic 						}
296cd4b894aSbostic 					}
297cd4b894aSbostic 					b_end = buf+n;
298cd4b894aSbostic 					bp = buf;
299cd4b894aSbostic 				}
300cd4b894aSbostic 
301cd4b894aSbostic 				c = *bp++;
302cd4b894aSbostic 				if (c == '\n') {
303cd4b894aSbostic 					if (rp > record && *(rp-1) == '\\') {
304cd4b894aSbostic 						rp--;
305cd4b894aSbostic 						continue;
306cd4b894aSbostic 					} else
307cd4b894aSbostic 						break;
308cd4b894aSbostic 				}
309cd4b894aSbostic 				*rp++ = c;
310cd4b894aSbostic 
311cd4b894aSbostic 				/*
312cd4b894aSbostic 				 * Enforce loop invariant: if no room
313cd4b894aSbostic 				 * left in record buffer, try to get
314cd4b894aSbostic 				 * some more.
315cd4b894aSbostic 				 */
316cd4b894aSbostic 				if (rp >= r_end) {
317f6291f8aSelan 					u_int pos;
318f6291f8aSelan 					size_t newsize;
319cd4b894aSbostic 
320cd4b894aSbostic 					pos = rp - record;
321cd4b894aSbostic 					newsize = r_end - record + BFRAG;
322cd4b894aSbostic 					record = realloc(record, newsize);
323cd4b894aSbostic 					if (record == NULL) {
324cd4b894aSbostic 						errno = ENOMEM;
325cd4b894aSbostic 						if (myfd)
326cd4b894aSbostic 							(void)close(fd);
327cd4b894aSbostic 						return (-2);
328cd4b894aSbostic 					}
329cd4b894aSbostic 					r_end = record + newsize;
330cd4b894aSbostic 					rp = record + pos;
331cd4b894aSbostic 				}
332cd4b894aSbostic 			}
333cd4b894aSbostic 				/* loop invariant let's us do this */
334cd4b894aSbostic 			*rp++ = '\0';
335cd4b894aSbostic 
336cd4b894aSbostic 			/*
337cd4b894aSbostic 			 * If encountered eof check next file.
338cd4b894aSbostic 			 */
339cd4b894aSbostic 			if (eof)
340cd4b894aSbostic 				break;
341cd4b894aSbostic 
342cd4b894aSbostic 			/*
343cd4b894aSbostic 			 * Toss blank lines and comments.
344cd4b894aSbostic 			 */
345cd4b894aSbostic 			if (*record == '\0' || *record == '#')
346cd4b894aSbostic 				continue;
347cd4b894aSbostic 
348cd4b894aSbostic 			/*
349cd4b894aSbostic 			 * See if this is the record we want ...
350cd4b894aSbostic 			 */
351cd4b894aSbostic 			if (cgetmatch(record, name) == 0) {
3525e4d7f0dSelan 				if (nfield == NULL || !nfcmp(nfield, record)) {
353cd4b894aSbostic 					foundit = 1;
354cd4b894aSbostic 					break;	/* found it! */
355cd4b894aSbostic 				}
356cd4b894aSbostic 			}
357cd4b894aSbostic 		}
3585e4d7f0dSelan 	}
359cd4b894aSbostic 		if (foundit)
360cd4b894aSbostic 			break;
361cd4b894aSbostic 	}
362cd4b894aSbostic 
363cd4b894aSbostic 	if (!foundit)
364cd4b894aSbostic 		return (-1);
365cd4b894aSbostic 
366cd4b894aSbostic 	/*
367cd4b894aSbostic 	 * Got the capability record, but now we have to expand all tc=name
368cd4b894aSbostic 	 * references in it ...
369cd4b894aSbostic 	 */
370cd4b894aSbostic tc_exp:	{
371cd4b894aSbostic 		register char *newicap, *s;
372cd4b894aSbostic 		register int newilen;
373cd4b894aSbostic 		u_int ilen;
374cd4b894aSbostic 		int diff, iret, tclen;
375cd4b894aSbostic 		char *icap, *scan, *tc, *tcstart, *tcend;
376cd4b894aSbostic 
377cd4b894aSbostic 		/*
378cd4b894aSbostic 		 * Loop invariants:
379cd4b894aSbostic 		 *	There is room for one more character in record.
380cd4b894aSbostic 		 *	R_end points just past end of record.
381cd4b894aSbostic 		 *	Rp points just past last character in record.
382cd4b894aSbostic 		 *	Scan points at remainder of record that needs to be
383cd4b894aSbostic 		 *	scanned for tc=name constructs.
384cd4b894aSbostic 		 */
385cd4b894aSbostic 		scan = record;
386f032f707Selan 		tc_not_resolved = 0;
387cd4b894aSbostic 		for (;;) {
388cd4b894aSbostic 			if ((tc = cgetcap(scan, "tc", '=')) == NULL)
389cd4b894aSbostic 				break;
390cd4b894aSbostic 
391cd4b894aSbostic 			/*
392cd4b894aSbostic 			 * Find end of tc=name and stomp on the trailing `:'
393cd4b894aSbostic 			 * (if present) so we can use it to call ourselves.
394cd4b894aSbostic 			 */
395cd4b894aSbostic 			s = tc;
396cd4b894aSbostic 			for (;;)
397cd4b894aSbostic 				if (*s == '\0')
398cd4b894aSbostic 					break;
399cd4b894aSbostic 				else
400cd4b894aSbostic 					if (*s++ == ':') {
401cd4b894aSbostic 						*(s - 1) = '\0';
402cd4b894aSbostic 						break;
403cd4b894aSbostic 					}
404cd4b894aSbostic 			tcstart = tc - 3;
405cd4b894aSbostic 			tclen = s - tcstart;
406cd4b894aSbostic 			tcend = s;
407cd4b894aSbostic 
4085e4d7f0dSelan 			iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
4095e4d7f0dSelan 				      NULL);
410cd4b894aSbostic 			newicap = icap;		/* Put into a register. */
411cd4b894aSbostic 			newilen = ilen;
412cd4b894aSbostic 			if (iret != 0) {
413c2d10093Selan 				/* an error */
414c2d10093Selan 				if (iret < -1) {
415c2d10093Selan 					if (myfd)
416c2d10093Selan 						(void)close(fd);
417c2d10093Selan 					free(record);
418c2d10093Selan 					return (iret);
419c2d10093Selan 				}
420f032f707Selan 				if (iret == 1)
421f032f707Selan 					tc_not_resolved = 1;
422c2d10093Selan 				/* couldn't resolve tc */
423f032f707Selan 				if (iret == -1) {
424f032f707Selan 					*(s - 1) = ':';
425f032f707Selan 					scan = s - 1;
426f032f707Selan 					tc_not_resolved = 1;
427f032f707Selan 					continue;
428f032f707Selan 
429f032f707Selan 				}
430cd4b894aSbostic 			}
431cd4b894aSbostic 			/* not interested in name field of tc'ed record */
432cd4b894aSbostic 			s = newicap;
433cd4b894aSbostic 			for (;;)
434cd4b894aSbostic 				if (*s == '\0')
435cd4b894aSbostic 					break;
436cd4b894aSbostic 				else
437cd4b894aSbostic 					if (*s++ == ':')
438cd4b894aSbostic 						break;
439cd4b894aSbostic 			newilen -= s - newicap;
440cd4b894aSbostic 			newicap = s;
441cd4b894aSbostic 
442cd4b894aSbostic 			/* make sure interpolated record is `:'-terminated */
443cd4b894aSbostic 			s += newilen;
444cd4b894aSbostic 			if (*(s-1) != ':') {
445cd4b894aSbostic 				*s = ':';	/* overwrite NUL with : */
446cd4b894aSbostic 				newilen++;
447cd4b894aSbostic 			}
448cd4b894aSbostic 
449cd4b894aSbostic 			/*
450cd4b894aSbostic 			 * Make sure there's enough room to insert the
451cd4b894aSbostic 			 * new record.
452cd4b894aSbostic 			 */
453cd4b894aSbostic 			diff = newilen - tclen;
454cd4b894aSbostic 			if (diff >= r_end - rp) {
455f6291f8aSelan 				u_int pos, tcpos, tcposend;
456f6291f8aSelan 				size_t newsize;
457cd4b894aSbostic 
458cd4b894aSbostic 				pos = rp - record;
459cd4b894aSbostic 				newsize = r_end - record + diff + BFRAG;
460cd4b894aSbostic 				tcpos = tcstart - record;
461cd4b894aSbostic 				tcposend = tcend - record;
462cd4b894aSbostic 				record = realloc(record, newsize);
463cd4b894aSbostic 				if (record == NULL) {
464cd4b894aSbostic 					errno = ENOMEM;
465cd4b894aSbostic 					if (myfd)
466cd4b894aSbostic 						(void)close(fd);
467cd4b894aSbostic 					free(icap);
468cd4b894aSbostic 					return (-2);
469cd4b894aSbostic 				}
470cd4b894aSbostic 				r_end = record + newsize;
471cd4b894aSbostic 				rp = record + pos;
472cd4b894aSbostic 				tcstart = record + tcpos;
473cd4b894aSbostic 				tcend = record + tcposend;
474cd4b894aSbostic 			}
475cd4b894aSbostic 
476cd4b894aSbostic 			/*
477cd4b894aSbostic 			 * Insert tc'ed record into our record.
478cd4b894aSbostic 			 */
479cd4b894aSbostic 			s = tcstart + newilen;
480cd4b894aSbostic 			bcopy(tcend, s, rp - tcend);
481cd4b894aSbostic 			bcopy(newicap, tcstart, newilen);
482cd4b894aSbostic 			rp += diff;
483cd4b894aSbostic 			free(icap);
484cd4b894aSbostic 
485cd4b894aSbostic 			/*
486cd4b894aSbostic 			 * Start scan on `:' so next cgetcap works properly
487cd4b894aSbostic 			 * (cgetcap always skips first field).
488cd4b894aSbostic 			 */
489cd4b894aSbostic 			scan = s-1;
490cd4b894aSbostic 		}
491cd4b894aSbostic 
4925e4d7f0dSelan 	}
493cd4b894aSbostic 	/*
494cd4b894aSbostic 	 * Close file (if we opened it), give back any extra memory, and
495cd4b894aSbostic 	 * return capability, length and success.
496cd4b894aSbostic 	 */
497cd4b894aSbostic 	if (myfd)
498cd4b894aSbostic 		(void)close(fd);
499cd4b894aSbostic 	*len = rp - record - 1;	/* don't count NUL */
500cd4b894aSbostic 	if (r_end > rp)
5015157a406Selan 		if ((record =
5025157a406Selan 		     realloc(record, (size_t)(rp - record))) == NULL) {
5035157a406Selan 			errno = ENOMEM;
5045157a406Selan 			return (-2);
5055157a406Selan 		}
5065157a406Selan 
507cd4b894aSbostic 	*cap = record;
508f032f707Selan 	if (tc_not_resolved)
509f032f707Selan 		return (1);
510cd4b894aSbostic 	return (0);
511cd4b894aSbostic }
512cd4b894aSbostic 
513f032f707Selan static int
cdbget(capdbp,bp,name)514f032f707Selan cdbget(capdbp, bp, name)
515f032f707Selan 	DB *capdbp;
516f032f707Selan 	char **bp, *name;
517f032f707Selan {
518f032f707Selan 	DBT key, data;
519f032f707Selan 	char *buf;
520f032f707Selan 	int st;
521f032f707Selan 
522f032f707Selan 	key.data = name;
523f3be1ef2Sbostic 	key.size = strlen(name);
524f032f707Selan 
525f3be1ef2Sbostic 	for (;;) {
526f3be1ef2Sbostic 		/* Get the reference. */
527f3be1ef2Sbostic 		switch(capdbp->get(capdbp, &key, &data, 0)) {
528f3be1ef2Sbostic 		case -1:
529f032f707Selan 			return (-2);
530f3be1ef2Sbostic 		case 1:
531f032f707Selan 			return (-1);
532f032f707Selan 		}
533f3be1ef2Sbostic 
53419cbfad9Sbostic 		/* If not an index to another record, leave. */
535f3be1ef2Sbostic 		if (((char *)data.data)[0] != SHADOW)
536f3be1ef2Sbostic 			break;
537f3be1ef2Sbostic 
53819cbfad9Sbostic 		key.data = (char *)data.data + 1;
539f3be1ef2Sbostic 		key.size = data.size - 1;
540f3be1ef2Sbostic 	}
541f3be1ef2Sbostic 
54219cbfad9Sbostic 	*bp = (char *)data.data + 1;
54319cbfad9Sbostic 	return (((char *)(data.data))[0] == TCERR ? 1 : 0);
544f032f707Selan }
545f032f707Selan 
546cd4b894aSbostic /*
547cd4b894aSbostic  * Cgetmatch will return 0 if name is one of the names of the capability
548cd4b894aSbostic  * record buf, -1 if not.
549cd4b894aSbostic  */
550cd4b894aSbostic int
cgetmatch(buf,name)551cd4b894aSbostic cgetmatch(buf, name)
552cd4b894aSbostic 	char *buf, *name;
553cd4b894aSbostic {
554cd4b894aSbostic 	register char *np, *bp;
555cd4b894aSbostic 
556cd4b894aSbostic 	/*
557cd4b894aSbostic 	 * Start search at beginning of record.
558cd4b894aSbostic 	 */
559cd4b894aSbostic 	bp = buf;
560cd4b894aSbostic 	for (;;) {
561cd4b894aSbostic 		/*
562cd4b894aSbostic 		 * Try to match a record name.
563cd4b894aSbostic 		 */
564cd4b894aSbostic 		np = name;
565cd4b894aSbostic 		for (;;)
566cd4b894aSbostic 			if (*np == '\0')
567cd4b894aSbostic 				if (*bp == '|' || *bp == ':' || *bp == '\0')
568cd4b894aSbostic 					return (0);
569cd4b894aSbostic 				else
570cd4b894aSbostic 					break;
571cd4b894aSbostic 			else
572cd4b894aSbostic 				if (*bp++ != *np++)
573cd4b894aSbostic 					break;
574cd4b894aSbostic 
575cd4b894aSbostic 		/*
576cd4b894aSbostic 		 * Match failed, skip to next name in record.
577cd4b894aSbostic 		 */
578cd4b894aSbostic 		bp--;	/* a '|' or ':' may have stopped the match */
579cd4b894aSbostic 		for (;;)
580cd4b894aSbostic 			if (*bp == '\0' || *bp == ':')
581cd4b894aSbostic 				return (-1);	/* match failed totally */
582cd4b894aSbostic 			else
583cd4b894aSbostic 				if (*bp++ == '|')
584cd4b894aSbostic 					break;	/* found next name */
585cd4b894aSbostic 	}
586cd4b894aSbostic }
587cd4b894aSbostic 
588366565adSelan 
589366565adSelan 
590366565adSelan 
591366565adSelan 
592cd4b894aSbostic int
cgetfirst(buf,db_array)593cd4b894aSbostic cgetfirst(buf, db_array)
594cd4b894aSbostic 	char **buf, **db_array;
595cd4b894aSbostic {
596cd4b894aSbostic 	(void)cgetclose();
597cd4b894aSbostic 	return (cgetnext(buf, db_array));
598cd4b894aSbostic }
599cd4b894aSbostic 
600cd4b894aSbostic static FILE *pfp;
601cd4b894aSbostic static int slash;
602cd4b894aSbostic static char **dbp;
603cd4b894aSbostic 
604cd4b894aSbostic int
cgetclose()605cd4b894aSbostic cgetclose()
606cd4b894aSbostic {
607cd4b894aSbostic 	if (pfp != NULL) {
608cd4b894aSbostic 		(void)fclose(pfp);
609cd4b894aSbostic 		pfp = NULL;
610cd4b894aSbostic 	}
611cd4b894aSbostic 	dbp = NULL;
612f6291f8aSelan 	gottoprec = 0;
613cd4b894aSbostic 	slash = 0;
614cd4b894aSbostic 	return(0);
615cd4b894aSbostic }
616cd4b894aSbostic 
617cd4b894aSbostic /*
618cd4b894aSbostic  * Cgetnext() gets either the first or next entry in the logical database
619cd4b894aSbostic  * specified by db_array.  It returns 0 upon completion of the database, 1
620cd4b894aSbostic  * upon returning an entry with more remaining, and -1 if an error occurs.
621cd4b894aSbostic  */
622cd4b894aSbostic int
cgetnext(bp,db_array)623cd4b894aSbostic cgetnext(bp, db_array)
624cd4b894aSbostic         register char **bp;
625cd4b894aSbostic 	char **db_array;
626cd4b894aSbostic {
627cd4b894aSbostic 	size_t len;
6285e4d7f0dSelan 	int status, i, done;
6295e4d7f0dSelan 	char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
630366565adSelan 	u_int dummy;
631cd4b894aSbostic 
632366565adSelan 	if (dbp == NULL)
633cd4b894aSbostic 		dbp = db_array;
634366565adSelan 
635f6291f8aSelan 	if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
636f6291f8aSelan 		(void)cgetclose();
637cd4b894aSbostic 		return (-1);
638f6291f8aSelan 	}
639cd4b894aSbostic 	for(;;) {
640366565adSelan 		if (toprec && !gottoprec) {
641366565adSelan 			gottoprec = 1;
642366565adSelan 			line = toprec;
643366565adSelan 		} else {
6448edba266Sbostic 			line = fgetln(pfp, &len);
645366565adSelan 			if (line == NULL && pfp) {
646cd4b894aSbostic 				(void)fclose(pfp);
647cd4b894aSbostic 				if (ferror(pfp)) {
648f6291f8aSelan 					(void)cgetclose();
649cd4b894aSbostic 					return (-1);
650cd4b894aSbostic 				} else {
651f3be1ef2Sbostic 					if (*++dbp == NULL) {
652f6291f8aSelan 						(void)cgetclose();
653cd4b894aSbostic 						return (0);
654f3be1ef2Sbostic 					} else if ((pfp =
655f3be1ef2Sbostic 					    fopen(*dbp, "r")) == NULL) {
656f6291f8aSelan 						(void)cgetclose();
657cd4b894aSbostic 						return (-1);
658cd4b894aSbostic 					} else
659cd4b894aSbostic 						continue;
660cd4b894aSbostic 				}
661b68e6496Selan 			} else
662b68e6496Selan 				line[len - 1] = '\0';
663f3be1ef2Sbostic 			if (len == 1) {
664f3be1ef2Sbostic 				slash = 0;
665f3be1ef2Sbostic 				continue;
666f3be1ef2Sbostic 			}
667f3be1ef2Sbostic 			if (isspace(*line) ||
668f3be1ef2Sbostic 			    *line == ':' || *line == '#' || slash) {
669f3be1ef2Sbostic 				if (line[len - 2] == '\\')
670cd4b894aSbostic 					slash = 1;
671cd4b894aSbostic 				else
672cd4b894aSbostic 					slash = 0;
673cd4b894aSbostic 				continue;
674cd4b894aSbostic 			}
675f3be1ef2Sbostic 			if (line[len - 2] == '\\')
676cd4b894aSbostic 				slash = 1;
677cd4b894aSbostic 			else
678cd4b894aSbostic 				slash = 0;
679366565adSelan 		}
680cd4b894aSbostic 
6815e4d7f0dSelan 
6825e4d7f0dSelan 		/*
6835e4d7f0dSelan 		 * Line points to a name line.
6845e4d7f0dSelan 		 */
6855e4d7f0dSelan 		i = 0;
6865e4d7f0dSelan 		done = 0;
6875e4d7f0dSelan 		np = nbuf;
6885e4d7f0dSelan 		for (;;) {
6895e4d7f0dSelan 			for (cp = line; *cp != '\0'; cp++) {
6905e4d7f0dSelan 				if (*cp == ':') {
6915e4d7f0dSelan 					*np++ = ':';
6925e4d7f0dSelan 					done = 1;
6935e4d7f0dSelan 					break;
6945e4d7f0dSelan 				}
6955e4d7f0dSelan 				if (*cp == '\\')
6965e4d7f0dSelan 					break;
6975e4d7f0dSelan 				*np++ = *cp;
6985e4d7f0dSelan 			}
6995e4d7f0dSelan 			if (done) {
7005e4d7f0dSelan 				*np = '\0';
7015e4d7f0dSelan 				break;
7025e4d7f0dSelan 			} else { /* name field extends beyond the line */
7038edba266Sbostic 				line = fgetln(pfp, &len);
7045e4d7f0dSelan 				if (line == NULL && pfp) {
7055e4d7f0dSelan 					(void)fclose(pfp);
7065e4d7f0dSelan 					if (ferror(pfp)) {
7075e4d7f0dSelan 						(void)cgetclose();
7085e4d7f0dSelan 						return (-1);
7095e4d7f0dSelan 					}
7101ed17661Sbostic 				} else
711b68e6496Selan 					line[len - 1] = '\0';
7125e4d7f0dSelan 			}
7135e4d7f0dSelan 		}
714cd4b894aSbostic 		rp = buf;
7155e4d7f0dSelan 		for(cp = nbuf; *cp != NULL; cp++)
716cd4b894aSbostic 			if (*cp == '|' || *cp == ':')
717cd4b894aSbostic 				break;
718cd4b894aSbostic 			else
719cd4b894aSbostic 				*rp++ = *cp;
720cd4b894aSbostic 
721cd4b894aSbostic 		*rp = '\0';
722d5255133Selan 		/*
723d5255133Selan 		 * XXX
724d5255133Selan 		 * Last argument of getent here should be nbuf if we want true
725d5255133Selan 		 * sequential access in the case of duplicates.
726d5255133Selan 		 * With NULL, getent will return the first entry found
727d5255133Selan 		 * rather than the duplicate entry record.  This is a
728d5255133Selan 		 * matter of semantics that should be resolved.
729d5255133Selan 		 */
730d5255133Selan 		status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
731f032f707Selan 		if (status == -2 || status == -3)
732f6291f8aSelan 			(void)cgetclose();
733f032f707Selan 
734cd4b894aSbostic 		return (status + 1);
735cd4b894aSbostic 	}
736cd4b894aSbostic 	/* NOTREACHED */
737cd4b894aSbostic }
738cd4b894aSbostic 
739cd4b894aSbostic /*
740cd4b894aSbostic  * Cgetstr retrieves the value of the string capability cap from the
741cd4b894aSbostic  * capability record pointed to by buf.  A pointer to a decoded, NUL
742cd4b894aSbostic  * terminated, malloc'd copy of the string is returned in the char *
743cd4b894aSbostic  * pointed to by str.  The length of the string not including the trailing
744cd4b894aSbostic  * NUL is returned on success, -1 if the requested string capability
745cd4b894aSbostic  * couldn't be found, -2 if a system error was encountered (storage
746cd4b894aSbostic  * allocation failure).
747cd4b894aSbostic  */
748cd4b894aSbostic int
cgetstr(buf,cap,str)749cd4b894aSbostic cgetstr(buf, cap, str)
750cd4b894aSbostic 	char *buf, *cap;
751cd4b894aSbostic 	char **str;
752cd4b894aSbostic {
753cd4b894aSbostic 	register u_int m_room;
754cd4b894aSbostic 	register char *bp, *mp;
755cd4b894aSbostic 	int len;
756cd4b894aSbostic 	char *mem;
757cd4b894aSbostic 
758cd4b894aSbostic 	/*
759cd4b894aSbostic 	 * Find string capability cap
760cd4b894aSbostic 	 */
761cd4b894aSbostic 	bp = cgetcap(buf, cap, '=');
762cd4b894aSbostic 	if (bp == NULL)
763cd4b894aSbostic 		return (-1);
764cd4b894aSbostic 
765cd4b894aSbostic 	/*
766cd4b894aSbostic 	 * Conversion / storage allocation loop ...  Allocate memory in
767cd4b894aSbostic 	 * chunks SFRAG in size.
768cd4b894aSbostic 	 */
769cd4b894aSbostic 	if ((mem = malloc(SFRAG)) == NULL) {
770cd4b894aSbostic 		errno = ENOMEM;
771cd4b894aSbostic 		return (-2);	/* couldn't even allocate the first fragment */
772cd4b894aSbostic 	}
773cd4b894aSbostic 	m_room = SFRAG;
774cd4b894aSbostic 	mp = mem;
775cd4b894aSbostic 
776cd4b894aSbostic 	while (*bp != ':' && *bp != '\0') {
777cd4b894aSbostic 		/*
778cd4b894aSbostic 		 * Loop invariants:
779cd4b894aSbostic 		 *	There is always room for one more character in mem.
780cd4b894aSbostic 		 *	Mp always points just past last character in mem.
781cd4b894aSbostic 		 *	Bp always points at next character in buf.
782cd4b894aSbostic 		 */
783cd4b894aSbostic 		if (*bp == '^') {
784cd4b894aSbostic 			bp++;
785cd4b894aSbostic 			if (*bp == ':' || *bp == '\0')
786cd4b894aSbostic 				break;	/* drop unfinished escape */
787cd4b894aSbostic 			*mp++ = *bp++ & 037;
788cd4b894aSbostic 		} else if (*bp == '\\') {
789cd4b894aSbostic 			bp++;
790cd4b894aSbostic 			if (*bp == ':' || *bp == '\0')
791cd4b894aSbostic 				break;	/* drop unfinished escape */
792cd4b894aSbostic 			if ('0' <= *bp && *bp <= '7') {
793cd4b894aSbostic 				register int n, i;
794cd4b894aSbostic 
795cd4b894aSbostic 				n = 0;
796cd4b894aSbostic 				i = 3;	/* maximum of three octal digits */
797cd4b894aSbostic 				do {
798cd4b894aSbostic 					n = n * 8 + (*bp++ - '0');
799cd4b894aSbostic 				} while (--i && '0' <= *bp && *bp <= '7');
800cd4b894aSbostic 				*mp++ = n;
801cd4b894aSbostic 			}
802cd4b894aSbostic 			else switch (*bp++) {
803cd4b894aSbostic 				case 'b': case 'B':
804cd4b894aSbostic 					*mp++ = '\b';
805cd4b894aSbostic 					break;
806cd4b894aSbostic 				case 't': case 'T':
807cd4b894aSbostic 					*mp++ = '\t';
808cd4b894aSbostic 					break;
809cd4b894aSbostic 				case 'n': case 'N':
810cd4b894aSbostic 					*mp++ = '\n';
811cd4b894aSbostic 					break;
812cd4b894aSbostic 				case 'f': case 'F':
813cd4b894aSbostic 					*mp++ = '\f';
814cd4b894aSbostic 					break;
815cd4b894aSbostic 				case 'r': case 'R':
816cd4b894aSbostic 					*mp++ = '\r';
817cd4b894aSbostic 					break;
818cd4b894aSbostic 				case 'e': case 'E':
819cd4b894aSbostic 					*mp++ = ESC;
820cd4b894aSbostic 					break;
821cd4b894aSbostic 				case 'c': case 'C':
822cd4b894aSbostic 					*mp++ = ':';
823cd4b894aSbostic 					break;
824cd4b894aSbostic 				default:
825cd4b894aSbostic 					/*
826cd4b894aSbostic 					 * Catches '\', '^', and
827cd4b894aSbostic 					 *  everything else.
828cd4b894aSbostic 					 */
829cd4b894aSbostic 					*mp++ = *(bp-1);
830cd4b894aSbostic 					break;
831cd4b894aSbostic 			}
832cd4b894aSbostic 		} else
833cd4b894aSbostic 			*mp++ = *bp++;
834cd4b894aSbostic 		m_room--;
835cd4b894aSbostic 
836cd4b894aSbostic 		/*
837cd4b894aSbostic 		 * Enforce loop invariant: if no room left in current
838cd4b894aSbostic 		 * buffer, try to get some more.
839cd4b894aSbostic 		 */
840cd4b894aSbostic 		if (m_room == 0) {
841f6291f8aSelan 			size_t size = mp - mem;
842cd4b894aSbostic 
843cd4b894aSbostic 			if ((mem = realloc(mem, size + SFRAG)) == NULL)
844cd4b894aSbostic 				return (-2);
845cd4b894aSbostic 			m_room = SFRAG;
846cd4b894aSbostic 			mp = mem + size;
847cd4b894aSbostic 		}
848cd4b894aSbostic 	}
849cd4b894aSbostic 	*mp++ = '\0';	/* loop invariant let's us do this */
850cd4b894aSbostic 	m_room--;
851cd4b894aSbostic 	len = mp - mem - 1;
852cd4b894aSbostic 
853cd4b894aSbostic 	/*
854cd4b894aSbostic 	 * Give back any extra memory and return value and success.
855cd4b894aSbostic 	 */
856cd4b894aSbostic 	if (m_room != 0)
8575157a406Selan 		if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
8585157a406Selan 			return (-2);
859cd4b894aSbostic 	*str = mem;
860cd4b894aSbostic 	return (len);
861cd4b894aSbostic }
862cd4b894aSbostic 
863cd4b894aSbostic /*
864cd4b894aSbostic  * Cgetustr retrieves the value of the string capability cap from the
865cd4b894aSbostic  * capability record pointed to by buf.  The difference between cgetustr()
866cd4b894aSbostic  * and cgetstr() is that cgetustr does not decode escapes but rather treats
867cd4b894aSbostic  * all characters literally.  A pointer to a  NUL terminated malloc'd
868cd4b894aSbostic  * copy of the string is returned in the char pointed to by str.  The
869cd4b894aSbostic  * length of the string not including the trailing NUL is returned on success,
870cd4b894aSbostic  * -1 if the requested string capability couldn't be found, -2 if a system
871cd4b894aSbostic  * error was encountered (storage allocation failure).
872cd4b894aSbostic  */
873cd4b894aSbostic int
cgetustr(buf,cap,str)874cd4b894aSbostic cgetustr(buf, cap, str)
875cd4b894aSbostic 	char *buf, *cap, **str;
876cd4b894aSbostic {
877cd4b894aSbostic 	register u_int m_room;
878cd4b894aSbostic 	register char *bp, *mp;
879cd4b894aSbostic 	int len;
880cd4b894aSbostic 	char *mem;
881cd4b894aSbostic 
882cd4b894aSbostic 	/*
883cd4b894aSbostic 	 * Find string capability cap
884cd4b894aSbostic 	 */
885cd4b894aSbostic 	if ((bp = cgetcap(buf, cap, '=')) == NULL)
886cd4b894aSbostic 		return (-1);
887cd4b894aSbostic 
888cd4b894aSbostic 	/*
889cd4b894aSbostic 	 * Conversion / storage allocation loop ...  Allocate memory in
890cd4b894aSbostic 	 * chunks SFRAG in size.
891cd4b894aSbostic 	 */
892cd4b894aSbostic 	if ((mem = malloc(SFRAG)) == NULL) {
893cd4b894aSbostic 		errno = ENOMEM;
894cd4b894aSbostic 		return (-2);	/* couldn't even allocate the first fragment */
895cd4b894aSbostic 	}
896cd4b894aSbostic 	m_room = SFRAG;
897cd4b894aSbostic 	mp = mem;
898cd4b894aSbostic 
899cd4b894aSbostic 	while (*bp != ':' && *bp != '\0') {
900cd4b894aSbostic 		/*
901cd4b894aSbostic 		 * Loop invariants:
902cd4b894aSbostic 		 *	There is always room for one more character in mem.
903cd4b894aSbostic 		 *	Mp always points just past last character in mem.
904cd4b894aSbostic 		 *	Bp always points at next character in buf.
905cd4b894aSbostic 		 */
906cd4b894aSbostic 		*mp++ = *bp++;
907cd4b894aSbostic 		m_room--;
908cd4b894aSbostic 
909cd4b894aSbostic 		/*
910cd4b894aSbostic 		 * Enforce loop invariant: if no room left in current
911cd4b894aSbostic 		 * buffer, try to get some more.
912cd4b894aSbostic 		 */
913cd4b894aSbostic 		if (m_room == 0) {
914f6291f8aSelan 			size_t size = mp - mem;
915cd4b894aSbostic 
916cd4b894aSbostic 			if ((mem = realloc(mem, size + SFRAG)) == NULL)
917cd4b894aSbostic 				return (-2);
918cd4b894aSbostic 			m_room = SFRAG;
919cd4b894aSbostic 			mp = mem + size;
920cd4b894aSbostic 		}
921cd4b894aSbostic 	}
922cd4b894aSbostic 	*mp++ = '\0';	/* loop invariant let's us do this */
923cd4b894aSbostic 	m_room--;
924cd4b894aSbostic 	len = mp - mem - 1;
925cd4b894aSbostic 
926cd4b894aSbostic 	/*
927cd4b894aSbostic 	 * Give back any extra memory and return value and success.
928cd4b894aSbostic 	 */
929cd4b894aSbostic 	if (m_room != 0)
9305157a406Selan 		if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
9315157a406Selan 			return (-2);
932cd4b894aSbostic 	*str = mem;
933cd4b894aSbostic 	return (len);
934cd4b894aSbostic }
935cd4b894aSbostic 
936cd4b894aSbostic /*
937cd4b894aSbostic  * Cgetnum retrieves the value of the numeric capability cap from the
938cd4b894aSbostic  * capability record pointed to by buf.  The numeric value is returned in
939cd4b894aSbostic  * the long pointed to by num.  0 is returned on success, -1 if the requested
940cd4b894aSbostic  * numeric capability couldn't be found.
941cd4b894aSbostic  */
942cd4b894aSbostic int
cgetnum(buf,cap,num)943cd4b894aSbostic cgetnum(buf, cap, num)
944cd4b894aSbostic 	char *buf, *cap;
945cd4b894aSbostic 	long *num;
946cd4b894aSbostic {
947cd4b894aSbostic 	register long n;
948cd4b894aSbostic 	register int base, digit;
949cd4b894aSbostic 	register char *bp;
950cd4b894aSbostic 
951cd4b894aSbostic 	/*
952cd4b894aSbostic 	 * Find numeric capability cap
953cd4b894aSbostic 	 */
954cd4b894aSbostic 	bp = cgetcap(buf, cap, '#');
955cd4b894aSbostic 	if (bp == NULL)
956cd4b894aSbostic 		return (-1);
957cd4b894aSbostic 
958cd4b894aSbostic 	/*
959cd4b894aSbostic 	 * Look at value and determine numeric base:
960cd4b894aSbostic 	 *	0x... or 0X...	hexadecimal,
961cd4b894aSbostic 	 * else	0...		octal,
962cd4b894aSbostic 	 * else			decimal.
963cd4b894aSbostic 	 */
964cd4b894aSbostic 	if (*bp == '0') {
965cd4b894aSbostic 		bp++;
966cd4b894aSbostic 		if (*bp == 'x' || *bp == 'X') {
967cd4b894aSbostic 			bp++;
968cd4b894aSbostic 			base = 16;
969cd4b894aSbostic 		} else
970cd4b894aSbostic 			base = 8;
971cd4b894aSbostic 	} else
972cd4b894aSbostic 		base = 10;
973cd4b894aSbostic 
974cd4b894aSbostic 	/*
975cd4b894aSbostic 	 * Conversion loop ...
976cd4b894aSbostic 	 */
977cd4b894aSbostic 	n = 0;
978cd4b894aSbostic 	for (;;) {
979cd4b894aSbostic 		if ('0' <= *bp && *bp <= '9')
980cd4b894aSbostic 			digit = *bp - '0';
98188f3610bSralph 		else if ('a' <= *bp && *bp <= 'f')
982cd4b894aSbostic 			digit = 10 + *bp - 'a';
98388f3610bSralph 		else if ('A' <= *bp && *bp <= 'F')
98488f3610bSralph 			digit = 10 + *bp - 'A';
985cd4b894aSbostic 		else
986cd4b894aSbostic 			break;
987cd4b894aSbostic 
988cd4b894aSbostic 		if (digit >= base)
989cd4b894aSbostic 			break;
990cd4b894aSbostic 
991cd4b894aSbostic 		n = n * base + digit;
992cd4b894aSbostic 		bp++;
993cd4b894aSbostic 	}
994cd4b894aSbostic 
995cd4b894aSbostic 	/*
996cd4b894aSbostic 	 * Return value and success.
997cd4b894aSbostic 	 */
998cd4b894aSbostic 	*num = n;
999cd4b894aSbostic 	return (0);
1000cd4b894aSbostic }
10015e4d7f0dSelan 
10025e4d7f0dSelan 
10035e4d7f0dSelan /*
10045e4d7f0dSelan  * Compare name field of record.
10055e4d7f0dSelan  */
10065e4d7f0dSelan static int
nfcmp(nf,rec)10075e4d7f0dSelan nfcmp(nf, rec)
10085e4d7f0dSelan 	char *nf, *rec;
10095e4d7f0dSelan {
10105e4d7f0dSelan 	char *cp, tmp;
10115e4d7f0dSelan 	int ret;
10125e4d7f0dSelan 
10135e4d7f0dSelan 	for (cp = rec; *cp != ':'; cp++)
10145e4d7f0dSelan 		;
10155e4d7f0dSelan 
10165e4d7f0dSelan 	tmp = *(cp + 1);
10175e4d7f0dSelan 	*(cp + 1) = '\0';
10185e4d7f0dSelan 	ret = strcmp(nf, rec);
10195e4d7f0dSelan 	*(cp + 1) = tmp;
10205e4d7f0dSelan 
10215e4d7f0dSelan 	return (ret);
10225e4d7f0dSelan }
1023