diff options
author | Thorsten Lockert <tholo@cvs.openbsd.org> | 1999-03-05 04:47:47 +0000 |
---|---|---|
committer | Thorsten Lockert <tholo@cvs.openbsd.org> | 1999-03-05 04:47:47 +0000 |
commit | b28bfeb89a71361e0d701fc926db0cfaeb6d2a78 (patch) | |
tree | eb91b37ef22ab464733a0d66d76051f5fbb57278 /usr.bin/cap_mkdb | |
parent | aaa14edd7ee527002686b0260ce5ffe1ab567fc8 (diff) |
Merge cap_mkdb(1) and info_mkdb(1)
Diffstat (limited to 'usr.bin/cap_mkdb')
-rw-r--r-- | usr.bin/cap_mkdb/Makefile | 3 | ||||
-rw-r--r-- | usr.bin/cap_mkdb/cap_mkdb.1 | 12 | ||||
-rw-r--r-- | usr.bin/cap_mkdb/cap_mkdb.c | 52 | ||||
-rw-r--r-- | usr.bin/cap_mkdb/getinfo.c | 628 |
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 */ +} |