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

Annotation of src/usr.bin/file/apprentice.c, Revision 1.1.1.1

1.1       deraadt     1: /*
                      2:  * apprentice - make one pass through /etc/magic, learning its secrets.
                      3:  *
                      4:  * Copyright (c) Ian F. Darwin, 1987.
                      5:  * Written by Ian F. Darwin.
                      6:  *
                      7:  * This software is not subject to any license of the American Telephone
                      8:  * and Telegraph Company or of the Regents of the University of California.
                      9:  *
                     10:  * Permission is granted to anyone to use this software for any purpose on
                     11:  * any computer system, and to alter it and redistribute it freely, subject
                     12:  * to the following restrictions:
                     13:  *
                     14:  * 1. The author is not responsible for the consequences of use of this
                     15:  *    software, no matter how awful, even if they arise from flaws in it.
                     16:  *
                     17:  * 2. The origin of this software must not be misrepresented, either by
                     18:  *    explicit claim or by omission.  Since few users ever read sources,
                     19:  *    credits must appear in the documentation.
                     20:  *
                     21:  * 3. Altered versions must be plainly marked as such, and must not be
                     22:  *    misrepresented as being the original software.  Since few users
                     23:  *    ever read sources, credits must appear in the documentation.
                     24:  *
                     25:  * 4. This notice may not be removed or altered.
                     26:  */
                     27:
                     28: #include <stdio.h>
                     29: #include <stdlib.h>
                     30: #include <string.h>
                     31: #include <ctype.h>
                     32: #include "file.h"
                     33:
                     34: #ifndef        lint
                     35: static char *moduleid =
                     36:        "@(#)$Id: apprentice.c,v 1.9 1995/05/21 00:13:24 christos Exp $";
                     37: #endif /* lint */
                     38:
                     39: #define        EATAB {while (isascii((unsigned char) *l) && \
                     40:                      isspace((unsigned char) *l))  ++l;}
                     41: #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
                     42:                        tolower((unsigned char) (l)) : (l))
                     43:
                     44:
                     45: static int getvalue    __P((struct magic *, char **));
                     46: static int hextoint    __P((int));
                     47: static char *getstr    __P((char *, char *, int, int *));
                     48: static int parse       __P((char *, int *, int));
                     49: static void eatsize    __P((char **));
                     50:
                     51: static int maxmagic = 0;
                     52:
                     53:
                     54: int
                     55: apprentice(fn, check)
                     56: char *fn;                      /* name of magic file */
                     57: int check;                     /* non-zero? checking-only run. */
                     58: {
                     59:        FILE *f;
                     60:        char line[BUFSIZ+1];
                     61:        int errs = 0;
                     62:
                     63:        f = fopen(fn, "r");
                     64:        if (f==NULL) {
                     65:                (void) fprintf(stderr, "%s: can't read magic file %s\n",
                     66:                progname, fn);
                     67:                if (check)
                     68:                        return -1;
                     69:                else
                     70:                        exit(1);
                     71:        }
                     72:
                     73:         maxmagic = MAXMAGIS;
                     74:        if ((magic = (struct magic *) calloc(sizeof(struct magic), maxmagic))
                     75:            == NULL) {
                     76:                (void) fprintf(stderr, "%s: Out of memory.\n", progname);
                     77:                if (check)
                     78:                        return -1;
                     79:                else
                     80:                        exit(1);
                     81:        }
                     82:
                     83:        /* parse it */
                     84:        if (check)      /* print silly verbose header for USG compat. */
                     85:                (void) printf("cont\toffset\ttype\topcode\tmask\tvalue\tdesc\n");
                     86:
                     87:        for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
                     88:                if (line[0]=='#')       /* comment, do not parse */
                     89:                        continue;
                     90:                if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
                     91:                        continue;
                     92:                line[strlen(line)-1] = '\0'; /* delete newline */
                     93:                if (parse(line, &nmagic, check) != 0)
                     94:                        ++errs;
                     95:        }
                     96:
                     97:        (void) fclose(f);
                     98:        return errs ? -1 : 0;
                     99: }
                    100:
                    101: /*
                    102:  * extend the sign bit if the comparison is to be signed
                    103:  */
                    104: unsigned long
                    105: signextend(m, v)
                    106: struct magic *m;
                    107: unsigned long v;
                    108: {
                    109:        if (!(m->flag & UNSIGNED))
                    110:                switch(m->type) {
                    111:                /*
                    112:                 * Do not remove the casts below.  They are
                    113:                 * vital.  When later compared with the data,
                    114:                 * the sign extension must have happened.
                    115:                 */
                    116:                case BYTE:
                    117:                        v = (char) v;
                    118:                        break;
                    119:                case SHORT:
                    120:                case BESHORT:
                    121:                case LESHORT:
                    122:                        v = (short) v;
                    123:                        break;
                    124:                case DATE:
                    125:                case BEDATE:
                    126:                case LEDATE:
                    127:                case LONG:
                    128:                case BELONG:
                    129:                case LELONG:
                    130:                        v = (long) v;
                    131:                        break;
                    132:                case STRING:
                    133:                        break;
                    134:                default:
                    135:                        magwarn("can't happen: m->type=%d\n",
                    136:                                m->type);
                    137:                        return -1;
                    138:                }
                    139:        return v;
                    140: }
                    141:
                    142: /*
                    143:  * parse one line from magic file, put into magic[index++] if valid
                    144:  */
                    145: static int
                    146: parse(l, ndx, check)
                    147: char *l;
                    148: int *ndx, check;
                    149: {
                    150:        int i = 0, nd = *ndx;
                    151:        struct magic *m;
                    152:        char *t, *s;
                    153:
                    154: #define ALLOC_INCR     20
                    155:        if (nd+1 >= maxmagic){
                    156:            maxmagic += ALLOC_INCR;
                    157:            if ((magic = (struct magic *) realloc(magic,
                    158:                                                  sizeof(struct magic) *
                    159:                                                  maxmagic)) == NULL) {
                    160:                (void) fprintf(stderr, "%s: Out of memory.\n", progname);
                    161:                if (check)
                    162:                        return -1;
                    163:                else
                    164:                        exit(1);
                    165:            }
                    166:            memset(&magic[*ndx], 0, sizeof(struct magic) * ALLOC_INCR);
                    167:        }
                    168:        m = &magic[*ndx];
                    169:        m->flag = 0;
                    170:        m->cont_level = 0;
                    171:
                    172:        while (*l == '>') {
                    173:                ++l;            /* step over */
                    174:                m->cont_level++;
                    175:        }
                    176:
                    177:        if (m->cont_level != 0 && *l == '(') {
                    178:                ++l;            /* step over */
                    179:                m->flag |= INDIR;
                    180:        }
                    181:
                    182:        /* get offset, then skip over it */
                    183:        m->offset = (int) strtoul(l,&t,0);
                    184:         if (l == t)
                    185:                magwarn("offset %s invalid", l);
                    186:         l = t;
                    187:
                    188:        if (m->flag & INDIR) {
                    189:                m->in.type = LONG;
                    190:                m->in.offset = 0;
                    191:                /*
                    192:                 * read [.lbs][+-]nnnnn)
                    193:                 */
                    194:                if (*l == '.') {
                    195:                        l++;
                    196:                        switch (LOWCASE(*l)) {
                    197:                        case 'l':
                    198:                                m->in.type = LONG;
                    199:                                break;
                    200:                        case 'h':
                    201:                        case 's':
                    202:                                m->in.type = SHORT;
                    203:                                break;
                    204:                        case 'c':
                    205:                        case 'b':
                    206:                                m->in.type = BYTE;
                    207:                                break;
                    208:                        default:
                    209:                                magwarn("indirect offset type %c invalid", *l);
                    210:                                break;
                    211:                        }
                    212:                        l++;
                    213:                }
                    214:                s = l;
                    215:                if (*l == '+' || *l == '-') l++;
                    216:                if (isdigit((unsigned char)*l)) {
                    217:                        m->in.offset = strtoul(l, &t, 0);
                    218:                        if (*s == '-') m->in.offset = - m->in.offset;
                    219:                }
                    220:                else
                    221:                        t = l;
                    222:                if (*t++ != ')')
                    223:                        magwarn("missing ')' in indirect offset");
                    224:                l = t;
                    225:        }
                    226:
                    227:
                    228:        while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
                    229:                ++l;
                    230:        EATAB;
                    231:
                    232: #define NBYTE          4
                    233: #define NSHORT         5
                    234: #define NLONG          4
                    235: #define NSTRING        6
                    236: #define NDATE          4
                    237: #define NBESHORT       7
                    238: #define NBELONG                6
                    239: #define NBEDATE                6
                    240: #define NLESHORT       7
                    241: #define NLELONG                6
                    242: #define NLEDATE                6
                    243:
                    244:        if (*l == 'u') {
                    245:                ++l;
                    246:                m->flag |= UNSIGNED;
                    247:        }
                    248:
                    249:        /* get type, skip it */
                    250:        if (strncmp(l, "byte", NBYTE)==0) {
                    251:                m->type = BYTE;
                    252:                l += NBYTE;
                    253:        } else if (strncmp(l, "short", NSHORT)==0) {
                    254:                m->type = SHORT;
                    255:                l += NSHORT;
                    256:        } else if (strncmp(l, "long", NLONG)==0) {
                    257:                m->type = LONG;
                    258:                l += NLONG;
                    259:        } else if (strncmp(l, "string", NSTRING)==0) {
                    260:                m->type = STRING;
                    261:                l += NSTRING;
                    262:        } else if (strncmp(l, "date", NDATE)==0) {
                    263:                m->type = DATE;
                    264:                l += NDATE;
                    265:        } else if (strncmp(l, "beshort", NBESHORT)==0) {
                    266:                m->type = BESHORT;
                    267:                l += NBESHORT;
                    268:        } else if (strncmp(l, "belong", NBELONG)==0) {
                    269:                m->type = BELONG;
                    270:                l += NBELONG;
                    271:        } else if (strncmp(l, "bedate", NBEDATE)==0) {
                    272:                m->type = BEDATE;
                    273:                l += NBEDATE;
                    274:        } else if (strncmp(l, "leshort", NLESHORT)==0) {
                    275:                m->type = LESHORT;
                    276:                l += NLESHORT;
                    277:        } else if (strncmp(l, "lelong", NLELONG)==0) {
                    278:                m->type = LELONG;
                    279:                l += NLELONG;
                    280:        } else if (strncmp(l, "ledate", NLEDATE)==0) {
                    281:                m->type = LEDATE;
                    282:                l += NLEDATE;
                    283:        } else {
                    284:                magwarn("type %s invalid", l);
                    285:                return -1;
                    286:        }
                    287:        /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
                    288:        if (*l == '&') {
                    289:                ++l;
                    290:                m->mask = signextend(m, strtoul(l, &l, 0));
                    291:                eatsize(&l);
                    292:        } else
                    293:                m->mask = ~0L;
                    294:        EATAB;
                    295:
                    296:        switch (*l) {
                    297:        case '>':
                    298:        case '<':
                    299:        /* Old-style anding: "0 byte &0x80 dynamically linked" */
                    300:        case '&':
                    301:        case '^':
                    302:        case '=':
                    303:                m->reln = *l;
                    304:                ++l;
                    305:                break;
                    306:        case '!':
                    307:                if (m->type != STRING) {
                    308:                        m->reln = *l;
                    309:                        ++l;
                    310:                        break;
                    311:                }
                    312:                /* FALL THROUGH */
                    313:        default:
                    314:                if (*l == 'x' && isascii((unsigned char)l[1]) &&
                    315:                    isspace((unsigned char)l[1])) {
                    316:                        m->reln = *l;
                    317:                        ++l;
                    318:                        goto GetDesc;   /* Bill The Cat */
                    319:                }
                    320:                m->reln = '=';
                    321:                break;
                    322:        }
                    323:        EATAB;
                    324:
                    325:        if (getvalue(m, &l))
                    326:                return -1;
                    327:        /*
                    328:         * TODO finish this macro and start using it!
                    329:         * #define offsetcheck {if (offset > HOWMANY-1)
                    330:         *      magwarn("offset too big"); }
                    331:         */
                    332:
                    333:        /*
                    334:         * now get last part - the description
                    335:         */
                    336: GetDesc:
                    337:        EATAB;
                    338:        if (l[0] == '\b') {
                    339:                ++l;
                    340:                m->nospflag = 1;
                    341:        } else if ((l[0] == '\\') && (l[1] == 'b')) {
                    342:                ++l;
                    343:                ++l;
                    344:                m->nospflag = 1;
                    345:        } else
                    346:                m->nospflag = 0;
                    347:        while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
                    348:                /* NULLBODY */;
                    349:
                    350:        if (check) {
                    351:                mdump(m);
                    352:        }
                    353:        ++(*ndx);               /* make room for next */
                    354:        return 0;
                    355: }
                    356:
                    357: /*
                    358:  * Read a numeric value from a pointer, into the value union of a magic
                    359:  * pointer, according to the magic type.  Update the string pointer to point
                    360:  * just after the number read.  Return 0 for success, non-zero for failure.
                    361:  */
                    362: static int
                    363: getvalue(m, p)
                    364: struct magic *m;
                    365: char **p;
                    366: {
                    367:        int slen;
                    368:
                    369:        if (m->type == STRING) {
                    370:                *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
                    371:                m->vallen = slen;
                    372:        } else
                    373:                if (m->reln != 'x') {
                    374:                        m->value.l = signextend(m, strtoul(*p, p, 0));
                    375:                        eatsize(p);
                    376:                }
                    377:        return 0;
                    378: }
                    379:
                    380: /*
                    381:  * Convert a string containing C character escapes.  Stop at an unescaped
                    382:  * space or tab.
                    383:  * Copy the converted version to "p", returning its length in *slen.
                    384:  * Return updated scan pointer as function result.
                    385:  */
                    386: static char *
                    387: getstr(s, p, plen, slen)
                    388: register char  *s;
                    389: register char  *p;
                    390: int    plen, *slen;
                    391: {
                    392:        char    *origs = s, *origp = p;
                    393:        char    *pmax = p + plen - 1;
                    394:        register int    c;
                    395:        register int    val;
                    396:
                    397:        while ((c = *s++) != '\0') {
                    398:                if (isspace((unsigned char) c))
                    399:                        break;
                    400:                if (p >= pmax) {
                    401:                        fprintf(stderr, "String too long: %s\n", origs);
                    402:                        break;
                    403:                }
                    404:                if(c == '\\') {
                    405:                        switch(c = *s++) {
                    406:
                    407:                        case '\0':
                    408:                                goto out;
                    409:
                    410:                        default:
                    411:                                *p++ = (char) c;
                    412:                                break;
                    413:
                    414:                        case 'n':
                    415:                                *p++ = '\n';
                    416:                                break;
                    417:
                    418:                        case 'r':
                    419:                                *p++ = '\r';
                    420:                                break;
                    421:
                    422:                        case 'b':
                    423:                                *p++ = '\b';
                    424:                                break;
                    425:
                    426:                        case 't':
                    427:                                *p++ = '\t';
                    428:                                break;
                    429:
                    430:                        case 'f':
                    431:                                *p++ = '\f';
                    432:                                break;
                    433:
                    434:                        case 'v':
                    435:                                *p++ = '\v';
                    436:                                break;
                    437:
                    438:                        /* \ and up to 3 octal digits */
                    439:                        case '0':
                    440:                        case '1':
                    441:                        case '2':
                    442:                        case '3':
                    443:                        case '4':
                    444:                        case '5':
                    445:                        case '6':
                    446:                        case '7':
                    447:                                val = c - '0';
                    448:                                c = *s++;  /* try for 2 */
                    449:                                if(c >= '0' && c <= '7') {
                    450:                                        val = (val<<3) | (c - '0');
                    451:                                        c = *s++;  /* try for 3 */
                    452:                                        if(c >= '0' && c <= '7')
                    453:                                                val = (val<<3) | (c-'0');
                    454:                                        else
                    455:                                                --s;
                    456:                                }
                    457:                                else
                    458:                                        --s;
                    459:                                *p++ = (char)val;
                    460:                                break;
                    461:
                    462:                        /* \x and up to 3 hex digits */
                    463:                        case 'x':
                    464:                                val = 'x';      /* Default if no digits */
                    465:                                c = hextoint(*s++);     /* Get next char */
                    466:                                if (c >= 0) {
                    467:                                        val = c;
                    468:                                        c = hextoint(*s++);
                    469:                                        if (c >= 0) {
                    470:                                                val = (val << 4) + c;
                    471:                                                c = hextoint(*s++);
                    472:                                                if (c >= 0) {
                    473:                                                        val = (val << 4) + c;
                    474:                                                } else
                    475:                                                        --s;
                    476:                                        } else
                    477:                                                --s;
                    478:                                } else
                    479:                                        --s;
                    480:                                *p++ = (char)val;
                    481:                                break;
                    482:                        }
                    483:                } else
                    484:                        *p++ = (char)c;
                    485:        }
                    486: out:
                    487:        *p = '\0';
                    488:        *slen = p - origp;
                    489:        return s;
                    490: }
                    491:
                    492:
                    493: /* Single hex char to int; -1 if not a hex char. */
                    494: static int
                    495: hextoint(c)
                    496: int c;
                    497: {
                    498:        if (!isascii((unsigned char) c))        return -1;
                    499:        if (isdigit((unsigned char) c))         return c - '0';
                    500:        if ((c>='a')&&(c<='f')) return c + 10 - 'a';
                    501:        if ((c>='A')&&(c<='F')) return c + 10 - 'A';
                    502:                                return -1;
                    503: }
                    504:
                    505:
                    506: /*
                    507:  * Print a string containing C character escapes.
                    508:  */
                    509: void
                    510: showstr(fp, s, len)
                    511: FILE *fp;
                    512: const char *s;
                    513: int len;
                    514: {
                    515:        register char   c;
                    516:
                    517:        for (;;) {
                    518:                c = *s++;
                    519:                if (len == -1) {
                    520:                        if (c == '\0')
                    521:                                break;
                    522:                }
                    523:                else  {
                    524:                        if (len-- == 0)
                    525:                                break;
                    526:                }
                    527:                if(c >= 040 && c <= 0176)       /* TODO isprint && !iscntrl */
                    528:                        (void) fputc(c, fp);
                    529:                else {
                    530:                        (void) fputc('\\', fp);
                    531:                        switch (c) {
                    532:
                    533:                        case '\n':
                    534:                                (void) fputc('n', fp);
                    535:                                break;
                    536:
                    537:                        case '\r':
                    538:                                (void) fputc('r', fp);
                    539:                                break;
                    540:
                    541:                        case '\b':
                    542:                                (void) fputc('b', fp);
                    543:                                break;
                    544:
                    545:                        case '\t':
                    546:                                (void) fputc('t', fp);
                    547:                                break;
                    548:
                    549:                        case '\f':
                    550:                                (void) fputc('f', fp);
                    551:                                break;
                    552:
                    553:                        case '\v':
                    554:                                (void) fputc('v', fp);
                    555:                                break;
                    556:
                    557:                        default:
                    558:                                (void) fprintf(fp, "%.3o", c & 0377);
                    559:                                break;
                    560:                        }
                    561:                }
                    562:        }
                    563: }
                    564:
                    565: /*
                    566:  * eatsize(): Eat the size spec from a number [eg. 10UL]
                    567:  */
                    568: static void
                    569: eatsize(p)
                    570: char **p;
                    571: {
                    572:        char *l = *p;
                    573:
                    574:        if (LOWCASE(*l) == 'u')
                    575:                l++;
                    576:
                    577:        switch (LOWCASE(*l)) {
                    578:        case 'l':    /* long */
                    579:        case 's':    /* short */
                    580:        case 'h':    /* short */
                    581:        case 'b':    /* char/byte */
                    582:        case 'c':    /* char/byte */
                    583:                l++;
                    584:                /*FALLTHROUGH*/
                    585:        default:
                    586:                break;
                    587:        }
                    588:
                    589:        *p = l;
                    590: }