summaryrefslogtreecommitdiff
path: root/usr.bin/cap_mkdb
diff options
context:
space:
mode:
authorThorsten Lockert <tholo@cvs.openbsd.org>1999-03-05 04:47:47 +0000
committerThorsten Lockert <tholo@cvs.openbsd.org>1999-03-05 04:47:47 +0000
commitb28bfeb89a71361e0d701fc926db0cfaeb6d2a78 (patch)
treeeb91b37ef22ab464733a0d66d76051f5fbb57278 /usr.bin/cap_mkdb
parentaaa14edd7ee527002686b0260ce5ffe1ab567fc8 (diff)
Merge cap_mkdb(1) and info_mkdb(1)
Diffstat (limited to 'usr.bin/cap_mkdb')
-rw-r--r--usr.bin/cap_mkdb/Makefile3
-rw-r--r--usr.bin/cap_mkdb/cap_mkdb.112
-rw-r--r--usr.bin/cap_mkdb/cap_mkdb.c52
-rw-r--r--usr.bin/cap_mkdb/getinfo.c628
4 files changed, 675 insertions, 20 deletions
diff --git a/usr.bin/cap_mkdb/Makefile b/usr.bin/cap_mkdb/Makefile
index d1d341283f8..55b86c5c7f8 100644
--- a/usr.bin/cap_mkdb/Makefile
+++ b/usr.bin/cap_mkdb/Makefile
@@ -1,5 +1,6 @@
-# $OpenBSD: Makefile,v 1.3 1997/09/21 11:48:33 deraadt Exp $
+# $OpenBSD: Makefile,v 1.4 1999/03/05 04:47:45 tholo Exp $
PROG= cap_mkdb
+SRCS= cap_mkdb.c getinfo.c
.include <bsd.prog.mk>
diff --git a/usr.bin/cap_mkdb/cap_mkdb.1 b/usr.bin/cap_mkdb/cap_mkdb.1
index 99300c4c930..5443d45e67b 100644
--- a/usr.bin/cap_mkdb/cap_mkdb.1
+++ b/usr.bin/cap_mkdb/cap_mkdb.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: cap_mkdb.1,v 1.6 1998/09/23 04:32:36 aaron Exp $
+.\" $OpenBSD: cap_mkdb.1,v 1.7 1999/03/05 04:47:45 tholo Exp $
.\" $NetBSD: cap_mkdb.1,v 1.4 1995/03/26 03:59:36 glass Exp $
.\"
.\" Copyright (c) 1992, 1993
@@ -43,6 +43,7 @@
.Pp
.Sh SYNOPSIS
.Nm cap_mkdb
+.Op Fl i
.Op Fl v
.Op Fl f Ar outfile
.Ar file1
@@ -52,6 +53,8 @@
.Nm cap_mkdb
builds a hashed database out of the
.Xr getcap 3
+or
+.Xr terminfo 5
logical database constructed by the concatenation of the specified
files.
.Pp
@@ -70,6 +73,10 @@ The options are as follows:
.Bl -tag -width XXXXXX -indent
.It Fl f Ar outfile
Specify a different database basename.
+.It Fl i
+Expect the capability records to be parsed to be in
+.Xr terminfo 5
+format.
.It Fl v
Print out the number of capability records in the database.
.El
@@ -103,4 +110,5 @@ utility exits 0 on success or >0 if an error occurred.
.Sh SEE ALSO
.Xr dbopen 3 ,
.Xr getcap 3 ,
-.Xr termcap 5
+.Xr termcap 5 ,
+.Xr terminfo 5
diff --git a/usr.bin/cap_mkdb/cap_mkdb.c b/usr.bin/cap_mkdb/cap_mkdb.c
index ed340c9b3e2..b12a199bbd3 100644
--- a/usr.bin/cap_mkdb/cap_mkdb.c
+++ b/usr.bin/cap_mkdb/cap_mkdb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cap_mkdb.c,v 1.3 1997/01/15 23:42:17 millert Exp $ */
+/* $OpenBSD: cap_mkdb.c,v 1.4 1999/03/05 04:47:45 tholo Exp $ */
/* $NetBSD: cap_mkdb.c,v 1.5 1995/09/02 05:47:12 jtc Exp $ */
/*-
@@ -44,7 +44,7 @@ static char copyright[] =
#if 0
static char sccsid[] = "@(#)cap_mkdb.c 8.2 (Berkeley) 4/27/95";
#endif
-static char rcsid[] = "$OpenBSD: cap_mkdb.c,v 1.3 1997/01/15 23:42:17 millert Exp $";
+static char rcsid[] = "$OpenBSD: cap_mkdb.c,v 1.4 1999/03/05 04:47:45 tholo Exp $";
#endif /* not lint */
#include <sys/param.h>
@@ -58,15 +58,18 @@ static char rcsid[] = "$OpenBSD: cap_mkdb.c,v 1.3 1997/01/15 23:42:17 millert Ex
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <ctype.h>
#include <unistd.h>
void db_build __P((char **));
void dounlink __P((void));
void usage __P((void));
+int igetnext __P((char **, char **));
+int main __P((int, char *[]));
DB *capdbp;
-int verbose;
-char *capdb, *capname, buf[8 * 1024];
+int info, verbose;
+char *capname, buf[8 * 1024];
HASHINFO openinfo = {
4096, /* bsize */
@@ -78,7 +81,7 @@ HASHINFO openinfo = {
};
/*
- * Mkcapdb creates a capability hash database for quick retrieval of capability
+ * cap_mkdb creates a capability hash database for quick retrieval of capability
* records. The database contains 2 types of entries: records and references
* marked by the first byte in the data. A record entry contains the actual
* capability record whereas a reference contains the name (key) under which
@@ -92,7 +95,7 @@ main(argc, argv)
int c;
capname = NULL;
- while ((c = getopt(argc, argv, "f:v")) != -1) {
+ while ((c = getopt(argc, argv, "f:iv")) != -1) {
switch(c) {
case 'f':
capname = optarg;
@@ -100,6 +103,9 @@ main(argc, argv)
case 'v':
verbose = 1;
break;
+ case 'i':
+ info = 1;
+ break;
case '?':
default:
usage();
@@ -149,7 +155,7 @@ dounlink()
#define SHADOW (char)2
/*
- * Db_build() builds the name and capabilty databases according to the
+ * db_build() builds the name and capabilty databases according to the
* details above.
*/
void
@@ -164,7 +170,8 @@ db_build(ifiles)
data.data = NULL;
key.data = NULL;
- for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
+ for (reccnt = 0, bplen = 0;
+ (st = (info ? igetnext(&bp, ifiles) : cgetnext(&bp, ifiles))) > 0;) {
/*
* Allocate enough memory to store record, terminating
@@ -178,7 +185,7 @@ db_build(ifiles)
}
/* Find the end of the name field. */
- if ((p = strchr(bp, ':')) == NULL) {
+ if ((p = strchr(bp, info ? ',' : ':')) == NULL) {
warnx("no name field: %.*s", MIN(len, 20), bp);
continue;
}
@@ -190,13 +197,24 @@ db_build(ifiles)
break;
case 2:
((char *)(data.data))[0] = TCERR;
- warnx("Record not tc expanded: %.*s", p - bp, bp);
+ warnx("Record not tc expanded: %.*s", (int)(p - bp), bp);
break;
}
/* Create the stored record. */
- memmove(&((u_char *)(data.data))[1], bp, len + 1);
+ (void) memmove(&((u_char *)(data.data))[1], bp, len + 1);
data.size = len + 2;
+ if (info) {
+ for (t = memchr((char *)data.data + 1, ',', data.size - 1);
+ t;
+ t = memchr(t, ',', data.size - (t - (char *)data.data)))
+ *t++ = ':';
+
+ if (memchr((char *)data.data + 1, '\0', data.size - 2)) {
+ warnx("NUL in entry: %.*s", (int)MIN(len, 20), bp);
+ continue;
+ }
+ }
/* Store the record under the name field. */
key.data = bp;
@@ -208,7 +226,7 @@ db_build(ifiles)
/* NOTREACHED */
case 1:
warnx("ignored duplicate: %.*s",
- key.size, (char *)key.data);
+ (int)key.size, (char *)key.data);
continue;
}
++reccnt;
@@ -219,12 +237,12 @@ db_build(ifiles)
/* The rest of the names reference the entire name. */
((char *)(data.data))[0] = SHADOW;
- memmove(&((u_char *)(data.data))[1], key.data, key.size);
+ (void) memmove(&((u_char *)(data.data))[1], key.data, key.size);
data.size = key.size + 1;
/* Store references for other names. */
for (p = t = bp;; ++p) {
- if (p > t && (*p == ':' || *p == '|')) {
+ if (p > t && (*p == (info ? ',' : ':') || *p == '|')) {
key.size = p - t;
key.data = t;
switch(capdbp->put(capdbp,
@@ -234,11 +252,11 @@ db_build(ifiles)
/* NOTREACHED */
case 1:
warnx("ignored duplicate: %.*s",
- key.size, (char *)key.data);
+ (int)key.size, (char *)key.data);
}
t = p + 1;
}
- if (*p == ':')
+ if (*p == (info ? ',' : ':'))
break;
}
}
@@ -260,6 +278,6 @@ void
usage()
{
(void)fprintf(stderr,
- "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n");
+ "usage: cap_mkdb [-iv] [-f outfile] file1 [file2 ...]\n");
exit(1);
}
diff --git a/usr.bin/cap_mkdb/getinfo.c b/usr.bin/cap_mkdb/getinfo.c
new file mode 100644
index 00000000000..9214525f694
--- /dev/null
+++ b/usr.bin/cap_mkdb/getinfo.c
@@ -0,0 +1,628 @@
+/* $OpenBSD: getinfo.c,v 1.1 1999/03/05 04:47:45 tholo Exp $ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California.
+ * Copyright (c) 1996 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by SigmaSoft, Th. Lockert.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char rcsid[] = "$OpenBSD: getinfo.c,v 1.1 1999/03/05 04:47:45 tholo Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <db.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define BFRAG 1024
+#define BSIZE 1024
+#define ESC ('[' & 037) /* ASCII ESC */
+#define MAX_RECURSION 32 /* maximum getent recursion */
+#define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */
+
+#define RECOK (char)0
+#define TCERR (char)1
+#define SHADOW (char)2
+
+static int getent __P((char **, u_int *, char **, int, char *, int));
+static char *igetcap __P((char *, char *, int));
+static int igetmatch __P((char *, char *));
+static int igetclose __P((void));
+
+int igetnext __P((char **, char **));
+
+/*
+ * Cgetcap searches the capability record buf for the capability cap with
+ * type `type'. A pointer to the value of cap is returned on success, NULL
+ * if the requested capability couldn't be found.
+ *
+ * Specifying a type of ',' means that nothing should follow cap (,cap,).
+ * In this case a pointer to the terminating ',' or NUL will be returned if
+ * cap is found.
+ *
+ * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
+ * return NULL.
+ */
+static char *
+igetcap(buf, cap, type)
+ char *buf, *cap;
+ int type;
+{
+ register char *bp, *cp;
+
+ bp = buf;
+ for (;;) {
+ /*
+ * Skip past the current capability field - it's either the
+ * name field if this is the first time through the loop, or
+ * the remainder of a field whose name failed to match cap.
+ */
+ for (;;)
+ if (*bp == '\0')
+ return (NULL);
+ else
+ if (*bp++ == ',')
+ break;
+
+ /*
+ * Try to match (cap, type) in buf.
+ */
+ for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
+ continue;
+ if (*cp != '\0')
+ continue;
+ if (*bp == '@')
+ return (NULL);
+ if (type == ',') {
+ if (*bp != '\0' && *bp != ',')
+ continue;
+ return(bp);
+ }
+ if (*bp != type)
+ continue;
+ bp++;
+ return (*bp == '@' ? NULL : bp);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Getent implements the functions of igetent. If fd is non-negative,
+ * *db_array has already been opened and fd is the open file descriptor. We
+ * do this to save time and avoid using up file descriptors for use=
+ * recursions.
+ *
+ * Getent returns the same success/failure codes as igetent. On success, a
+ * pointer to a malloc'ed capability record with all use= capabilities fully
+ * expanded and its length (not including trailing ASCII NUL) are left in
+ * *cap and *len.
+ *
+ * Basic algorithm:
+ * + Allocate memory incrementally as needed in chunks of size BFRAG
+ * for capability buffer.
+ * + Recurse for each use=name and interpolate result. Stop when all
+ * names interpolated, a name can't be found, or depth exceeds
+ * MAX_RECURSION.
+ */
+static int
+getent(cap, len, db_array, fd, name, depth)
+ char **cap, **db_array, *name;
+ u_int *len;
+ int fd, depth;
+{
+ register char *r_end, *rp, **db_p;
+ int myfd, eof, foundit;
+ char *record;
+ int tc_not_resolved;
+
+ /*
+ * Return with ``loop detected'' error if we've recursed more than
+ * MAX_RECURSION times.
+ */
+ if (depth > MAX_RECURSION)
+ return (-3);
+
+ /*
+ * Allocate first chunk of memory.
+ */
+ if ((record = malloc(BFRAG)) == NULL) {
+ errno = ENOMEM;
+ return (-2);
+ }
+ r_end = record + BFRAG;
+ foundit = 0;
+ rp = NULL;
+ myfd = -1;
+ /*
+ * Loop through database array until finding the record.
+ */
+
+ for (db_p = db_array; *db_p != NULL; db_p++) {
+ eof = 0;
+
+ /*
+ * Open database if not already open.
+ */
+
+ if (fd >= 0) {
+ (void)lseek(fd, (off_t)0, SEEK_SET);
+ myfd = 0;
+ } else {
+ fd = open(*db_p, O_RDONLY, 0);
+ if (fd < 0) {
+ /* No error on unfound file. */
+ continue;
+ }
+ myfd = 1;
+ }
+ /*
+ * Find the requested capability record ...
+ */
+ {
+ char buf[BUFSIZ];
+ register char *b_end, *bp;
+ register int c;
+
+ /*
+ * Loop invariants:
+ * There is always room for one more character in record.
+ * R_end always points just past end of record.
+ * Rp always points just past last character in record.
+ * B_end always points just past last character in buf.
+ * Bp always points at next character in buf.
+ */
+ b_end = buf;
+ bp = buf;
+ for (;;) {
+
+ /*
+ * Read in a line implementing (\, newline)
+ * line continuation.
+ */
+ rp = record;
+ for (;;) {
+ if (bp >= b_end) {
+ int n;
+
+ n = read(fd, buf, sizeof(buf));
+ if (n <= 0) {
+ if (myfd)
+ (void)close(fd);
+ if (n < 0) {
+ free(record);
+ return (-2);
+ } else {
+ fd = -1;
+ eof = 1;
+ break;
+ }
+ }
+ b_end = buf+n;
+ bp = buf;
+ }
+
+ c = *bp++;
+ if (c == '\n') {
+ if (bp >= b_end) {
+ int n;
+
+ n = read(fd, buf, sizeof(buf));
+ if (n <= 0) {
+ if (myfd)
+ (void)close(fd);
+ if (n < 0) {
+ free(record);
+ return (-2);
+ } else {
+ fd = -1;
+ eof = 1;
+ break;
+ }
+ }
+ b_end = buf+n;
+ bp = buf;
+ }
+ if (rp > record && isspace(*bp))
+ continue;
+ else
+ break;
+ }
+ if (rp <= record || *(rp - 1) != ',' || !isspace(c))
+ *rp++ = c;
+
+ /*
+ * Enforce loop invariant: if no room
+ * left in record buffer, try to get
+ * some more.
+ */
+ if (rp >= r_end) {
+ u_int pos;
+ size_t newsize;
+
+ pos = rp - record;
+ newsize = r_end - record + BFRAG;
+ record = realloc(record, newsize);
+ if (record == NULL) {
+ errno = ENOMEM;
+ if (myfd)
+ (void)close(fd);
+ return (-2);
+ }
+ r_end = record + newsize;
+ rp = record + pos;
+ }
+ }
+ /* loop invariant let's us do this */
+ *rp++ = '\0';
+
+ /*
+ * If encountered eof check next file.
+ */
+ if (eof)
+ break;
+
+ /*
+ * Toss blank lines and comments.
+ */
+ if (*record == '\0' || *record == '#')
+ continue;
+
+ /*
+ * See if this is the record we want ...
+ */
+ if (igetmatch(record, name) == 0) {
+ foundit = 1;
+ break; /* found it! */
+ }
+ }
+ }
+ if (foundit)
+ break;
+ }
+
+ if (!foundit)
+ return (-1);
+
+ /*
+ * Got the capability record, but now we have to expand all use=name
+ * references in it ...
+ */
+ {
+ register char *newicap, *s;
+ register int newilen;
+ u_int ilen;
+ int diff, iret, tclen;
+ char *icap, *scan, *tc, *tcstart, *tcend;
+
+ /*
+ * Loop invariants:
+ * There is room for one more character in record.
+ * R_end points just past end of record.
+ * Rp points just past last character in record.
+ * Scan points at remainder of record that needs to be
+ * scanned for use=name constructs.
+ */
+ scan = record;
+ tc_not_resolved = 0;
+ for (;;) {
+ if ((tc = igetcap(scan, "use", '=')) == NULL)
+ break;
+
+ /*
+ * Find end of use=name and stomp on the trailing `,'
+ * (if present) so we can use it to call ourselves.
+ */
+ s = tc;
+ for (;;)
+ if (*s == '\0')
+ break;
+ else
+ if (*s++ == ',') {
+ *(s - 1) = '\0';
+ break;
+ }
+ tcstart = tc - 4;
+ tclen = s - tcstart;
+ tcend = s;
+
+ iret = getent(&icap, &ilen, db_p, fd, tc, depth+1);
+ newicap = icap; /* Put into a register. */
+ newilen = ilen;
+ if (iret != 0) {
+ /* an error */
+ if (iret < -1) {
+ if (myfd)
+ (void)close(fd);
+ free(record);
+ return (iret);
+ }
+ if (iret == 1)
+ tc_not_resolved = 1;
+ /* couldn't resolve tc */
+ if (iret == -1) {
+ *(s - 1) = ',';
+ scan = s - 1;
+ tc_not_resolved = 1;
+ continue;
+
+ }
+ }
+ /* not interested in name field of tc'ed record */
+ s = newicap;
+ for (;;)
+ if (*s == '\0')
+ break;
+ else
+ if (*s++ == ',')
+ break;
+ newilen -= s - newicap;
+ newicap = s;
+
+ /* make sure interpolated record is `,'-terminated */
+ s += newilen;
+ if (*(s-1) != ',') {
+ *s = ','; /* overwrite NUL with , */
+ newilen++;
+ }
+
+ /*
+ * Make sure there's enough room to insert the
+ * new record.
+ */
+ diff = newilen - tclen;
+ if (diff >= r_end - rp) {
+ u_int pos, tcpos, tcposend;
+ size_t newsize;
+
+ pos = rp - record;
+ newsize = r_end - record + diff + BFRAG;
+ tcpos = tcstart - record;
+ tcposend = tcend - record;
+ record = realloc(record, newsize);
+ if (record == NULL) {
+ errno = ENOMEM;
+ if (myfd)
+ (void)close(fd);
+ free(icap);
+ return (-2);
+ }
+ r_end = record + newsize;
+ rp = record + pos;
+ tcstart = record + tcpos;
+ tcend = record + tcposend;
+ }
+
+ /*
+ * Insert tc'ed record into our record.
+ */
+ s = tcstart + newilen;
+ bcopy(tcend, s, (size_t)(rp - tcend));
+ bcopy(newicap, tcstart, (size_t)newilen);
+ rp += diff;
+ free(icap);
+
+ /*
+ * Start scan on `,' so next igetcap works properly
+ * (igetcap always skips first field).
+ */
+ scan = s-1;
+ }
+
+ }
+ /*
+ * Close file (if we opened it), give back any extra memory, and
+ * return capability, length and success.
+ */
+ if (myfd)
+ (void)close(fd);
+ *len = rp - record - 1; /* don't count NUL */
+ if (r_end > rp)
+ if ((record =
+ realloc(record, (size_t)(rp - record))) == NULL) {
+ errno = ENOMEM;
+ return (-2);
+ }
+
+ *cap = record;
+ if (tc_not_resolved)
+ return (1);
+ return (0);
+}
+
+/*
+ * Cgetmatch will return 0 if name is one of the names of the capability
+ * record buf, -1 if not.
+ */
+static int
+igetmatch(buf, name)
+ char *buf, *name;
+{
+ register char *np, *bp;
+
+ /*
+ * Start search at beginning of record.
+ */
+ bp = buf;
+ for (;;) {
+ /*
+ * Try to match a record name.
+ */
+ np = name;
+ for (;;)
+ if (*np == '\0') {
+ if (*bp == '|' || *bp == ',' || *bp == '\0')
+ return (0);
+ else
+ break;
+ } else {
+ if (*bp++ != *np++)
+ break;
+ }
+
+ /*
+ * Match failed, skip to next name in record.
+ */
+ bp--; /* a '|' or ',' may have stopped the match */
+ for (;;)
+ if (*bp == '\0' || *bp == ',')
+ return (-1); /* match failed totally */
+ else
+ if (*bp++ == '|')
+ break; /* found next name */
+ }
+}
+
+static FILE *pfp;
+static int slash;
+static char **dbp;
+
+static int
+igetclose()
+{
+ if (pfp != NULL) {
+ (void)fclose(pfp);
+ pfp = NULL;
+ }
+ dbp = NULL;
+ slash = 0;
+ return(0);
+}
+
+/*
+ * Cgetnext() gets either the first or next entry in the logical database
+ * specified by db_array. It returns 0 upon completion of the database, 1
+ * upon returning an entry with more remaining, and -1 if an error occurs.
+ */
+int
+igetnext(bp, db_array)
+ register char **bp;
+ char **db_array;
+{
+ size_t len;
+ int status, done;
+ char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
+ u_int dummy;
+
+ if (dbp == NULL)
+ dbp = db_array;
+
+ if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
+ (void)igetclose();
+ return (-1);
+ }
+ for(;;) {
+ line = fgetln(pfp, &len);
+ if (line == NULL && pfp) {
+ (void)fclose(pfp);
+ if (ferror(pfp)) {
+ (void)igetclose();
+ return (-1);
+ } else {
+ if (*++dbp == NULL) {
+ (void)igetclose();
+ return (0);
+ } else if ((pfp =
+ fopen(*dbp, "r")) == NULL) {
+ (void)igetclose();
+ return (-1);
+ } else
+ continue;
+ }
+ } else
+ line[len - 1] = '\0';
+ if (len == 1) {
+ slash = 0;
+ continue;
+ }
+ if (isspace(*line) ||
+ *line == ',' || *line == '#' || slash) {
+ if (line[len - 2] == '\\')
+ slash = 1;
+ else
+ slash = 0;
+ continue;
+ }
+ if (line[len - 2] == '\\')
+ slash = 1;
+ else
+ slash = 0;
+
+ /*
+ * Line points to a name line.
+ */
+ done = 0;
+ np = nbuf;
+ for (;;) {
+ for (cp = line; *cp != '\0'; cp++) {
+ if (*cp == ',') {
+ *np++ = ',';
+ done = 1;
+ break;
+ }
+ *np++ = *cp;
+ }
+ if (done) {
+ *np = '\0';
+ break;
+ } else { /* name field extends beyond the line */
+ line = fgetln(pfp, &len);
+ if (line == NULL && pfp) {
+ (void)fclose(pfp);
+ if (ferror(pfp)) {
+ (void)igetclose();
+ return (-1);
+ }
+ } else
+ line[len - 1] = '\0';
+ }
+ }
+ rp = buf;
+ for(cp = nbuf; *cp != NULL; cp++)
+ if (*cp == '|' || *cp == ',')
+ break;
+ else
+ *rp++ = *cp;
+
+ *rp = '\0';
+ status = getent(bp, &dummy, db_array, -1, buf, 0);
+ if (status == -2 || status == -3)
+ (void)igetclose();
+
+ return (status + 1);
+ }
+ /* NOTREACHED */
+}