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

Annotation of src/usr.bin/cap_mkdb/getinfo.c, Revision 1.18

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