Home | History | Annotate | Line # | Download | only in gen
getcap.c revision 1.1.1.1
      1      1.1  cgd /*-
      2  1.1.1.1  cgd  * Copyright (c) 1992, 1993
      3  1.1.1.1  cgd  *	The Regents of the University of California.  All rights reserved.
      4      1.1  cgd  *
      5      1.1  cgd  * This code is derived from software contributed to Berkeley by
      6      1.1  cgd  * Casey Leedom of Lawrence Livermore National Laboratory.
      7      1.1  cgd  *
      8      1.1  cgd  * Redistribution and use in source and binary forms, with or without
      9      1.1  cgd  * modification, are permitted provided that the following conditions
     10      1.1  cgd  * are met:
     11      1.1  cgd  * 1. Redistributions of source code must retain the above copyright
     12      1.1  cgd  *    notice, this list of conditions and the following disclaimer.
     13      1.1  cgd  * 2. Redistributions in binary form must reproduce the above copyright
     14      1.1  cgd  *    notice, this list of conditions and the following disclaimer in the
     15      1.1  cgd  *    documentation and/or other materials provided with the distribution.
     16      1.1  cgd  * 3. All advertising materials mentioning features or use of this software
     17      1.1  cgd  *    must display the following acknowledgement:
     18      1.1  cgd  *	This product includes software developed by the University of
     19      1.1  cgd  *	California, Berkeley and its contributors.
     20      1.1  cgd  * 4. Neither the name of the University nor the names of its contributors
     21      1.1  cgd  *    may be used to endorse or promote products derived from this software
     22      1.1  cgd  *    without specific prior written permission.
     23      1.1  cgd  *
     24      1.1  cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25      1.1  cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26      1.1  cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27      1.1  cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28      1.1  cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29      1.1  cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30      1.1  cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31      1.1  cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32      1.1  cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33      1.1  cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34      1.1  cgd  * SUCH DAMAGE.
     35      1.1  cgd  */
     36      1.1  cgd 
     37      1.1  cgd #if defined(LIBC_SCCS) && !defined(lint)
     38  1.1.1.1  cgd static char sccsid[] = "@(#)getcap.c	8.3 (Berkeley) 3/25/94";
     39      1.1  cgd #endif /* LIBC_SCCS and not lint */
     40      1.1  cgd 
     41      1.1  cgd #include <sys/types.h>
     42      1.1  cgd 
     43      1.1  cgd #include <ctype.h>
     44      1.1  cgd #include <db.h>
     45      1.1  cgd #include <errno.h>
     46      1.1  cgd #include <fcntl.h>
     47      1.1  cgd #include <limits.h>
     48      1.1  cgd #include <stdio.h>
     49      1.1  cgd #include <stdlib.h>
     50      1.1  cgd #include <string.h>
     51      1.1  cgd #include <unistd.h>
     52      1.1  cgd 
     53      1.1  cgd #define	BFRAG		1024
     54      1.1  cgd #define	BSIZE		1024
     55      1.1  cgd #define	ESC		('[' & 037)	/* ASCII ESC */
     56      1.1  cgd #define	MAX_RECURSION	32		/* maximum getent recursion */
     57      1.1  cgd #define	SFRAG		100		/* cgetstr mallocs in SFRAG chunks */
     58      1.1  cgd 
     59      1.1  cgd #define RECOK	(char)0
     60      1.1  cgd #define TCERR	(char)1
     61      1.1  cgd #define	SHADOW	(char)2
     62      1.1  cgd 
     63      1.1  cgd static size_t	 topreclen;	/* toprec length */
     64      1.1  cgd static char	*toprec;	/* Additional record specified by cgetset() */
     65      1.1  cgd static int	 gottoprec;	/* Flag indicating retrieval of toprecord */
     66      1.1  cgd 
     67      1.1  cgd static int	cdbget __P((DB *, char **, char *));
     68      1.1  cgd static int 	getent __P((char **, u_int *, char **, int, char *, int, char *));
     69      1.1  cgd static int	nfcmp __P((char *, char *));
     70      1.1  cgd 
     71      1.1  cgd /*
     72      1.1  cgd  * Cgetset() allows the addition of a user specified buffer to be added
     73      1.1  cgd  * to the database array, in effect "pushing" the buffer on top of the
     74      1.1  cgd  * virtual database. 0 is returned on success, -1 on failure.
     75      1.1  cgd  */
     76      1.1  cgd int
     77      1.1  cgd cgetset(ent)
     78      1.1  cgd 	char *ent;
     79      1.1  cgd {
     80      1.1  cgd 	if (ent == NULL) {
     81      1.1  cgd 		if (toprec)
     82      1.1  cgd 			free(toprec);
     83      1.1  cgd                 toprec = NULL;
     84      1.1  cgd                 topreclen = 0;
     85      1.1  cgd                 return (0);
     86      1.1  cgd         }
     87      1.1  cgd         topreclen = strlen(ent);
     88      1.1  cgd         if ((toprec = malloc (topreclen + 1)) == NULL) {
     89      1.1  cgd 		errno = ENOMEM;
     90      1.1  cgd                 return (-1);
     91      1.1  cgd 	}
     92      1.1  cgd 	gottoprec = 0;
     93      1.1  cgd         (void)strcpy(toprec, ent);
     94      1.1  cgd         return (0);
     95      1.1  cgd }
     96      1.1  cgd 
     97      1.1  cgd /*
     98      1.1  cgd  * Cgetcap searches the capability record buf for the capability cap with
     99      1.1  cgd  * type `type'.  A pointer to the value of cap is returned on success, NULL
    100      1.1  cgd  * if the requested capability couldn't be found.
    101      1.1  cgd  *
    102      1.1  cgd  * Specifying a type of ':' means that nothing should follow cap (:cap:).
    103      1.1  cgd  * In this case a pointer to the terminating ':' or NUL will be returned if
    104      1.1  cgd  * cap is found.
    105      1.1  cgd  *
    106      1.1  cgd  * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
    107      1.1  cgd  * return NULL.
    108      1.1  cgd  */
    109      1.1  cgd char *
    110      1.1  cgd cgetcap(buf, cap, type)
    111      1.1  cgd 	char *buf, *cap;
    112      1.1  cgd 	int type;
    113      1.1  cgd {
    114      1.1  cgd 	register char *bp, *cp;
    115      1.1  cgd 
    116      1.1  cgd 	bp = buf;
    117      1.1  cgd 	for (;;) {
    118      1.1  cgd 		/*
    119      1.1  cgd 		 * Skip past the current capability field - it's either the
    120      1.1  cgd 		 * name field if this is the first time through the loop, or
    121      1.1  cgd 		 * the remainder of a field whose name failed to match cap.
    122      1.1  cgd 		 */
    123      1.1  cgd 		for (;;)
    124      1.1  cgd 			if (*bp == '\0')
    125      1.1  cgd 				return (NULL);
    126      1.1  cgd 			else
    127      1.1  cgd 				if (*bp++ == ':')
    128      1.1  cgd 					break;
    129      1.1  cgd 
    130      1.1  cgd 		/*
    131      1.1  cgd 		 * Try to match (cap, type) in buf.
    132      1.1  cgd 		 */
    133      1.1  cgd 		for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
    134      1.1  cgd 			continue;
    135      1.1  cgd 		if (*cp != '\0')
    136      1.1  cgd 			continue;
    137      1.1  cgd 		if (*bp == '@')
    138      1.1  cgd 			return (NULL);
    139      1.1  cgd 		if (type == ':') {
    140      1.1  cgd 			if (*bp != '\0' && *bp != ':')
    141      1.1  cgd 				continue;
    142      1.1  cgd 			return(bp);
    143      1.1  cgd 		}
    144      1.1  cgd 		if (*bp != type)
    145      1.1  cgd 			continue;
    146      1.1  cgd 		bp++;
    147      1.1  cgd 		return (*bp == '@' ? NULL : bp);
    148      1.1  cgd 	}
    149      1.1  cgd 	/* NOTREACHED */
    150      1.1  cgd }
    151      1.1  cgd 
    152      1.1  cgd /*
    153      1.1  cgd  * Cgetent extracts the capability record name from the NULL terminated file
    154      1.1  cgd  * array db_array and returns a pointer to a malloc'd copy of it in buf.
    155      1.1  cgd  * Buf must be retained through all subsequent calls to cgetcap, cgetnum,
    156      1.1  cgd  * cgetflag, and cgetstr, but may then be free'd.  0 is returned on success,
    157      1.1  cgd  * -1 if the requested record couldn't be found, -2 if a system error was
    158      1.1  cgd  * encountered (couldn't open/read a file, etc.), and -3 if a potential
    159      1.1  cgd  * reference loop is detected.
    160      1.1  cgd  */
    161      1.1  cgd int
    162      1.1  cgd cgetent(buf, db_array, name)
    163      1.1  cgd 	char **buf, **db_array, *name;
    164      1.1  cgd {
    165      1.1  cgd 	u_int dummy;
    166      1.1  cgd 
    167      1.1  cgd 	return (getent(buf, &dummy, db_array, -1, name, 0, NULL));
    168      1.1  cgd }
    169      1.1  cgd 
    170      1.1  cgd /*
    171      1.1  cgd  * Getent implements the functions of cgetent.  If fd is non-negative,
    172      1.1  cgd  * *db_array has already been opened and fd is the open file descriptor.  We
    173      1.1  cgd  * do this to save time and avoid using up file descriptors for tc=
    174      1.1  cgd  * recursions.
    175      1.1  cgd  *
    176      1.1  cgd  * Getent returns the same success/failure codes as cgetent.  On success, a
    177      1.1  cgd  * pointer to a malloc'ed capability record with all tc= capabilities fully
    178      1.1  cgd  * expanded and its length (not including trailing ASCII NUL) are left in
    179      1.1  cgd  * *cap and *len.
    180      1.1  cgd  *
    181      1.1  cgd  * Basic algorithm:
    182      1.1  cgd  *	+ Allocate memory incrementally as needed in chunks of size BFRAG
    183      1.1  cgd  *	  for capability buffer.
    184      1.1  cgd  *	+ Recurse for each tc=name and interpolate result.  Stop when all
    185      1.1  cgd  *	  names interpolated, a name can't be found, or depth exceeds
    186      1.1  cgd  *	  MAX_RECURSION.
    187      1.1  cgd  */
    188      1.1  cgd static int
    189      1.1  cgd getent(cap, len, db_array, fd, name, depth, nfield)
    190      1.1  cgd 	char **cap, **db_array, *name, *nfield;
    191      1.1  cgd 	u_int *len;
    192      1.1  cgd 	int fd, depth;
    193      1.1  cgd {
    194      1.1  cgd 	DB *capdbp;
    195      1.1  cgd 	DBT key, data;
    196      1.1  cgd 	register char *r_end, *rp, **db_p;
    197  1.1.1.1  cgd 	int myfd, eof, foundit, retval, clen;
    198  1.1.1.1  cgd 	char *record, *cbuf;
    199      1.1  cgd 	int tc_not_resolved;
    200      1.1  cgd 	char pbuf[_POSIX_PATH_MAX];
    201      1.1  cgd 
    202      1.1  cgd 	/*
    203      1.1  cgd 	 * Return with ``loop detected'' error if we've recursed more than
    204      1.1  cgd 	 * MAX_RECURSION times.
    205      1.1  cgd 	 */
    206      1.1  cgd 	if (depth > MAX_RECURSION)
    207      1.1  cgd 		return (-3);
    208      1.1  cgd 
    209      1.1  cgd 	/*
    210      1.1  cgd 	 * Check if we have a top record from cgetset().
    211      1.1  cgd          */
    212      1.1  cgd 	if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) {
    213      1.1  cgd 		if ((record = malloc (topreclen + BFRAG)) == NULL) {
    214      1.1  cgd 			errno = ENOMEM;
    215      1.1  cgd 			return (-2);
    216      1.1  cgd 		}
    217      1.1  cgd 		(void)strcpy(record, toprec);
    218      1.1  cgd 		myfd = 0;
    219      1.1  cgd 		db_p = db_array;
    220      1.1  cgd 		rp = record + topreclen + 1;
    221      1.1  cgd 		r_end = rp + BFRAG;
    222      1.1  cgd 		goto tc_exp;
    223      1.1  cgd 	}
    224      1.1  cgd 	/*
    225      1.1  cgd 	 * Allocate first chunk of memory.
    226      1.1  cgd 	 */
    227      1.1  cgd 	if ((record = malloc(BFRAG)) == NULL) {
    228      1.1  cgd 		errno = ENOMEM;
    229      1.1  cgd 		return (-2);
    230      1.1  cgd 	}
    231      1.1  cgd 	r_end = record + BFRAG;
    232      1.1  cgd 	foundit = 0;
    233      1.1  cgd 	/*
    234      1.1  cgd 	 * Loop through database array until finding the record.
    235      1.1  cgd 	 */
    236      1.1  cgd 
    237      1.1  cgd 	for (db_p = db_array; *db_p != NULL; db_p++) {
    238      1.1  cgd 		eof = 0;
    239      1.1  cgd 
    240      1.1  cgd 		/*
    241      1.1  cgd 		 * Open database if not already open.
    242      1.1  cgd 		 */
    243      1.1  cgd 
    244      1.1  cgd 		if (fd >= 0) {
    245      1.1  cgd 			(void)lseek(fd, (off_t)0, L_SET);
    246      1.1  cgd 			myfd = 0;
    247      1.1  cgd 		} else {
    248      1.1  cgd 			(void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p);
    249      1.1  cgd 			if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0))
    250      1.1  cgd 			     != NULL) {
    251      1.1  cgd 				free(record);
    252      1.1  cgd 				retval = cdbget(capdbp, &record, name);
    253  1.1.1.1  cgd 				if (retval < 0) {
    254  1.1.1.1  cgd 					/* no record available */
    255  1.1.1.1  cgd 					(void)capdbp->close(capdbp);
    256  1.1.1.1  cgd 					return (retval);
    257  1.1.1.1  cgd 				}
    258  1.1.1.1  cgd 				/* save the data; close frees it */
    259  1.1.1.1  cgd 				clen = strlen(record);
    260  1.1.1.1  cgd 				cbuf = malloc(clen + 1);
    261  1.1.1.1  cgd 				memcpy(cbuf, record, clen + 1);
    262  1.1.1.1  cgd 				if (capdbp->close(capdbp) < 0) {
    263  1.1.1.1  cgd 					free(cbuf);
    264      1.1  cgd 					return (-2);
    265  1.1.1.1  cgd 				}
    266  1.1.1.1  cgd 				*len = clen;
    267  1.1.1.1  cgd 				*cap = cbuf;
    268      1.1  cgd 				return (retval);
    269      1.1  cgd 			} else {
    270      1.1  cgd 				fd = open(*db_p, O_RDONLY, 0);
    271      1.1  cgd 				if (fd < 0) {
    272      1.1  cgd 					/* No error on unfound file. */
    273      1.1  cgd 					if (errno == ENOENT)
    274      1.1  cgd 						continue;
    275      1.1  cgd 					free(record);
    276      1.1  cgd 					return (-2);
    277      1.1  cgd 				}
    278      1.1  cgd 				myfd = 1;
    279      1.1  cgd 			}
    280      1.1  cgd 		}
    281      1.1  cgd 		/*
    282      1.1  cgd 		 * Find the requested capability record ...
    283      1.1  cgd 		 */
    284      1.1  cgd 		{
    285      1.1  cgd 		char buf[BUFSIZ];
    286      1.1  cgd 		register char *b_end, *bp;
    287      1.1  cgd 		register int c;
    288      1.1  cgd 
    289      1.1  cgd 		/*
    290      1.1  cgd 		 * Loop invariants:
    291      1.1  cgd 		 *	There is always room for one more character in record.
    292      1.1  cgd 		 *	R_end always points just past end of record.
    293      1.1  cgd 		 *	Rp always points just past last character in record.
    294      1.1  cgd 		 *	B_end always points just past last character in buf.
    295      1.1  cgd 		 *	Bp always points at next character in buf.
    296      1.1  cgd 		 */
    297      1.1  cgd 		b_end = buf;
    298      1.1  cgd 		bp = buf;
    299      1.1  cgd 		for (;;) {
    300      1.1  cgd 
    301      1.1  cgd 			/*
    302      1.1  cgd 			 * Read in a line implementing (\, newline)
    303      1.1  cgd 			 * line continuation.
    304      1.1  cgd 			 */
    305      1.1  cgd 			rp = record;
    306      1.1  cgd 			for (;;) {
    307      1.1  cgd 				if (bp >= b_end) {
    308      1.1  cgd 					int n;
    309      1.1  cgd 
    310      1.1  cgd 					n = read(fd, buf, sizeof(buf));
    311      1.1  cgd 					if (n <= 0) {
    312      1.1  cgd 						if (myfd)
    313      1.1  cgd 							(void)close(fd);
    314      1.1  cgd 						if (n < 0) {
    315      1.1  cgd 							free(record);
    316      1.1  cgd 							return (-2);
    317      1.1  cgd 						} else {
    318      1.1  cgd 							fd = -1;
    319      1.1  cgd 							eof = 1;
    320      1.1  cgd 							break;
    321      1.1  cgd 						}
    322      1.1  cgd 					}
    323      1.1  cgd 					b_end = buf+n;
    324      1.1  cgd 					bp = buf;
    325      1.1  cgd 				}
    326      1.1  cgd 
    327      1.1  cgd 				c = *bp++;
    328      1.1  cgd 				if (c == '\n') {
    329      1.1  cgd 					if (rp > record && *(rp-1) == '\\') {
    330      1.1  cgd 						rp--;
    331      1.1  cgd 						continue;
    332      1.1  cgd 					} else
    333      1.1  cgd 						break;
    334      1.1  cgd 				}
    335      1.1  cgd 				*rp++ = c;
    336      1.1  cgd 
    337      1.1  cgd 				/*
    338      1.1  cgd 				 * Enforce loop invariant: if no room
    339      1.1  cgd 				 * left in record buffer, try to get
    340      1.1  cgd 				 * some more.
    341      1.1  cgd 				 */
    342      1.1  cgd 				if (rp >= r_end) {
    343      1.1  cgd 					u_int pos;
    344      1.1  cgd 					size_t newsize;
    345      1.1  cgd 
    346      1.1  cgd 					pos = rp - record;
    347      1.1  cgd 					newsize = r_end - record + BFRAG;
    348      1.1  cgd 					record = realloc(record, newsize);
    349      1.1  cgd 					if (record == NULL) {
    350      1.1  cgd 						errno = ENOMEM;
    351      1.1  cgd 						if (myfd)
    352      1.1  cgd 							(void)close(fd);
    353      1.1  cgd 						return (-2);
    354      1.1  cgd 					}
    355      1.1  cgd 					r_end = record + newsize;
    356      1.1  cgd 					rp = record + pos;
    357      1.1  cgd 				}
    358      1.1  cgd 			}
    359      1.1  cgd 				/* loop invariant let's us do this */
    360      1.1  cgd 			*rp++ = '\0';
    361      1.1  cgd 
    362      1.1  cgd 			/*
    363      1.1  cgd 			 * If encountered eof check next file.
    364      1.1  cgd 			 */
    365      1.1  cgd 			if (eof)
    366      1.1  cgd 				break;
    367      1.1  cgd 
    368      1.1  cgd 			/*
    369      1.1  cgd 			 * Toss blank lines and comments.
    370      1.1  cgd 			 */
    371      1.1  cgd 			if (*record == '\0' || *record == '#')
    372      1.1  cgd 				continue;
    373      1.1  cgd 
    374      1.1  cgd 			/*
    375      1.1  cgd 			 * See if this is the record we want ...
    376      1.1  cgd 			 */
    377      1.1  cgd 			if (cgetmatch(record, name) == 0) {
    378      1.1  cgd 				if (nfield == NULL || !nfcmp(nfield, record)) {
    379      1.1  cgd 					foundit = 1;
    380      1.1  cgd 					break;	/* found it! */
    381      1.1  cgd 				}
    382      1.1  cgd 			}
    383      1.1  cgd 		}
    384      1.1  cgd 	}
    385      1.1  cgd 		if (foundit)
    386      1.1  cgd 			break;
    387      1.1  cgd 	}
    388      1.1  cgd 
    389      1.1  cgd 	if (!foundit)
    390      1.1  cgd 		return (-1);
    391      1.1  cgd 
    392      1.1  cgd 	/*
    393      1.1  cgd 	 * Got the capability record, but now we have to expand all tc=name
    394      1.1  cgd 	 * references in it ...
    395      1.1  cgd 	 */
    396      1.1  cgd tc_exp:	{
    397      1.1  cgd 		register char *newicap, *s;
    398      1.1  cgd 		register int newilen;
    399      1.1  cgd 		u_int ilen;
    400      1.1  cgd 		int diff, iret, tclen;
    401      1.1  cgd 		char *icap, *scan, *tc, *tcstart, *tcend;
    402      1.1  cgd 
    403      1.1  cgd 		/*
    404      1.1  cgd 		 * Loop invariants:
    405      1.1  cgd 		 *	There is room for one more character in record.
    406      1.1  cgd 		 *	R_end points just past end of record.
    407      1.1  cgd 		 *	Rp points just past last character in record.
    408      1.1  cgd 		 *	Scan points at remainder of record that needs to be
    409      1.1  cgd 		 *	scanned for tc=name constructs.
    410      1.1  cgd 		 */
    411      1.1  cgd 		scan = record;
    412      1.1  cgd 		tc_not_resolved = 0;
    413      1.1  cgd 		for (;;) {
    414      1.1  cgd 			if ((tc = cgetcap(scan, "tc", '=')) == NULL)
    415      1.1  cgd 				break;
    416      1.1  cgd 
    417      1.1  cgd 			/*
    418      1.1  cgd 			 * Find end of tc=name and stomp on the trailing `:'
    419      1.1  cgd 			 * (if present) so we can use it to call ourselves.
    420      1.1  cgd 			 */
    421      1.1  cgd 			s = tc;
    422      1.1  cgd 			for (;;)
    423      1.1  cgd 				if (*s == '\0')
    424      1.1  cgd 					break;
    425      1.1  cgd 				else
    426      1.1  cgd 					if (*s++ == ':') {
    427      1.1  cgd 						*(s - 1) = '\0';
    428      1.1  cgd 						break;
    429      1.1  cgd 					}
    430      1.1  cgd 			tcstart = tc - 3;
    431      1.1  cgd 			tclen = s - tcstart;
    432      1.1  cgd 			tcend = s;
    433      1.1  cgd 
    434      1.1  cgd 			iret = getent(&icap, &ilen, db_p, fd, tc, depth+1,
    435      1.1  cgd 				      NULL);
    436      1.1  cgd 			newicap = icap;		/* Put into a register. */
    437      1.1  cgd 			newilen = ilen;
    438      1.1  cgd 			if (iret != 0) {
    439      1.1  cgd 				/* an error */
    440      1.1  cgd 				if (iret < -1) {
    441      1.1  cgd 					if (myfd)
    442      1.1  cgd 						(void)close(fd);
    443      1.1  cgd 					free(record);
    444      1.1  cgd 					return (iret);
    445      1.1  cgd 				}
    446      1.1  cgd 				if (iret == 1)
    447      1.1  cgd 					tc_not_resolved = 1;
    448      1.1  cgd 				/* couldn't resolve tc */
    449      1.1  cgd 				if (iret == -1) {
    450      1.1  cgd 					*(s - 1) = ':';
    451      1.1  cgd 					scan = s - 1;
    452      1.1  cgd 					tc_not_resolved = 1;
    453      1.1  cgd 					continue;
    454      1.1  cgd 
    455      1.1  cgd 				}
    456      1.1  cgd 			}
    457      1.1  cgd 			/* not interested in name field of tc'ed record */
    458      1.1  cgd 			s = newicap;
    459      1.1  cgd 			for (;;)
    460      1.1  cgd 				if (*s == '\0')
    461      1.1  cgd 					break;
    462      1.1  cgd 				else
    463      1.1  cgd 					if (*s++ == ':')
    464      1.1  cgd 						break;
    465      1.1  cgd 			newilen -= s - newicap;
    466      1.1  cgd 			newicap = s;
    467      1.1  cgd 
    468      1.1  cgd 			/* make sure interpolated record is `:'-terminated */
    469      1.1  cgd 			s += newilen;
    470      1.1  cgd 			if (*(s-1) != ':') {
    471      1.1  cgd 				*s = ':';	/* overwrite NUL with : */
    472      1.1  cgd 				newilen++;
    473      1.1  cgd 			}
    474      1.1  cgd 
    475      1.1  cgd 			/*
    476      1.1  cgd 			 * Make sure there's enough room to insert the
    477      1.1  cgd 			 * new record.
    478      1.1  cgd 			 */
    479      1.1  cgd 			diff = newilen - tclen;
    480      1.1  cgd 			if (diff >= r_end - rp) {
    481      1.1  cgd 				u_int pos, tcpos, tcposend;
    482      1.1  cgd 				size_t newsize;
    483      1.1  cgd 
    484      1.1  cgd 				pos = rp - record;
    485      1.1  cgd 				newsize = r_end - record + diff + BFRAG;
    486      1.1  cgd 				tcpos = tcstart - record;
    487      1.1  cgd 				tcposend = tcend - record;
    488      1.1  cgd 				record = realloc(record, newsize);
    489      1.1  cgd 				if (record == NULL) {
    490      1.1  cgd 					errno = ENOMEM;
    491      1.1  cgd 					if (myfd)
    492      1.1  cgd 						(void)close(fd);
    493      1.1  cgd 					free(icap);
    494      1.1  cgd 					return (-2);
    495      1.1  cgd 				}
    496      1.1  cgd 				r_end = record + newsize;
    497      1.1  cgd 				rp = record + pos;
    498      1.1  cgd 				tcstart = record + tcpos;
    499      1.1  cgd 				tcend = record + tcposend;
    500      1.1  cgd 			}
    501      1.1  cgd 
    502      1.1  cgd 			/*
    503      1.1  cgd 			 * Insert tc'ed record into our record.
    504      1.1  cgd 			 */
    505      1.1  cgd 			s = tcstart + newilen;
    506      1.1  cgd 			bcopy(tcend, s, rp - tcend);
    507      1.1  cgd 			bcopy(newicap, tcstart, newilen);
    508      1.1  cgd 			rp += diff;
    509      1.1  cgd 			free(icap);
    510      1.1  cgd 
    511      1.1  cgd 			/*
    512      1.1  cgd 			 * Start scan on `:' so next cgetcap works properly
    513      1.1  cgd 			 * (cgetcap always skips first field).
    514      1.1  cgd 			 */
    515      1.1  cgd 			scan = s-1;
    516      1.1  cgd 		}
    517      1.1  cgd 
    518      1.1  cgd 	}
    519      1.1  cgd 	/*
    520      1.1  cgd 	 * Close file (if we opened it), give back any extra memory, and
    521      1.1  cgd 	 * return capability, length and success.
    522      1.1  cgd 	 */
    523      1.1  cgd 	if (myfd)
    524      1.1  cgd 		(void)close(fd);
    525      1.1  cgd 	*len = rp - record - 1;	/* don't count NUL */
    526      1.1  cgd 	if (r_end > rp)
    527      1.1  cgd 		if ((record =
    528      1.1  cgd 		     realloc(record, (size_t)(rp - record))) == NULL) {
    529      1.1  cgd 			errno = ENOMEM;
    530      1.1  cgd 			return (-2);
    531      1.1  cgd 		}
    532      1.1  cgd 
    533      1.1  cgd 	*cap = record;
    534      1.1  cgd 	if (tc_not_resolved)
    535      1.1  cgd 		return (1);
    536      1.1  cgd 	return (0);
    537      1.1  cgd }
    538      1.1  cgd 
    539      1.1  cgd static int
    540      1.1  cgd cdbget(capdbp, bp, name)
    541      1.1  cgd 	DB *capdbp;
    542      1.1  cgd 	char **bp, *name;
    543      1.1  cgd {
    544      1.1  cgd 	DBT key, data;
    545      1.1  cgd 	char *buf;
    546      1.1  cgd 	int st;
    547      1.1  cgd 
    548      1.1  cgd 	key.data = name;
    549      1.1  cgd 	key.size = strlen(name);
    550      1.1  cgd 
    551      1.1  cgd 	for (;;) {
    552      1.1  cgd 		/* Get the reference. */
    553      1.1  cgd 		switch(capdbp->get(capdbp, &key, &data, 0)) {
    554      1.1  cgd 		case -1:
    555      1.1  cgd 			return (-2);
    556      1.1  cgd 		case 1:
    557      1.1  cgd 			return (-1);
    558      1.1  cgd 		}
    559      1.1  cgd 
    560      1.1  cgd 		/* If not an index to another record, leave. */
    561      1.1  cgd 		if (((char *)data.data)[0] != SHADOW)
    562      1.1  cgd 			break;
    563      1.1  cgd 
    564      1.1  cgd 		key.data = (char *)data.data + 1;
    565      1.1  cgd 		key.size = data.size - 1;
    566      1.1  cgd 	}
    567      1.1  cgd 
    568      1.1  cgd 	*bp = (char *)data.data + 1;
    569      1.1  cgd 	return (((char *)(data.data))[0] == TCERR ? 1 : 0);
    570      1.1  cgd }
    571      1.1  cgd 
    572      1.1  cgd /*
    573      1.1  cgd  * Cgetmatch will return 0 if name is one of the names of the capability
    574      1.1  cgd  * record buf, -1 if not.
    575      1.1  cgd  */
    576      1.1  cgd int
    577      1.1  cgd cgetmatch(buf, name)
    578      1.1  cgd 	char *buf, *name;
    579      1.1  cgd {
    580      1.1  cgd 	register char *np, *bp;
    581      1.1  cgd 
    582      1.1  cgd 	/*
    583      1.1  cgd 	 * Start search at beginning of record.
    584      1.1  cgd 	 */
    585      1.1  cgd 	bp = buf;
    586      1.1  cgd 	for (;;) {
    587      1.1  cgd 		/*
    588      1.1  cgd 		 * Try to match a record name.
    589      1.1  cgd 		 */
    590      1.1  cgd 		np = name;
    591      1.1  cgd 		for (;;)
    592      1.1  cgd 			if (*np == '\0')
    593      1.1  cgd 				if (*bp == '|' || *bp == ':' || *bp == '\0')
    594      1.1  cgd 					return (0);
    595      1.1  cgd 				else
    596      1.1  cgd 					break;
    597      1.1  cgd 			else
    598      1.1  cgd 				if (*bp++ != *np++)
    599      1.1  cgd 					break;
    600      1.1  cgd 
    601      1.1  cgd 		/*
    602      1.1  cgd 		 * Match failed, skip to next name in record.
    603      1.1  cgd 		 */
    604      1.1  cgd 		bp--;	/* a '|' or ':' may have stopped the match */
    605      1.1  cgd 		for (;;)
    606      1.1  cgd 			if (*bp == '\0' || *bp == ':')
    607      1.1  cgd 				return (-1);	/* match failed totally */
    608      1.1  cgd 			else
    609      1.1  cgd 				if (*bp++ == '|')
    610      1.1  cgd 					break;	/* found next name */
    611      1.1  cgd 	}
    612      1.1  cgd }
    613      1.1  cgd 
    614      1.1  cgd 
    615      1.1  cgd 
    616      1.1  cgd 
    617      1.1  cgd 
    618      1.1  cgd int
    619      1.1  cgd cgetfirst(buf, db_array)
    620      1.1  cgd 	char **buf, **db_array;
    621      1.1  cgd {
    622      1.1  cgd 	(void)cgetclose();
    623      1.1  cgd 	return (cgetnext(buf, db_array));
    624      1.1  cgd }
    625      1.1  cgd 
    626      1.1  cgd static FILE *pfp;
    627      1.1  cgd static int slash;
    628      1.1  cgd static char **dbp;
    629      1.1  cgd 
    630      1.1  cgd int
    631      1.1  cgd cgetclose()
    632      1.1  cgd {
    633      1.1  cgd 	if (pfp != NULL) {
    634      1.1  cgd 		(void)fclose(pfp);
    635      1.1  cgd 		pfp = NULL;
    636      1.1  cgd 	}
    637      1.1  cgd 	dbp = NULL;
    638      1.1  cgd 	gottoprec = 0;
    639      1.1  cgd 	slash = 0;
    640      1.1  cgd 	return(0);
    641      1.1  cgd }
    642      1.1  cgd 
    643      1.1  cgd /*
    644      1.1  cgd  * Cgetnext() gets either the first or next entry in the logical database
    645      1.1  cgd  * specified by db_array.  It returns 0 upon completion of the database, 1
    646      1.1  cgd  * upon returning an entry with more remaining, and -1 if an error occurs.
    647      1.1  cgd  */
    648      1.1  cgd int
    649      1.1  cgd cgetnext(bp, db_array)
    650      1.1  cgd         register char **bp;
    651      1.1  cgd 	char **db_array;
    652      1.1  cgd {
    653      1.1  cgd 	size_t len;
    654      1.1  cgd 	int status, i, done;
    655      1.1  cgd 	char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
    656      1.1  cgd 	u_int dummy;
    657      1.1  cgd 
    658      1.1  cgd 	if (dbp == NULL)
    659      1.1  cgd 		dbp = db_array;
    660      1.1  cgd 
    661      1.1  cgd 	if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
    662      1.1  cgd 		(void)cgetclose();
    663      1.1  cgd 		return (-1);
    664      1.1  cgd 	}
    665      1.1  cgd 	for(;;) {
    666      1.1  cgd 		if (toprec && !gottoprec) {
    667      1.1  cgd 			gottoprec = 1;
    668      1.1  cgd 			line = toprec;
    669      1.1  cgd 		} else {
    670  1.1.1.1  cgd 			line = fgetln(pfp, &len);
    671      1.1  cgd 			if (line == NULL && pfp) {
    672      1.1  cgd 				(void)fclose(pfp);
    673      1.1  cgd 				if (ferror(pfp)) {
    674      1.1  cgd 					(void)cgetclose();
    675      1.1  cgd 					return (-1);
    676      1.1  cgd 				} else {
    677      1.1  cgd 					if (*++dbp == NULL) {
    678      1.1  cgd 						(void)cgetclose();
    679      1.1  cgd 						return (0);
    680      1.1  cgd 					} else if ((pfp =
    681      1.1  cgd 					    fopen(*dbp, "r")) == NULL) {
    682      1.1  cgd 						(void)cgetclose();
    683      1.1  cgd 						return (-1);
    684      1.1  cgd 					} else
    685      1.1  cgd 						continue;
    686      1.1  cgd 				}
    687      1.1  cgd 			} else
    688      1.1  cgd 				line[len - 1] = '\0';
    689      1.1  cgd 			if (len == 1) {
    690      1.1  cgd 				slash = 0;
    691      1.1  cgd 				continue;
    692      1.1  cgd 			}
    693      1.1  cgd 			if (isspace(*line) ||
    694      1.1  cgd 			    *line == ':' || *line == '#' || slash) {
    695      1.1  cgd 				if (line[len - 2] == '\\')
    696      1.1  cgd 					slash = 1;
    697      1.1  cgd 				else
    698      1.1  cgd 					slash = 0;
    699      1.1  cgd 				continue;
    700      1.1  cgd 			}
    701      1.1  cgd 			if (line[len - 2] == '\\')
    702      1.1  cgd 				slash = 1;
    703      1.1  cgd 			else
    704      1.1  cgd 				slash = 0;
    705      1.1  cgd 		}
    706      1.1  cgd 
    707      1.1  cgd 
    708      1.1  cgd 		/*
    709      1.1  cgd 		 * Line points to a name line.
    710      1.1  cgd 		 */
    711      1.1  cgd 		i = 0;
    712      1.1  cgd 		done = 0;
    713      1.1  cgd 		np = nbuf;
    714      1.1  cgd 		for (;;) {
    715      1.1  cgd 			for (cp = line; *cp != '\0'; cp++) {
    716      1.1  cgd 				if (*cp == ':') {
    717      1.1  cgd 					*np++ = ':';
    718      1.1  cgd 					done = 1;
    719      1.1  cgd 					break;
    720      1.1  cgd 				}
    721      1.1  cgd 				if (*cp == '\\')
    722      1.1  cgd 					break;
    723      1.1  cgd 				*np++ = *cp;
    724      1.1  cgd 			}
    725      1.1  cgd 			if (done) {
    726      1.1  cgd 				*np = '\0';
    727      1.1  cgd 				break;
    728      1.1  cgd 			} else { /* name field extends beyond the line */
    729  1.1.1.1  cgd 				line = fgetln(pfp, &len);
    730      1.1  cgd 				if (line == NULL && pfp) {
    731      1.1  cgd 					(void)fclose(pfp);
    732      1.1  cgd 					if (ferror(pfp)) {
    733      1.1  cgd 						(void)cgetclose();
    734      1.1  cgd 						return (-1);
    735      1.1  cgd 					}
    736      1.1  cgd 				} else
    737      1.1  cgd 					line[len - 1] = '\0';
    738      1.1  cgd 			}
    739      1.1  cgd 		}
    740      1.1  cgd 		rp = buf;
    741      1.1  cgd 		for(cp = nbuf; *cp != NULL; cp++)
    742      1.1  cgd 			if (*cp == '|' || *cp == ':')
    743      1.1  cgd 				break;
    744      1.1  cgd 			else
    745      1.1  cgd 				*rp++ = *cp;
    746      1.1  cgd 
    747      1.1  cgd 		*rp = '\0';
    748      1.1  cgd 		/*
    749      1.1  cgd 		 * XXX
    750      1.1  cgd 		 * Last argument of getent here should be nbuf if we want true
    751      1.1  cgd 		 * sequential access in the case of duplicates.
    752      1.1  cgd 		 * With NULL, getent will return the first entry found
    753      1.1  cgd 		 * rather than the duplicate entry record.  This is a
    754      1.1  cgd 		 * matter of semantics that should be resolved.
    755      1.1  cgd 		 */
    756      1.1  cgd 		status = getent(bp, &dummy, db_array, -1, buf, 0, NULL);
    757      1.1  cgd 		if (status == -2 || status == -3)
    758      1.1  cgd 			(void)cgetclose();
    759      1.1  cgd 
    760      1.1  cgd 		return (status + 1);
    761      1.1  cgd 	}
    762      1.1  cgd 	/* NOTREACHED */
    763      1.1  cgd }
    764      1.1  cgd 
    765      1.1  cgd /*
    766      1.1  cgd  * Cgetstr retrieves the value of the string capability cap from the
    767      1.1  cgd  * capability record pointed to by buf.  A pointer to a decoded, NUL
    768      1.1  cgd  * terminated, malloc'd copy of the string is returned in the char *
    769      1.1  cgd  * pointed to by str.  The length of the string not including the trailing
    770      1.1  cgd  * NUL is returned on success, -1 if the requested string capability
    771      1.1  cgd  * couldn't be found, -2 if a system error was encountered (storage
    772      1.1  cgd  * allocation failure).
    773      1.1  cgd  */
    774      1.1  cgd int
    775      1.1  cgd cgetstr(buf, cap, str)
    776      1.1  cgd 	char *buf, *cap;
    777      1.1  cgd 	char **str;
    778      1.1  cgd {
    779      1.1  cgd 	register u_int m_room;
    780      1.1  cgd 	register char *bp, *mp;
    781      1.1  cgd 	int len;
    782      1.1  cgd 	char *mem;
    783      1.1  cgd 
    784      1.1  cgd 	/*
    785      1.1  cgd 	 * Find string capability cap
    786      1.1  cgd 	 */
    787      1.1  cgd 	bp = cgetcap(buf, cap, '=');
    788      1.1  cgd 	if (bp == NULL)
    789      1.1  cgd 		return (-1);
    790      1.1  cgd 
    791      1.1  cgd 	/*
    792      1.1  cgd 	 * Conversion / storage allocation loop ...  Allocate memory in
    793      1.1  cgd 	 * chunks SFRAG in size.
    794      1.1  cgd 	 */
    795      1.1  cgd 	if ((mem = malloc(SFRAG)) == NULL) {
    796      1.1  cgd 		errno = ENOMEM;
    797      1.1  cgd 		return (-2);	/* couldn't even allocate the first fragment */
    798      1.1  cgd 	}
    799      1.1  cgd 	m_room = SFRAG;
    800      1.1  cgd 	mp = mem;
    801      1.1  cgd 
    802      1.1  cgd 	while (*bp != ':' && *bp != '\0') {
    803      1.1  cgd 		/*
    804      1.1  cgd 		 * Loop invariants:
    805      1.1  cgd 		 *	There is always room for one more character in mem.
    806      1.1  cgd 		 *	Mp always points just past last character in mem.
    807      1.1  cgd 		 *	Bp always points at next character in buf.
    808      1.1  cgd 		 */
    809      1.1  cgd 		if (*bp == '^') {
    810      1.1  cgd 			bp++;
    811      1.1  cgd 			if (*bp == ':' || *bp == '\0')
    812      1.1  cgd 				break;	/* drop unfinished escape */
    813      1.1  cgd 			*mp++ = *bp++ & 037;
    814      1.1  cgd 		} else if (*bp == '\\') {
    815      1.1  cgd 			bp++;
    816      1.1  cgd 			if (*bp == ':' || *bp == '\0')
    817      1.1  cgd 				break;	/* drop unfinished escape */
    818      1.1  cgd 			if ('0' <= *bp && *bp <= '7') {
    819      1.1  cgd 				register int n, i;
    820      1.1  cgd 
    821      1.1  cgd 				n = 0;
    822      1.1  cgd 				i = 3;	/* maximum of three octal digits */
    823      1.1  cgd 				do {
    824      1.1  cgd 					n = n * 8 + (*bp++ - '0');
    825      1.1  cgd 				} while (--i && '0' <= *bp && *bp <= '7');
    826      1.1  cgd 				*mp++ = n;
    827      1.1  cgd 			}
    828      1.1  cgd 			else switch (*bp++) {
    829      1.1  cgd 				case 'b': case 'B':
    830      1.1  cgd 					*mp++ = '\b';
    831      1.1  cgd 					break;
    832      1.1  cgd 				case 't': case 'T':
    833      1.1  cgd 					*mp++ = '\t';
    834      1.1  cgd 					break;
    835      1.1  cgd 				case 'n': case 'N':
    836      1.1  cgd 					*mp++ = '\n';
    837      1.1  cgd 					break;
    838      1.1  cgd 				case 'f': case 'F':
    839      1.1  cgd 					*mp++ = '\f';
    840      1.1  cgd 					break;
    841      1.1  cgd 				case 'r': case 'R':
    842      1.1  cgd 					*mp++ = '\r';
    843      1.1  cgd 					break;
    844      1.1  cgd 				case 'e': case 'E':
    845      1.1  cgd 					*mp++ = ESC;
    846      1.1  cgd 					break;
    847      1.1  cgd 				case 'c': case 'C':
    848      1.1  cgd 					*mp++ = ':';
    849      1.1  cgd 					break;
    850      1.1  cgd 				default:
    851      1.1  cgd 					/*
    852      1.1  cgd 					 * Catches '\', '^', and
    853      1.1  cgd 					 *  everything else.
    854      1.1  cgd 					 */
    855      1.1  cgd 					*mp++ = *(bp-1);
    856      1.1  cgd 					break;
    857      1.1  cgd 			}
    858      1.1  cgd 		} else
    859      1.1  cgd 			*mp++ = *bp++;
    860      1.1  cgd 		m_room--;
    861      1.1  cgd 
    862      1.1  cgd 		/*
    863      1.1  cgd 		 * Enforce loop invariant: if no room left in current
    864      1.1  cgd 		 * buffer, try to get some more.
    865      1.1  cgd 		 */
    866      1.1  cgd 		if (m_room == 0) {
    867      1.1  cgd 			size_t size = mp - mem;
    868      1.1  cgd 
    869      1.1  cgd 			if ((mem = realloc(mem, size + SFRAG)) == NULL)
    870      1.1  cgd 				return (-2);
    871      1.1  cgd 			m_room = SFRAG;
    872      1.1  cgd 			mp = mem + size;
    873      1.1  cgd 		}
    874      1.1  cgd 	}
    875      1.1  cgd 	*mp++ = '\0';	/* loop invariant let's us do this */
    876      1.1  cgd 	m_room--;
    877      1.1  cgd 	len = mp - mem - 1;
    878      1.1  cgd 
    879      1.1  cgd 	/*
    880      1.1  cgd 	 * Give back any extra memory and return value and success.
    881      1.1  cgd 	 */
    882      1.1  cgd 	if (m_room != 0)
    883      1.1  cgd 		if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
    884      1.1  cgd 			return (-2);
    885      1.1  cgd 	*str = mem;
    886      1.1  cgd 	return (len);
    887      1.1  cgd }
    888      1.1  cgd 
    889      1.1  cgd /*
    890      1.1  cgd  * Cgetustr retrieves the value of the string capability cap from the
    891      1.1  cgd  * capability record pointed to by buf.  The difference between cgetustr()
    892      1.1  cgd  * and cgetstr() is that cgetustr does not decode escapes but rather treats
    893      1.1  cgd  * all characters literally.  A pointer to a  NUL terminated malloc'd
    894      1.1  cgd  * copy of the string is returned in the char pointed to by str.  The
    895      1.1  cgd  * length of the string not including the trailing NUL is returned on success,
    896      1.1  cgd  * -1 if the requested string capability couldn't be found, -2 if a system
    897      1.1  cgd  * error was encountered (storage allocation failure).
    898      1.1  cgd  */
    899      1.1  cgd int
    900      1.1  cgd cgetustr(buf, cap, str)
    901      1.1  cgd 	char *buf, *cap, **str;
    902      1.1  cgd {
    903      1.1  cgd 	register u_int m_room;
    904      1.1  cgd 	register char *bp, *mp;
    905      1.1  cgd 	int len;
    906      1.1  cgd 	char *mem;
    907      1.1  cgd 
    908      1.1  cgd 	/*
    909      1.1  cgd 	 * Find string capability cap
    910      1.1  cgd 	 */
    911      1.1  cgd 	if ((bp = cgetcap(buf, cap, '=')) == NULL)
    912      1.1  cgd 		return (-1);
    913      1.1  cgd 
    914      1.1  cgd 	/*
    915      1.1  cgd 	 * Conversion / storage allocation loop ...  Allocate memory in
    916      1.1  cgd 	 * chunks SFRAG in size.
    917      1.1  cgd 	 */
    918      1.1  cgd 	if ((mem = malloc(SFRAG)) == NULL) {
    919      1.1  cgd 		errno = ENOMEM;
    920      1.1  cgd 		return (-2);	/* couldn't even allocate the first fragment */
    921      1.1  cgd 	}
    922      1.1  cgd 	m_room = SFRAG;
    923      1.1  cgd 	mp = mem;
    924      1.1  cgd 
    925      1.1  cgd 	while (*bp != ':' && *bp != '\0') {
    926      1.1  cgd 		/*
    927      1.1  cgd 		 * Loop invariants:
    928      1.1  cgd 		 *	There is always room for one more character in mem.
    929      1.1  cgd 		 *	Mp always points just past last character in mem.
    930      1.1  cgd 		 *	Bp always points at next character in buf.
    931      1.1  cgd 		 */
    932      1.1  cgd 		*mp++ = *bp++;
    933      1.1  cgd 		m_room--;
    934      1.1  cgd 
    935      1.1  cgd 		/*
    936      1.1  cgd 		 * Enforce loop invariant: if no room left in current
    937      1.1  cgd 		 * buffer, try to get some more.
    938      1.1  cgd 		 */
    939      1.1  cgd 		if (m_room == 0) {
    940      1.1  cgd 			size_t size = mp - mem;
    941      1.1  cgd 
    942      1.1  cgd 			if ((mem = realloc(mem, size + SFRAG)) == NULL)
    943      1.1  cgd 				return (-2);
    944      1.1  cgd 			m_room = SFRAG;
    945      1.1  cgd 			mp = mem + size;
    946      1.1  cgd 		}
    947      1.1  cgd 	}
    948      1.1  cgd 	*mp++ = '\0';	/* loop invariant let's us do this */
    949      1.1  cgd 	m_room--;
    950      1.1  cgd 	len = mp - mem - 1;
    951      1.1  cgd 
    952      1.1  cgd 	/*
    953      1.1  cgd 	 * Give back any extra memory and return value and success.
    954      1.1  cgd 	 */
    955      1.1  cgd 	if (m_room != 0)
    956      1.1  cgd 		if ((mem = realloc(mem, (size_t)(mp - mem))) == NULL)
    957      1.1  cgd 			return (-2);
    958      1.1  cgd 	*str = mem;
    959      1.1  cgd 	return (len);
    960      1.1  cgd }
    961      1.1  cgd 
    962      1.1  cgd /*
    963      1.1  cgd  * Cgetnum retrieves the value of the numeric capability cap from the
    964      1.1  cgd  * capability record pointed to by buf.  The numeric value is returned in
    965      1.1  cgd  * the long pointed to by num.  0 is returned on success, -1 if the requested
    966      1.1  cgd  * numeric capability couldn't be found.
    967      1.1  cgd  */
    968      1.1  cgd int
    969      1.1  cgd cgetnum(buf, cap, num)
    970      1.1  cgd 	char *buf, *cap;
    971      1.1  cgd 	long *num;
    972      1.1  cgd {
    973      1.1  cgd 	register long n;
    974      1.1  cgd 	register int base, digit;
    975      1.1  cgd 	register char *bp;
    976      1.1  cgd 
    977      1.1  cgd 	/*
    978      1.1  cgd 	 * Find numeric capability cap
    979      1.1  cgd 	 */
    980      1.1  cgd 	bp = cgetcap(buf, cap, '#');
    981      1.1  cgd 	if (bp == NULL)
    982      1.1  cgd 		return (-1);
    983      1.1  cgd 
    984      1.1  cgd 	/*
    985      1.1  cgd 	 * Look at value and determine numeric base:
    986      1.1  cgd 	 *	0x... or 0X...	hexadecimal,
    987      1.1  cgd 	 * else	0...		octal,
    988      1.1  cgd 	 * else			decimal.
    989      1.1  cgd 	 */
    990      1.1  cgd 	if (*bp == '0') {
    991      1.1  cgd 		bp++;
    992      1.1  cgd 		if (*bp == 'x' || *bp == 'X') {
    993      1.1  cgd 			bp++;
    994      1.1  cgd 			base = 16;
    995      1.1  cgd 		} else
    996      1.1  cgd 			base = 8;
    997      1.1  cgd 	} else
    998      1.1  cgd 		base = 10;
    999      1.1  cgd 
   1000      1.1  cgd 	/*
   1001      1.1  cgd 	 * Conversion loop ...
   1002      1.1  cgd 	 */
   1003      1.1  cgd 	n = 0;
   1004      1.1  cgd 	for (;;) {
   1005      1.1  cgd 		if ('0' <= *bp && *bp <= '9')
   1006      1.1  cgd 			digit = *bp - '0';
   1007      1.1  cgd 		else if ('a' <= *bp && *bp <= 'f')
   1008      1.1  cgd 			digit = 10 + *bp - 'a';
   1009      1.1  cgd 		else if ('A' <= *bp && *bp <= 'F')
   1010      1.1  cgd 			digit = 10 + *bp - 'A';
   1011      1.1  cgd 		else
   1012      1.1  cgd 			break;
   1013      1.1  cgd 
   1014      1.1  cgd 		if (digit >= base)
   1015      1.1  cgd 			break;
   1016      1.1  cgd 
   1017      1.1  cgd 		n = n * base + digit;
   1018      1.1  cgd 		bp++;
   1019      1.1  cgd 	}
   1020      1.1  cgd 
   1021      1.1  cgd 	/*
   1022      1.1  cgd 	 * Return value and success.
   1023      1.1  cgd 	 */
   1024      1.1  cgd 	*num = n;
   1025      1.1  cgd 	return (0);
   1026      1.1  cgd }
   1027      1.1  cgd 
   1028      1.1  cgd 
   1029      1.1  cgd /*
   1030      1.1  cgd  * Compare name field of record.
   1031      1.1  cgd  */
   1032      1.1  cgd static int
   1033      1.1  cgd nfcmp(nf, rec)
   1034      1.1  cgd 	char *nf, *rec;
   1035      1.1  cgd {
   1036      1.1  cgd 	char *cp, tmp;
   1037      1.1  cgd 	int ret;
   1038      1.1  cgd 
   1039      1.1  cgd 	for (cp = rec; *cp != ':'; cp++)
   1040      1.1  cgd 		;
   1041      1.1  cgd 
   1042      1.1  cgd 	tmp = *(cp + 1);
   1043      1.1  cgd 	*(cp + 1) = '\0';
   1044      1.1  cgd 	ret = strcmp(nf, rec);
   1045      1.1  cgd 	*(cp + 1) = tmp;
   1046      1.1  cgd 
   1047      1.1  cgd 	return (ret);
   1048      1.1  cgd }
   1049