[BACK]Return to getinfo.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / info_mkdb

Annotation of src/usr.bin/info_mkdb/getinfo.c, Revision 1.2

1.2     ! tholo       1: /*     $OpenBSD: getinfo.c,v 1.1 1996/07/22 03:16:30 tholo Exp $       */
1.1       tholo       2:
                      3: /*-
                      4:  * Copyright (c) 1996 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by SigmaSoft, Th.  Lockert.
                     18:  * 4. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     22:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     23:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
                     24:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     25:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     26:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     27:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     28:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     29:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     30:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     31:  */
                     32:
                     33: #ifndef lint
1.2     ! tholo      34: static char rcsid[] = "$OpenBSD: getinfo.c,v 1.1 1996/07/22 03:16:30 tholo Exp $";
1.1       tholo      35: #endif /* not lint */
                     36:
                     37: #include <sys/types.h>
                     38:
                     39: #include <ctype.h>
                     40: #include <db.h>
                     41: #include <errno.h>
                     42: #include <fcntl.h>
                     43: #include <limits.h>
                     44: #include <stdio.h>
                     45: #include <stdlib.h>
                     46: #include <string.h>
                     47: #include <unistd.h>
                     48:
                     49: #define        BFRAG           1024
                     50: #define        BSIZE           1024
                     51: #define        ESC             ('[' & 037)     /* ASCII ESC */
                     52: #define        MAX_RECURSION   32              /* maximum getent recursion */
                     53: #define        SFRAG           100             /* cgetstr mallocs in SFRAG chunks */
                     54:
                     55: #define RECOK  (char)0
                     56: #define TCERR  (char)1
                     57: #define        SHADOW  (char)2
                     58:
                     59: static int      getent __P((char **, u_int *, char **, int, char *, int));
                     60: static char    *igetcap __P((char *, char *, int));
                     61: static int      igetmatch __P((char *, char *));
                     62: static int      igetclose __P((void));
                     63:
                     64: int    igetnext __P((char **, char **));
                     65:
                     66: /*
                     67:  * Cgetcap searches the capability record buf for the capability cap with
                     68:  * type `type'.  A pointer to the value of cap is returned on success, NULL
                     69:  * if the requested capability couldn't be found.
                     70:  *
                     71:  * Specifying a type of ',' means that nothing should follow cap (,cap,).
                     72:  * In this case a pointer to the terminating ',' or NUL will be returned if
                     73:  * cap is found.
                     74:  *
                     75:  * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator)
                     76:  * return NULL.
                     77:  */
                     78: static char *
                     79: igetcap(buf, cap, type)
                     80:        char *buf, *cap;
                     81:        int type;
                     82: {
                     83:        register char *bp, *cp;
                     84:
                     85:        bp = buf;
                     86:        for (;;) {
                     87:                /*
                     88:                 * Skip past the current capability field - it's either the
                     89:                 * name field if this is the first time through the loop, or
                     90:                 * the remainder of a field whose name failed to match cap.
                     91:                 */
                     92:                for (;;)
                     93:                        if (*bp == '\0')
                     94:                                return (NULL);
                     95:                        else
                     96:                                if (*bp++ == ',')
                     97:                                        break;
                     98:
                     99:                /*
                    100:                 * Try to match (cap, type) in buf.
                    101:                 */
                    102:                for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++)
                    103:                        continue;
                    104:                if (*cp != '\0')
                    105:                        continue;
                    106:                if (*bp == '@')
                    107:                        return (NULL);
                    108:                if (type == ',') {
                    109:                        if (*bp != '\0' && *bp != ',')
                    110:                                continue;
                    111:                        return(bp);
                    112:                }
                    113:                if (*bp != type)
                    114:                        continue;
                    115:                bp++;
                    116:                return (*bp == '@' ? NULL : bp);
                    117:        }
                    118:        /* NOTREACHED */
                    119: }
                    120:
                    121: /*
                    122:  * Getent implements the functions of igetent.  If fd is non-negative,
                    123:  * *db_array has already been opened and fd is the open file descriptor.  We
                    124:  * do this to save time and avoid using up file descriptors for use=
                    125:  * recursions.
                    126:  *
                    127:  * Getent returns the same success/failure codes as igetent.  On success, a
                    128:  * pointer to a malloc'ed capability record with all use= capabilities fully
                    129:  * expanded and its length (not including trailing ASCII NUL) are left in
                    130:  * *cap and *len.
                    131:  *
                    132:  * Basic algorithm:
                    133:  *     + Allocate memory incrementally as needed in chunks of size BFRAG
                    134:  *       for capability buffer.
                    135:  *     + Recurse for each use=name and interpolate result.  Stop when all
                    136:  *       names interpolated, a name can't be found, or depth exceeds
                    137:  *       MAX_RECURSION.
                    138:  */
                    139: static int
                    140: getent(cap, len, db_array, fd, name, depth)
                    141:        char **cap, **db_array, *name;
                    142:        u_int *len;
                    143:        int fd, depth;
                    144: {
                    145:        register char *r_end, *rp, **db_p;
                    146:        int myfd, eof, foundit;
                    147:        char *record;
                    148:        int tc_not_resolved;
                    149:
                    150:        /*
                    151:         * Return with ``loop detected'' error if we've recursed more than
                    152:         * MAX_RECURSION times.
                    153:         */
                    154:        if (depth > MAX_RECURSION)
                    155:                return (-3);
                    156:
                    157:        /*
                    158:         * Allocate first chunk of memory.
                    159:         */
                    160:        if ((record = malloc(BFRAG)) == NULL) {
                    161:                errno = ENOMEM;
                    162:                return (-2);
                    163:        }
                    164:        r_end = record + BFRAG;
                    165:        foundit = 0;
                    166:        rp = NULL;
                    167:        myfd = -1;
                    168:        /*
                    169:         * Loop through database array until finding the record.
                    170:         */
                    171:
                    172:        for (db_p = db_array; *db_p != NULL; db_p++) {
                    173:                eof = 0;
                    174:
                    175:                /*
                    176:                 * Open database if not already open.
                    177:                 */
                    178:
                    179:                if (fd >= 0) {
                    180:                        (void)lseek(fd, (off_t)0, L_SET);
                    181:                        myfd = 0;
                    182:                } else {
                    183:                        fd = open(*db_p, O_RDONLY, 0);
                    184:                        if (fd < 0) {
                    185:                                /* No error on unfound file. */
                    186:                                continue;
                    187:                        }
                    188:                        myfd = 1;
                    189:                }
                    190:                /*
                    191:                 * Find the requested capability record ...
                    192:                 */
                    193:                {
                    194:                char buf[BUFSIZ];
                    195:                register char *b_end, *bp;
                    196:                register int c;
                    197:
                    198:                /*
                    199:                 * Loop invariants:
                    200:                 *      There is always room for one more character in record.
                    201:                 *      R_end always points just past end of record.
                    202:                 *      Rp always points just past last character in record.
                    203:                 *      B_end always points just past last character in buf.
                    204:                 *      Bp always points at next character in buf.
                    205:                 */
                    206:                b_end = buf;
                    207:                bp = buf;
                    208:                for (;;) {
                    209:
                    210:                        /*
                    211:                         * Read in a line implementing (\, newline)
                    212:                         * line continuation.
                    213:                         */
                    214:                        rp = record;
                    215:                        for (;;) {
                    216:                                if (bp >= b_end) {
                    217:                                        int n;
                    218:
                    219:                                        n = read(fd, buf, sizeof(buf));
                    220:                                        if (n <= 0) {
                    221:                                                if (myfd)
                    222:                                                        (void)close(fd);
                    223:                                                if (n < 0) {
                    224:                                                        free(record);
                    225:                                                        return (-2);
                    226:                                                } else {
                    227:                                                        fd = -1;
                    228:                                                        eof = 1;
                    229:                                                        break;
                    230:                                                }
                    231:                                        }
                    232:                                        b_end = buf+n;
                    233:                                        bp = buf;
                    234:                                }
                    235:
                    236:                                c = *bp++;
                    237:                                if (c == '\n') {
                    238:                                        if (bp >= b_end) {
                    239:                                                int n;
                    240:
                    241:                                                n = read(fd, buf, sizeof(buf));
                    242:                                                if (n <= 0) {
                    243:                                                        if (myfd)
                    244:                                                                (void)close(fd);
                    245:                                                        if (n < 0) {
                    246:                                                                free(record);
                    247:                                                                return (-2);
                    248:                                                        } else {
                    249:                                                                fd = -1;
                    250:                                                                eof = 1;
                    251:                                                                break;
                    252:                                                        }
                    253:                                                }
                    254:                                                b_end = buf+n;
                    255:                                                bp = buf;
                    256:                                        }
                    257:                                        if (rp > record && isspace(*bp))
                    258:                                                continue;
                    259:                                        else
                    260:                                                break;
                    261:                                }
                    262:                                if (rp <= record || *(rp - 1) != ',' || !isspace(c))
                    263:                                        *rp++ = c;
                    264:
                    265:                                /*
                    266:                                 * Enforce loop invariant: if no room
                    267:                                 * left in record buffer, try to get
                    268:                                 * some more.
                    269:                                 */
                    270:                                if (rp >= r_end) {
                    271:                                        u_int pos;
                    272:                                        size_t newsize;
                    273:
                    274:                                        pos = rp - record;
                    275:                                        newsize = r_end - record + BFRAG;
                    276:                                        record = realloc(record, newsize);
                    277:                                        if (record == NULL) {
                    278:                                                errno = ENOMEM;
                    279:                                                if (myfd)
                    280:                                                        (void)close(fd);
                    281:                                                return (-2);
                    282:                                        }
                    283:                                        r_end = record + newsize;
                    284:                                        rp = record + pos;
                    285:                                }
                    286:                        }
                    287:                                /* loop invariant let's us do this */
                    288:                        *rp++ = '\0';
                    289:
                    290:                        /*
                    291:                         * If encountered eof check next file.
                    292:                         */
                    293:                        if (eof)
                    294:                                break;
                    295:
                    296:                        /*
                    297:                         * Toss blank lines and comments.
                    298:                         */
                    299:                        if (*record == '\0' || *record == '#')
                    300:                                continue;
                    301:
                    302:                        /*
                    303:                         * See if this is the record we want ...
                    304:                         */
                    305:                        if (igetmatch(record, name) == 0) {
                    306:                                foundit = 1;
                    307:                                break;  /* found it! */
                    308:                        }
                    309:                }
                    310:        }
                    311:                if (foundit)
                    312:                        break;
                    313:        }
                    314:
                    315:        if (!foundit)
                    316:                return (-1);
                    317:
                    318:        /*
                    319:         * Got the capability record, but now we have to expand all use=name
                    320:         * references in it ...
                    321:         */
                    322:        {
                    323:                register char *newicap, *s;
                    324:                register int newilen;
                    325:                u_int ilen;
                    326:                int diff, iret, tclen;
                    327:                char *icap, *scan, *tc, *tcstart, *tcend;
                    328:
                    329:                /*
                    330:                 * Loop invariants:
                    331:                 *      There is room for one more character in record.
                    332:                 *      R_end points just past end of record.
                    333:                 *      Rp points just past last character in record.
                    334:                 *      Scan points at remainder of record that needs to be
                    335:                 *      scanned for use=name constructs.
                    336:                 */
                    337:                scan = record;
                    338:                tc_not_resolved = 0;
                    339:                for (;;) {
                    340:                        if ((tc = igetcap(scan, "use", '=')) == NULL)
                    341:                                break;
                    342:
                    343:                        /*
                    344:                         * Find end of use=name and stomp on the trailing `,'
                    345:                         * (if present) so we can use it to call ourselves.
                    346:                         */
                    347:                        s = tc;
                    348:                        for (;;)
                    349:                                if (*s == '\0')
                    350:                                        break;
                    351:                                else
                    352:                                        if (*s++ == ',') {
                    353:                                                *(s - 1) = '\0';
                    354:                                                break;
                    355:                                        }
1.2     ! tholo     356:                        tcstart = tc - 4;
1.1       tholo     357:                        tclen = s - tcstart;
                    358:                        tcend = s;
                    359:
                    360:                        iret = getent(&icap, &ilen, db_p, fd, tc, depth+1);
                    361:                        newicap = icap;         /* Put into a register. */
                    362:                        newilen = ilen;
                    363:                        if (iret != 0) {
                    364:                                /* an error */
                    365:                                if (iret < -1) {
                    366:                                        if (myfd)
                    367:                                                (void)close(fd);
                    368:                                        free(record);
                    369:                                        return (iret);
                    370:                                }
                    371:                                if (iret == 1)
                    372:                                        tc_not_resolved = 1;
                    373:                                /* couldn't resolve tc */
                    374:                                if (iret == -1) {
                    375:                                        *(s - 1) = ',';
                    376:                                        scan = s - 1;
                    377:                                        tc_not_resolved = 1;
                    378:                                        continue;
                    379:
                    380:                                }
                    381:                        }
                    382:                        /* not interested in name field of tc'ed record */
                    383:                        s = newicap;
                    384:                        for (;;)
                    385:                                if (*s == '\0')
                    386:                                        break;
                    387:                                else
                    388:                                        if (*s++ == ',')
                    389:                                                break;
                    390:                        newilen -= s - newicap;
                    391:                        newicap = s;
                    392:
                    393:                        /* make sure interpolated record is `,'-terminated */
                    394:                        s += newilen;
                    395:                        if (*(s-1) != ',') {
                    396:                                *s = ',';       /* overwrite NUL with , */
                    397:                                newilen++;
                    398:                        }
                    399:
                    400:                        /*
                    401:                         * Make sure there's enough room to insert the
                    402:                         * new record.
                    403:                         */
                    404:                        diff = newilen - tclen;
                    405:                        if (diff >= r_end - rp) {
                    406:                                u_int pos, tcpos, tcposend;
                    407:                                size_t newsize;
                    408:
                    409:                                pos = rp - record;
                    410:                                newsize = r_end - record + diff + BFRAG;
                    411:                                tcpos = tcstart - record;
                    412:                                tcposend = tcend - record;
                    413:                                record = realloc(record, newsize);
                    414:                                if (record == NULL) {
                    415:                                        errno = ENOMEM;
                    416:                                        if (myfd)
                    417:                                                (void)close(fd);
                    418:                                        free(icap);
                    419:                                        return (-2);
                    420:                                }
                    421:                                r_end = record + newsize;
                    422:                                rp = record + pos;
                    423:                                tcstart = record + tcpos;
                    424:                                tcend = record + tcposend;
                    425:                        }
                    426:
                    427:                        /*
                    428:                         * Insert tc'ed record into our record.
                    429:                         */
                    430:                        s = tcstart + newilen;
                    431:                        bcopy(tcend, s, (size_t)(rp - tcend));
                    432:                        bcopy(newicap, tcstart, (size_t)newilen);
                    433:                        rp += diff;
                    434:                        free(icap);
                    435:
                    436:                        /*
                    437:                         * Start scan on `,' so next igetcap works properly
                    438:                         * (igetcap always skips first field).
                    439:                         */
                    440:                        scan = s-1;
                    441:                }
                    442:
                    443:        }
                    444:        /*
                    445:         * Close file (if we opened it), give back any extra memory, and
                    446:         * return capability, length and success.
                    447:         */
                    448:        if (myfd)
                    449:                (void)close(fd);
                    450:        *len = rp - record - 1; /* don't count NUL */
                    451:        if (r_end > rp)
                    452:                if ((record =
                    453:                     realloc(record, (size_t)(rp - record))) == NULL) {
                    454:                        errno = ENOMEM;
                    455:                        return (-2);
                    456:                }
                    457:
                    458:        *cap = record;
                    459:        if (tc_not_resolved)
                    460:                return (1);
                    461:        return (0);
                    462: }
                    463:
                    464: /*
                    465:  * Cgetmatch will return 0 if name is one of the names of the capability
                    466:  * record buf, -1 if not.
                    467:  */
                    468: static int
                    469: igetmatch(buf, name)
                    470:        char *buf, *name;
                    471: {
                    472:        register char *np, *bp;
                    473:
                    474:        /*
                    475:         * Start search at beginning of record.
                    476:         */
                    477:        bp = buf;
                    478:        for (;;) {
                    479:                /*
                    480:                 * Try to match a record name.
                    481:                 */
                    482:                np = name;
                    483:                for (;;)
                    484:                        if (*np == '\0')
                    485:                                if (*bp == '|' || *bp == ',' || *bp == '\0')
                    486:                                        return (0);
                    487:                                else
                    488:                                        break;
                    489:                        else
                    490:                                if (*bp++ != *np++)
                    491:                                        break;
                    492:
                    493:                /*
                    494:                 * Match failed, skip to next name in record.
                    495:                 */
                    496:                bp--;   /* a '|' or ',' may have stopped the match */
                    497:                for (;;)
                    498:                        if (*bp == '\0' || *bp == ',')
                    499:                                return (-1);    /* match failed totally */
                    500:                        else
                    501:                                if (*bp++ == '|')
                    502:                                        break;  /* found next name */
                    503:        }
                    504: }
                    505:
                    506: static FILE *pfp;
                    507: static int slash;
                    508: static char **dbp;
                    509:
                    510: static int
                    511: igetclose()
                    512: {
                    513:        if (pfp != NULL) {
                    514:                (void)fclose(pfp);
                    515:                pfp = NULL;
                    516:        }
                    517:        dbp = NULL;
                    518:        slash = 0;
                    519:        return(0);
                    520: }
                    521:
                    522: /*
                    523:  * Cgetnext() gets either the first or next entry in the logical database
                    524:  * specified by db_array.  It returns 0 upon completion of the database, 1
                    525:  * upon returning an entry with more remaining, and -1 if an error occurs.
                    526:  */
                    527: int
                    528: igetnext(bp, db_array)
                    529:         register char **bp;
                    530:        char **db_array;
                    531: {
                    532:        size_t len;
                    533:        int status, done;
                    534:        char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE];
                    535:        u_int dummy;
                    536:
                    537:        if (dbp == NULL)
                    538:                dbp = db_array;
                    539:
                    540:        if (pfp == NULL && (pfp = fopen(*dbp, "r")) == NULL) {
                    541:                (void)igetclose();
                    542:                return (-1);
                    543:        }
                    544:        for(;;) {
                    545:                line = fgetln(pfp, &len);
                    546:                if (line == NULL && pfp) {
                    547:                        (void)fclose(pfp);
                    548:                        if (ferror(pfp)) {
                    549:                                (void)igetclose();
                    550:                                return (-1);
                    551:                        } else {
                    552:                                if (*++dbp == NULL) {
                    553:                                        (void)igetclose();
                    554:                                        return (0);
                    555:                                } else if ((pfp =
                    556:                                    fopen(*dbp, "r")) == NULL) {
                    557:                                        (void)igetclose();
                    558:                                        return (-1);
                    559:                                } else
                    560:                                        continue;
                    561:                        }
                    562:                } else
                    563:                        line[len - 1] = '\0';
                    564:                if (len == 1) {
                    565:                        slash = 0;
                    566:                        continue;
                    567:                }
                    568:                if (isspace(*line) ||
                    569:                    *line == ',' || *line == '#' || slash) {
                    570:                        if (line[len - 2] == '\\')
                    571:                                slash = 1;
                    572:                        else
                    573:                                slash = 0;
                    574:                        continue;
                    575:                }
                    576:                if (line[len - 2] == '\\')
                    577:                        slash = 1;
                    578:                else
                    579:                        slash = 0;
                    580:
                    581:                /*
                    582:                 * Line points to a name line.
                    583:                 */
                    584:                done = 0;
                    585:                np = nbuf;
                    586:                for (;;) {
                    587:                        for (cp = line; *cp != '\0'; cp++) {
                    588:                                if (*cp == ',') {
                    589:                                        *np++ = ',';
                    590:                                        done = 1;
                    591:                                        break;
                    592:                                }
                    593:                                *np++ = *cp;
                    594:                        }
                    595:                        if (done) {
                    596:                                *np = '\0';
                    597:                                break;
                    598:                        } else { /* name field extends beyond the line */
                    599:                                line = fgetln(pfp, &len);
                    600:                                if (line == NULL && pfp) {
                    601:                                        (void)fclose(pfp);
                    602:                                        if (ferror(pfp)) {
                    603:                                                (void)igetclose();
                    604:                                                return (-1);
                    605:                                        }
                    606:                                } else
                    607:                                        line[len - 1] = '\0';
                    608:                        }
                    609:                }
                    610:                rp = buf;
                    611:                for(cp = nbuf; *cp != NULL; cp++)
                    612:                        if (*cp == '|' || *cp == ',')
                    613:                                break;
                    614:                        else
                    615:                                *rp++ = *cp;
                    616:
                    617:                *rp = '\0';
                    618:                status = getent(bp, &dummy, db_array, -1, buf, 0);
                    619:                if (status == -2 || status == -3)
                    620:                        (void)igetclose();
                    621:
                    622:                return (status + 1);
                    623:        }
                    624:        /* NOTREACHED */
                    625: }