[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.25

1.25    ! chl         1: /*     $OpenBSD: apprentice.c,v 1.24 2007/10/05 14:29:46 chl Exp $ */
1.1       deraadt     2: /*
1.16      ian         3:  * Copyright (c) Ian F. Darwin 1986-1995.
                      4:  * Software written by Ian F. Darwin and others;
                      5:  * maintained 1995-present by Christos Zoulas and others.
                      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 immediately at the beginning of the file, without modification,
                     12:  *    this list of conditions, and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
                     16:  *
                     17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     18:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     19:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     20:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
                     21:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     22:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     23:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     24:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     25:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     26:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     27:  * SUCH DAMAGE.
1.1       deraadt    28:  */
1.19      tedu       29: /*
                     30:  * apprentice - make one pass through /etc/magic, learning its secrets.
                     31:  */
1.1       deraadt    32:
1.19      tedu       33: #include "file.h"
                     34: #include "magic.h"
1.1       deraadt    35: #include <stdlib.h>
1.19      tedu       36: #ifdef HAVE_UNISTD_H
                     37: #include <unistd.h>
                     38: #endif
1.1       deraadt    39: #include <string.h>
1.25    ! chl        40: #include <assert.h>
1.1       deraadt    41: #include <ctype.h>
1.19      tedu       42: #include <fcntl.h>
                     43: #include <sys/stat.h>
                     44: #include <sys/param.h>
                     45: #ifdef QUICK
                     46: #include <sys/mman.h>
                     47: #endif
1.1       deraadt    48:
                     49: #ifndef        lint
1.25    ! chl        50: FILE_RCSID("@(#)$Id: apprentice.c,v 1.24 2007/10/05 14:29:46 chl Exp $")
1.1       deraadt    51: #endif /* lint */
                     52:
                     53: #define        EATAB {while (isascii((unsigned char) *l) && \
                     54:                      isspace((unsigned char) *l))  ++l;}
                     55: #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
                     56:                        tolower((unsigned char) (l)) : (l))
1.19      tedu       57: /*
                     58:  * Work around a bug in headers on Digital Unix.
                     59:  * At least confirmed for: OSF1 V4.0 878
                     60:  */
                     61: #if defined(__osf__) && defined(__DECC)
                     62: #ifdef MAP_FAILED
                     63: #undef MAP_FAILED
                     64: #endif
                     65: #endif
                     66:
                     67: #ifndef MAP_FAILED
                     68: #define MAP_FAILED (void *) -1
                     69: #endif
                     70:
                     71: #ifndef MAP_FILE
                     72: #define MAP_FILE 0
                     73: #endif
                     74:
                     75: #ifndef MAXPATHLEN
                     76: #define MAXPATHLEN     1024
                     77: #endif
                     78:
1.25    ! chl        79: struct magic_entry {
        !            80:        struct magic *mp;
        !            81:        uint32_t cont_count;
        !            82:        uint32_t max_count;
        !            83: };
        !            84:
        !            85: int file_formats[FILE_NAMES_SIZE];
        !            86: const size_t file_nformats = FILE_NAMES_SIZE;
        !            87: const char *file_names[FILE_NAMES_SIZE];
        !            88: const size_t file_nnames = FILE_NAMES_SIZE;
        !            89:
        !            90: private int getvalue(struct magic_set *ms, struct magic *, const char **, int);
1.19      tedu       91: private int hextoint(int);
1.25    ! chl        92: private const char *getstr(struct magic_set *, const char *, char *, int,
        !            93:     int *, int);
        !            94: private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
        !            95:     const char *, size_t, int);
        !            96: private void eatsize(const char **);
1.19      tedu       97: private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
1.25    ! chl        98: private size_t apprentice_magic_strength(const struct magic *);
        !            99: private int apprentice_sort(const void *, const void *);
1.19      tedu      100: private int apprentice_file(struct magic_set *, struct magic **, uint32_t *,
                    101:     const char *, int);
                    102: private void byteswap(struct magic *, uint32_t);
                    103: private void bs1(struct magic *);
                    104: private uint16_t swap2(uint16_t);
                    105: private uint32_t swap4(uint32_t);
1.25    ! chl       106: private uint64_t swap8(uint64_t);
        !           107: private char *mkdbname(const char *, char *, size_t, int);
1.19      tedu      108: private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
                    109:     const char *);
                    110: private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
                    111:     const char *);
1.25    ! chl       112: private int check_format_type(const char *, int);
        !           113: private int check_format(struct magic_set *, struct magic *);
1.19      tedu      114:
                    115: private size_t maxmagic = 0;
                    116: private size_t magicsize = sizeof(struct magic);
                    117:
1.25    ! chl       118:
1.19      tedu      119: #ifdef COMPILE_ONLY
                    120:
                    121: int main(int, char *[]);
                    122:
                    123: int
                    124: main(int argc, char *argv[])
                    125: {
                    126:        int ret;
1.25    ! chl       127:        struct magic_set *ms;
        !           128:        char *progname;
1.19      tedu      129:
                    130:        if ((progname = strrchr(argv[0], '/')) != NULL)
                    131:                progname++;
                    132:        else
                    133:                progname = argv[0];
                    134:
                    135:        if (argc != 2) {
1.25    ! chl       136:                (void)fprintf(stderr, "Usage: %s file\n", progname);
        !           137:                return 1;
1.19      tedu      138:        }
                    139:
1.25    ! chl       140:        if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
        !           141:                (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
        !           142:                return 1;
        !           143:        }
        !           144:        ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
        !           145:        if (ret == 1)
        !           146:                (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
        !           147:        magic_close(ms);
        !           148:        return ret;
1.19      tedu      149: }
                    150: #endif /* COMPILE_ONLY */
                    151:
1.25    ! chl       152: static const struct type_tbl_s {
        !           153:        const char *name;
        !           154:        const size_t len;
        !           155:        const int type;
        !           156:        const int format;
        !           157: } type_tbl[] = {
        !           158: # define XX(s)         s, (sizeof(s) - 1)
        !           159: # define XX_NULL       NULL, 0
        !           160:        { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
        !           161:        { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
        !           162:        { XX("default"),        FILE_DEFAULT,           FILE_FMT_STR },
        !           163:        { XX("long"),           FILE_LONG,              FILE_FMT_NUM },
        !           164:        { XX("string"),         FILE_STRING,            FILE_FMT_STR },
        !           165:        { XX("date"),           FILE_DATE,              FILE_FMT_STR },
        !           166:        { XX("beshort"),        FILE_BESHORT,           FILE_FMT_NUM },
        !           167:        { XX("belong"),         FILE_BELONG,            FILE_FMT_NUM },
        !           168:        { XX("bedate"),         FILE_BEDATE,            FILE_FMT_STR },
        !           169:        { XX("leshort"),        FILE_LESHORT,           FILE_FMT_NUM },
        !           170:        { XX("lelong"),         FILE_LELONG,            FILE_FMT_NUM },
        !           171:        { XX("ledate"),         FILE_LEDATE,            FILE_FMT_STR },
        !           172:        { XX("pstring"),        FILE_PSTRING,           FILE_FMT_STR },
        !           173:        { XX("ldate"),          FILE_LDATE,             FILE_FMT_STR },
        !           174:        { XX("beldate"),        FILE_BELDATE,           FILE_FMT_STR },
        !           175:        { XX("leldate"),        FILE_LELDATE,           FILE_FMT_STR },
        !           176:        { XX("regex"),          FILE_REGEX,             FILE_FMT_STR },
        !           177:        { XX("bestring16"),     FILE_BESTRING16,        FILE_FMT_STR },
        !           178:        { XX("lestring16"),     FILE_LESTRING16,        FILE_FMT_STR },
        !           179:        { XX("search"),         FILE_SEARCH,            FILE_FMT_STR },
        !           180:        { XX("medate"),         FILE_MEDATE,            FILE_FMT_STR },
        !           181:        { XX("meldate"),        FILE_MELDATE,           FILE_FMT_STR },
        !           182:        { XX("melong"),         FILE_MELONG,            FILE_FMT_NUM },
        !           183:        { XX("quad"),           FILE_QUAD,              FILE_FMT_QUAD },
        !           184:        { XX("lequad"),         FILE_LEQUAD,            FILE_FMT_QUAD },
        !           185:        { XX("bequad"),         FILE_BEQUAD,            FILE_FMT_QUAD },
        !           186:        { XX("qdate"),          FILE_QDATE,             FILE_FMT_STR },
        !           187:        { XX("leqdate"),        FILE_LEQDATE,           FILE_FMT_STR },
        !           188:        { XX("beqdate"),        FILE_BEQDATE,           FILE_FMT_STR },
        !           189:        { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
        !           190:        { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
        !           191:        { XX("beqldate"),       FILE_BEQLDATE,          FILE_FMT_STR },
        !           192:        { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
        !           193: # undef XX
        !           194: # undef XX_NULL
        !           195: };
        !           196:
        !           197: private int
        !           198: get_type(const char *l, const char **t)
        !           199: {
        !           200:        const struct type_tbl_s *p;
        !           201:
        !           202:        for (p = type_tbl; p->name; p++) {
        !           203:                if (strncmp(l, p->name, p->len) == 0) {
        !           204:                        if (t)
        !           205:                                *t = l + p->len;
        !           206:                        break;
        !           207:                }
        !           208:        }
        !           209:        return p->type;
        !           210: }
        !           211:
        !           212: private void
        !           213: init_file_tables(void)
        !           214: {
        !           215:        static int done = 0;
        !           216:        const struct type_tbl_s *p;
        !           217:
        !           218:        if (done)
        !           219:                return;
        !           220:        done++;
        !           221:
        !           222:        for (p = type_tbl; p->name; p++) {
        !           223:                assert(p->type < FILE_NAMES_SIZE);
        !           224:                file_names[p->type] = p->name;
        !           225:                file_formats[p->type] = p->format;
        !           226:        }
        !           227: }
1.19      tedu      228:
                    229: /*
                    230:  * Handle one file.
                    231:  */
                    232: private int
                    233: apprentice_1(struct magic_set *ms, const char *fn, int action,
                    234:     struct mlist *mlist)
                    235: {
                    236:        struct magic *magic = NULL;
                    237:        uint32_t nmagic = 0;
                    238:        struct mlist *ml;
                    239:        int rv = -1;
                    240:        int mapped;
                    241:
                    242:        if (magicsize != FILE_MAGICSIZE) {
                    243:                file_error(ms, 0, "magic element size %lu != %lu",
                    244:                    (unsigned long)sizeof(*magic),
                    245:                    (unsigned long)FILE_MAGICSIZE);
                    246:                return -1;
                    247:        }
1.1       deraadt   248:
1.19      tedu      249:        if (action == FILE_COMPILE) {
                    250:                rv = apprentice_file(ms, &magic, &nmagic, fn, action);
                    251:                if (rv != 0)
                    252:                        return -1;
                    253:                rv = apprentice_compile(ms, &magic, &nmagic, fn);
                    254:                free(magic);
                    255:                return rv;
                    256:        }
1.25    ! chl       257:
1.19      tedu      258: #ifndef COMPILE_ONLY
                    259:        if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
                    260:                if (ms->flags & MAGIC_CHECK)
1.25    ! chl       261:                        file_magwarn(ms, "using regular magic file `%s'", fn);
1.19      tedu      262:                rv = apprentice_file(ms, &magic, &nmagic, fn, action);
                    263:                if (rv != 0)
                    264:                        return -1;
                    265:        }
1.1       deraadt   266:
1.19      tedu      267:        mapped = rv;
                    268:
                    269:        if (magic == NULL || nmagic == 0) {
                    270:                file_delmagic(magic, mapped, nmagic);
                    271:                return -1;
                    272:        }
1.1       deraadt   273:
1.19      tedu      274:        if ((ml = malloc(sizeof(*ml))) == NULL) {
                    275:                file_delmagic(magic, mapped, nmagic);
1.25    ! chl       276:                file_oomem(ms, sizeof(*ml));
1.19      tedu      277:                return -1;
                    278:        }
1.1       deraadt   279:
1.19      tedu      280:        ml->magic = magic;
                    281:        ml->nmagic = nmagic;
                    282:        ml->mapped = mapped;
                    283:
                    284:        mlist->prev->next = ml;
                    285:        ml->prev = mlist->prev;
                    286:        ml->next = mlist;
                    287:        mlist->prev = ml;
1.1       deraadt   288:
1.19      tedu      289:        return 0;
                    290: #endif /* COMPILE_ONLY */
                    291: }
                    292:
                    293: protected void
                    294: file_delmagic(struct magic *p, int type, size_t entries)
                    295: {
                    296:        if (p == NULL)
                    297:                return;
                    298:        switch (type) {
1.25    ! chl       299: #ifdef QUICK
1.19      tedu      300:        case 2:
                    301:                p--;
                    302:                (void)munmap((void *)p, sizeof(*p) * (entries + 1));
                    303:                break;
1.25    ! chl       304: #endif
1.19      tedu      305:        case 1:
                    306:                p--;
1.25    ! chl       307:                /*FALLTHROUGH*/
1.19      tedu      308:        case 0:
                    309:                free(p);
                    310:                break;
                    311:        default:
                    312:                abort();
                    313:        }
                    314: }
                    315:
                    316: /* const char *fn: list of magic files */
                    317: protected struct mlist *
                    318: file_apprentice(struct magic_set *ms, const char *fn, int action)
1.2       deraadt   319: {
1.19      tedu      320:        char *p, *mfn, *afn = NULL;
1.2       deraadt   321:        int file_err, errs = -1;
1.19      tedu      322:        struct mlist *mlist;
1.25    ! chl       323:        static const char mime[] = ".mime";
        !           324:
        !           325:        init_file_tables();
1.2       deraadt   326:
1.19      tedu      327:        if (fn == NULL)
                    328:                fn = getenv("MAGIC");
                    329:        if (fn == NULL)
                    330:                fn = MAGIC;
                    331:
1.25    ! chl       332:        if ((mfn = strdup(fn)) == NULL) {
        !           333:                file_oomem(ms, strlen(fn));
1.19      tedu      334:                return NULL;
                    335:        }
1.25    ! chl       336:        fn = mfn;
1.19      tedu      337:
                    338:        if ((mlist = malloc(sizeof(*mlist))) == NULL) {
                    339:                free(mfn);
1.25    ! chl       340:                file_oomem(ms, sizeof(*mlist));
1.19      tedu      341:                return NULL;
1.2       deraadt   342:        }
1.19      tedu      343:        mlist->next = mlist->prev = mlist;
1.17      deraadt   344:
1.2       deraadt   345:        while (fn) {
1.19      tedu      346:                p = strchr(fn, PATHSEP);
1.2       deraadt   347:                if (p)
                    348:                        *p++ = '\0';
1.19      tedu      349:                if (*fn == '\0')
                    350:                        break;
                    351:                if (ms->flags & MAGIC_MIME) {
1.25    ! chl       352:                        size_t len = strlen(fn) + sizeof(mime);
1.19      tedu      353:                        if ((afn = malloc(len)) == NULL) {
                    354:                                free(mfn);
                    355:                                free(mlist);
1.25    ! chl       356:                                file_oomem(ms, len);
1.19      tedu      357:                                return NULL;
                    358:                        }
                    359:                        (void)strlcpy(afn, fn, len);
                    360:                        (void)strlcat(afn, ".mime", len);
                    361:                        fn = afn;
                    362:                }
                    363:                file_err = apprentice_1(ms, fn, action, mlist);
1.2       deraadt   364:                if (file_err > errs)
                    365:                        errs = file_err;
1.19      tedu      366:                if (afn) {
                    367:                        free(afn);
                    368:                        afn = NULL;
                    369:                }
1.2       deraadt   370:                fn = p;
                    371:        }
1.19      tedu      372:        if (errs == -1) {
                    373:                free(mfn);
                    374:                free(mlist);
                    375:                mlist = NULL;
                    376:                file_error(ms, 0, "could not find any magic files!");
                    377:                return NULL;
                    378:        }
1.2       deraadt   379:        free(mfn);
1.19      tedu      380:        return mlist;
1.2       deraadt   381: }
                    382:
1.19      tedu      383: /*
1.25    ! chl       384:  * Get weight of this magic entry, for sorting purposes.
        !           385:  */
        !           386: private size_t
        !           387: apprentice_magic_strength(const struct magic *m)
        !           388: {
        !           389: #define MULT 10
        !           390:        size_t val = 2 * MULT;  /* baseline strength */
        !           391:
        !           392:        switch (m->type) {
        !           393:        case FILE_DEFAULT:      /* make sure this sorts last */
        !           394:                return 0;
        !           395:
        !           396:        case FILE_BYTE:
        !           397:                val += 1 * MULT;
        !           398:                break;
        !           399:
        !           400:        case FILE_SHORT:
        !           401:        case FILE_LESHORT:
        !           402:        case FILE_BESHORT:
        !           403:                val += 2 * MULT;
        !           404:                break;
        !           405:
        !           406:        case FILE_LONG:
        !           407:        case FILE_LELONG:
        !           408:        case FILE_BELONG:
        !           409:        case FILE_MELONG:
        !           410:                val += 4 * MULT;
        !           411:                break;
        !           412:
        !           413:        case FILE_PSTRING:
        !           414:        case FILE_STRING:
        !           415:                val += m->vallen * MULT;
        !           416:                break;
        !           417:
        !           418:        case FILE_BESTRING16:
        !           419:        case FILE_LESTRING16:
        !           420:                val += m->vallen * MULT / 2;
        !           421:                break;
        !           422:
        !           423:        case FILE_SEARCH:
        !           424:        case FILE_REGEX:
        !           425:                val += m->vallen;
        !           426:                break;
        !           427:
        !           428:        case FILE_DATE:
        !           429:        case FILE_LEDATE:
        !           430:        case FILE_BEDATE:
        !           431:        case FILE_MEDATE:
        !           432:        case FILE_LDATE:
        !           433:        case FILE_LELDATE:
        !           434:        case FILE_BELDATE:
        !           435:        case FILE_MELDATE:
        !           436:                val += 4 * MULT;
        !           437:                break;
        !           438:
        !           439:        case FILE_QUAD:
        !           440:        case FILE_BEQUAD:
        !           441:        case FILE_LEQUAD:
        !           442:        case FILE_QDATE:
        !           443:        case FILE_LEQDATE:
        !           444:        case FILE_BEQDATE:
        !           445:        case FILE_QLDATE:
        !           446:        case FILE_LEQLDATE:
        !           447:        case FILE_BEQLDATE:
        !           448:                val += 8 * MULT;
        !           449:                break;
        !           450:
        !           451:        default:
        !           452:                val = 0;
        !           453:                (void)fprintf(stderr, "Bad type %d\n", m->type);
        !           454:                abort();
        !           455:        }
        !           456:
        !           457:        switch (m->reln) {
        !           458:        case 'x':       /* matches anything penalize */
        !           459:                val = 0;
        !           460:                break;
        !           461:
        !           462:        case '!':
        !           463:        case '=':       /* Exact match, prefer */
        !           464:                val += MULT;
        !           465:                break;
        !           466:
        !           467:        case '>':
        !           468:        case '<':       /* comparison match reduce strength */
        !           469:                val -= 2 * MULT;
        !           470:                break;
        !           471:
        !           472:        case '^':
        !           473:        case '&':       /* masking bits, we could count them too */
        !           474:                val -= MULT;
        !           475:                break;
        !           476:
        !           477:        default:
        !           478:                (void)fprintf(stderr, "Bad relation %c\n", m->reln);
        !           479:                abort();
        !           480:        }
        !           481:
        !           482:        if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
        !           483:                val = 1;
        !           484:
        !           485:        return val;
        !           486: }
        !           487:
        !           488: /*
        !           489:  * Sort callback for sorting entries by "strength" (basically length)
        !           490:  */
        !           491: private int
        !           492: apprentice_sort(const void *a, const void *b)
        !           493: {
        !           494:        const struct magic_entry *ma = a;
        !           495:        const struct magic_entry *mb = b;
        !           496:        size_t sa = apprentice_magic_strength(ma->mp);
        !           497:        size_t sb = apprentice_magic_strength(mb->mp);
        !           498:        if (sa == sb)
        !           499:                return 0;
        !           500:        else if (sa > sb)
        !           501:                return -1;
        !           502:        else
        !           503:                return 1;
        !           504: }
        !           505:
        !           506: /*
1.19      tedu      507:  * parse from a file
                    508:  * const char *fn: name of magic file
                    509:  */
                    510: private int
                    511: apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
                    512:     const char *fn, int action)
1.1       deraadt   513: {
1.19      tedu      514:        private const char hdr[] =
1.2       deraadt   515:                "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
1.1       deraadt   516:        FILE *f;
1.20      otto      517:        char line[BUFSIZ];
1.1       deraadt   518:        int errs = 0;
1.25    ! chl       519:        struct magic_entry *marray;
        !           520:        uint32_t marraycount, i, mentrycount = 0;
        !           521:        size_t lineno = 0;
1.1       deraadt   522:
1.25    ! chl       523:        ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
        !           524:
        !           525:        f = fopen(ms->file = fn, "r");
1.19      tedu      526:        if (f == NULL) {
1.2       deraadt   527:                if (errno != ENOENT)
1.19      tedu      528:                        file_error(ms, errno, "cannot read magic file `%s'",
                    529:                            fn);
1.2       deraadt   530:                return -1;
1.1       deraadt   531:        }
                    532:
1.19      tedu      533:         maxmagic = MAXMAGIS;
1.25    ! chl       534:        if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
1.19      tedu      535:                (void)fclose(f);
1.25    ! chl       536:                file_oomem(ms, maxmagic * sizeof(*marray));
1.19      tedu      537:                return -1;
                    538:        }
1.25    ! chl       539:        marraycount = 0;
1.19      tedu      540:
                    541:        /* print silly verbose header for USG compat. */
                    542:        if (action == FILE_CHECK)
                    543:                (void)fprintf(stderr, "%s\n", hdr);
                    544:
1.25    ! chl       545:        /* read and parse this file */
        !           546:        for (ms->line = 1; fgets(line, sizeof(line), f) != NULL; ms->line++) {
        !           547:                size_t len;
        !           548:                len = strlen(line);
        !           549:                if (len == 0) /* null line, garbage, etc */
        !           550:                        continue;
        !           551:                if (line[len - 1] == '\n') {
        !           552:                        lineno++;
        !           553:                        line[len - 1] = '\0'; /* delete newline */
        !           554:                }
        !           555:                if (line[0] == '\0')    /* empty, do not parse */
1.1       deraadt   556:                        continue;
1.25    ! chl       557:                if (line[0] == '#')     /* comment, do not parse */
1.1       deraadt   558:                        continue;
1.25    ! chl       559:                if (parse(ms, &marray, &marraycount, line, lineno, action) != 0)
        !           560:                        errs++;
1.1       deraadt   561:        }
                    562:
1.19      tedu      563:        (void)fclose(f);
1.25    ! chl       564:        if (errs)
        !           565:                goto out;
        !           566:
        !           567: #ifndef NOORDER
        !           568:        qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
        !           569:        /*
        !           570:         * Make sure that any level 0 "default" line is last (if one exists).
        !           571:         */
        !           572:        for (i = 0; i < marraycount; i++) {
        !           573:                if (marray[i].mp->cont_level == 0 &&
        !           574:                    marray[i].mp->type == FILE_DEFAULT) {
        !           575:                        while (++i < marraycount)
        !           576:                                if (marray[i].mp->cont_level == 0)
        !           577:                                        break;
        !           578:                        if (i != marraycount) {
        !           579:                                ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
        !           580:                                file_magwarn(ms,
        !           581:                                    "level 0 \"default\" did not sort last");
        !           582:                        }
        !           583:                        break;
        !           584:                }
        !           585:        }
        !           586: #endif
        !           587:
        !           588:        for (i = 0; i < marraycount; i++)
        !           589:                mentrycount += marray[i].cont_count;
        !           590:
        !           591:        if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) {
        !           592:                file_oomem(ms, sizeof(**magicp) * mentrycount);
        !           593:                errs++;
        !           594:                goto out;
        !           595:        }
        !           596:
        !           597:        mentrycount = 0;
        !           598:        for (i = 0; i < marraycount; i++) {
        !           599:                (void)memcpy(*magicp + mentrycount, marray[i].mp,
        !           600:                    marray[i].cont_count * sizeof(**magicp));
        !           601:                mentrycount += marray[i].cont_count;
        !           602:        }
        !           603: out:
        !           604:        for (i = 0; i < marraycount; i++)
        !           605:                free(marray[i].mp);
        !           606:        free(marray);
1.19      tedu      607:        if (errs) {
                    608:                *magicp = NULL;
                    609:                *nmagicp = 0;
1.25    ! chl       610:                return errs;
        !           611:        } else {
        !           612:                *nmagicp = mentrycount;
        !           613:                return 0;
1.19      tedu      614:        }
1.25    ! chl       615:
1.1       deraadt   616: }
                    617:
                    618: /*
                    619:  * extend the sign bit if the comparison is to be signed
                    620:  */
1.25    ! chl       621: protected uint64_t
        !           622: file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
1.1       deraadt   623: {
1.25    ! chl       624:        if (!(m->flag & UNSIGNED)) {
1.1       deraadt   625:                switch(m->type) {
                    626:                /*
                    627:                 * Do not remove the casts below.  They are
                    628:                 * vital.  When later compared with the data,
                    629:                 * the sign extension must have happened.
                    630:                 */
1.19      tedu      631:                case FILE_BYTE:
1.1       deraadt   632:                        v = (char) v;
                    633:                        break;
1.19      tedu      634:                case FILE_SHORT:
                    635:                case FILE_BESHORT:
                    636:                case FILE_LESHORT:
1.1       deraadt   637:                        v = (short) v;
                    638:                        break;
1.19      tedu      639:                case FILE_DATE:
                    640:                case FILE_BEDATE:
                    641:                case FILE_LEDATE:
1.25    ! chl       642:                case FILE_MEDATE:
1.19      tedu      643:                case FILE_LDATE:
                    644:                case FILE_BELDATE:
                    645:                case FILE_LELDATE:
1.25    ! chl       646:                case FILE_MELDATE:
1.19      tedu      647:                case FILE_LONG:
                    648:                case FILE_BELONG:
                    649:                case FILE_LELONG:
1.25    ! chl       650:                case FILE_MELONG:
1.14      itojun    651:                        v = (int32_t) v;
1.1       deraadt   652:                        break;
1.25    ! chl       653:                case FILE_QUAD:
        !           654:                case FILE_BEQUAD:
        !           655:                case FILE_LEQUAD:
        !           656:                case FILE_QDATE:
        !           657:                case FILE_QLDATE:
        !           658:                case FILE_BEQDATE:
        !           659:                case FILE_BEQLDATE:
        !           660:                case FILE_LEQDATE:
        !           661:                case FILE_LEQLDATE:
        !           662:                        v = (int64_t) v;
        !           663:                        break;
1.19      tedu      664:                case FILE_STRING:
                    665:                case FILE_PSTRING:
1.25    ! chl       666:                case FILE_BESTRING16:
        !           667:                case FILE_LESTRING16:
1.19      tedu      668:                case FILE_REGEX:
1.25    ! chl       669:                case FILE_SEARCH:
        !           670:                case FILE_DEFAULT:
1.1       deraadt   671:                        break;
                    672:                default:
1.19      tedu      673:                        if (ms->flags & MAGIC_CHECK)
1.25    ! chl       674:                            file_magwarn(ms, "cannot happen: m->type=%d\n",
1.19      tedu      675:                                    m->type);
                    676:                        return ~0U;
1.1       deraadt   677:                }
1.25    ! chl       678:        }
1.1       deraadt   679:        return v;
                    680: }
                    681:
1.25    ! chl       682: private int
        !           683: string_modifier_check(struct magic_set *ms, struct magic const *m)
        !           684: {
        !           685:        if ((ms->flags & MAGIC_CHECK) == 0)
        !           686:                return 0;
        !           687:
        !           688:        switch (m->type) {
        !           689:        case FILE_BESTRING16:
        !           690:        case FILE_LESTRING16:
        !           691:                if (m->str_flags != 0) {
        !           692:                        file_magwarn(ms, "no modifiers allowed for 16-bit strings\n");
        !           693:                        return -1;
        !           694:                }
        !           695:                break;
        !           696:        case FILE_STRING:
        !           697:        case FILE_PSTRING:
        !           698:                if ((m->str_flags & REGEX_OFFSET_START) != 0) {
        !           699:                        file_magwarn(ms, "'/%c' only allowed on regex and search\n",
        !           700:                            CHAR_REGEX_OFFSET_START);
        !           701:                        return -1;
        !           702:                }
        !           703:                break;
        !           704:        case FILE_SEARCH:
        !           705:                break;
        !           706:        case FILE_REGEX:
        !           707:                if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
        !           708:                        file_magwarn(ms, "'/%c' not allowed on regex\n",
        !           709:                            CHAR_COMPACT_BLANK);
        !           710:                        return -1;
        !           711:                }
        !           712:                if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
        !           713:                        file_magwarn(ms, "'/%c' not allowed on regex\n",
        !           714:                            CHAR_COMPACT_OPTIONAL_BLANK);
        !           715:                        return -1;
        !           716:                }
        !           717:                break;
        !           718:        default:
        !           719:                file_magwarn(ms, "coding error: m->type=%d\n",
        !           720:                    m->type);
        !           721:                return -1;
        !           722:        }
        !           723:        return 0;
        !           724: }
        !           725:
        !           726: private int
        !           727: get_op(char c)
        !           728: {
        !           729:        switch (c) {
        !           730:        case '&':
        !           731:                return FILE_OPAND;
        !           732:        case '|':
        !           733:                return FILE_OPOR;
        !           734:        case '^':
        !           735:                return FILE_OPXOR;
        !           736:        case '+':
        !           737:                return FILE_OPADD;
        !           738:        case '-':
        !           739:                return FILE_OPMINUS;
        !           740:        case '*':
        !           741:                return FILE_OPMULTIPLY;
        !           742:        case '/':
        !           743:                return FILE_OPDIVIDE;
        !           744:        case '%':
        !           745:                return FILE_OPMODULO;
        !           746:        default:
        !           747:                return -1;
        !           748:        }
        !           749: }
        !           750:
        !           751: #ifdef ENABLE_CONDITIONALS
        !           752: private int
        !           753: get_cond(const char *l, const char **t)
        !           754: {
        !           755:        static struct cond_tbl_s {
        !           756:                const char *name;
        !           757:                const size_t len;
        !           758:                const int cond;
        !           759:        } cond_tbl[] = {
        !           760:                { "if",         2,      COND_IF },
        !           761:                { "elif",       4,      COND_ELIF },
        !           762:                { "else",       4,      COND_ELSE },
        !           763:                { NULL,         0,      COND_NONE },
        !           764:        };
        !           765:        struct cond_tbl_s *p;
        !           766:
        !           767:        for (p = cond_tbl; p->name; p++) {
        !           768:                if (strncmp(l, p->name, p->len) == 0 &&
        !           769:                    isspace((unsigned char)l[p->len])) {
        !           770:                        if (t)
        !           771:                                *t = l + p->len;
        !           772:                        break;
        !           773:                }
        !           774:        }
        !           775:        return p->cond;
        !           776: }
        !           777:
        !           778: private int
        !           779: check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
        !           780: {
        !           781:        int last_cond;
        !           782:        last_cond = ms->c.li[cont_level].last_cond;
        !           783:
        !           784:        switch (cond) {
        !           785:        case COND_IF:
        !           786:                if (last_cond != COND_NONE && last_cond != COND_ELIF) {
        !           787:                        if (ms->flags & MAGIC_CHECK)
        !           788:                                file_magwarn(ms, "syntax error: `if'");
        !           789:                        return -1;
        !           790:                }
        !           791:                last_cond = COND_IF;
        !           792:                break;
        !           793:
        !           794:        case COND_ELIF:
        !           795:                if (last_cond != COND_IF && last_cond != COND_ELIF) {
        !           796:                        if (ms->flags & MAGIC_CHECK)
        !           797:                                file_magwarn(ms, "syntax error: `elif'");
        !           798:                        return -1;
        !           799:                }
        !           800:                last_cond = COND_ELIF;
        !           801:                break;
        !           802:
        !           803:        case COND_ELSE:
        !           804:                if (last_cond != COND_IF && last_cond != COND_ELIF) {
        !           805:                        if (ms->flags & MAGIC_CHECK)
        !           806:                                file_magwarn(ms, "syntax error: `else'");
        !           807:                        return -1;
        !           808:                }
        !           809:                last_cond = COND_NONE;
        !           810:                break;
        !           811:
        !           812:        case COND_NONE:
        !           813:                last_cond = COND_NONE;
        !           814:                break;
        !           815:        }
        !           816:
        !           817:        ms->c.li[cont_level].last_cond = last_cond;
        !           818:        return 0;
        !           819: }
        !           820: #endif /* ENABLE_CONDITIONALS */
        !           821:
1.1       deraadt   822: /*
                    823:  * parse one line from magic file, put into magic[index++] if valid
                    824:  */
1.19      tedu      825: private int
1.25    ! chl       826: parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp,
        !           827:     const char *line, size_t lineno, int action)
1.1       deraadt   828: {
1.25    ! chl       829: #ifdef ENABLE_CONDITIONALS
        !           830:        static uint32_t last_cont_level = 0;
        !           831: #endif
        !           832:        size_t i;
        !           833:        struct magic_entry *me;
1.1       deraadt   834:        struct magic *m;
1.25    ! chl       835:        const char *l = line;
1.19      tedu      836:        char *t;
1.25    ! chl       837:        int op;
        !           838:        uint32_t cont_level;
1.19      tedu      839:
1.25    ! chl       840:        cont_level = 0;
1.1       deraadt   841:
                    842:        while (*l == '>') {
                    843:                ++l;            /* step over */
1.25    ! chl       844:                cont_level++;
1.1       deraadt   845:        }
1.25    ! chl       846: #ifdef ENABLE_CONDITIONALS
        !           847:        if (cont_level == 0 || cont_level > last_cont_level)
        !           848:                if (file_check_mem(ms, cont_level) == -1)
        !           849:                        return -1;
        !           850:        last_cont_level = cont_level;
        !           851: #endif
        !           852:
        !           853: #define ALLOC_CHUNK    (size_t)10
        !           854: #define ALLOC_INCR     (size_t)200
1.1       deraadt   855:
1.25    ! chl       856:        if (cont_level != 0) {
        !           857:                if (*nmentryp == 0) {
        !           858:                        file_error(ms, 0, "No current entry for continuation");
        !           859:                        return -1;
        !           860:                }
        !           861:                me = &(*mentryp)[*nmentryp - 1];
        !           862:                if (me->cont_count == me->max_count) {
        !           863:                        struct magic *nm;
        !           864:                        size_t cnt = me->max_count + ALLOC_CHUNK;
        !           865:                        if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) {
        !           866:                                file_oomem(ms, sizeof(*nm) * cnt);
        !           867:                                return -1;
        !           868:                        }
        !           869:                        me->mp = m = nm;
        !           870:                        me->max_count = cnt;
        !           871:                }
        !           872:                m = &me->mp[me->cont_count++];
        !           873:                (void)memset(m, 0, sizeof(*m));
        !           874:                m->cont_level = cont_level;
        !           875:        } else {
        !           876:                if (*nmentryp == maxmagic) {
        !           877:                        struct magic_entry *mp;
        !           878:
        !           879:                        maxmagic += ALLOC_INCR;
        !           880:                        if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) ==
        !           881:                            NULL) {
        !           882:                                file_oomem(ms, sizeof(*mp) * maxmagic);
        !           883:                                return -1;
        !           884:                        }
        !           885:                        (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
        !           886:                            ALLOC_INCR);
        !           887:                        *mentryp = mp;
        !           888:                }
        !           889:                me = &(*mentryp)[*nmentryp];
        !           890:                if (me->mp == NULL) {
        !           891:                        if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) {
        !           892:                                file_oomem(ms, sizeof(*m) * ALLOC_CHUNK);
        !           893:                                return -1;
        !           894:                        }
        !           895:                        me->mp = m;
        !           896:                        me->max_count = ALLOC_CHUNK;
        !           897:                } else
        !           898:                        m = me->mp;
        !           899:                (void)memset(m, 0, sizeof(*m));
        !           900:                m->cont_level = 0;
        !           901:                me->cont_count = 1;
1.1       deraadt   902:        }
1.25    ! chl       903:        m->lineno = lineno;
        !           904:
        !           905:        if (*l == '&') {  /* m->cont_level == 0 checked below. */
1.4       millert   906:                 ++l;            /* step over */
1.19      tedu      907:                 m->flag |= OFFADD;
1.4       millert   908:         }
1.25    ! chl       909:        if (*l == '(') {
        !           910:                ++l;            /* step over */
        !           911:                m->flag |= INDIR;
        !           912:                if (m->flag & OFFADD)
        !           913:                        m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
        !           914:
        !           915:                if (*l == '&') {  /* m->cont_level == 0 checked below */
        !           916:                        ++l;            /* step over */
        !           917:                        m->flag |= OFFADD;
        !           918:                }
        !           919:        }
        !           920:        /* Indirect offsets are not valid at level 0. */
        !           921:        if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
        !           922:                if (ms->flags & MAGIC_CHECK)
        !           923:                        file_magwarn(ms, "relative offset at level 0");
1.1       deraadt   924:
                    925:        /* get offset, then skip over it */
1.19      tedu      926:        m->offset = (uint32_t)strtoul(l, &t, 0);
1.1       deraadt   927:         if (l == t)
1.19      tedu      928:                if (ms->flags & MAGIC_CHECK)
1.25    ! chl       929:                        file_magwarn(ms, "offset `%s' invalid", l);
1.1       deraadt   930:         l = t;
                    931:
                    932:        if (m->flag & INDIR) {
1.19      tedu      933:                m->in_type = FILE_LONG;
                    934:                m->in_offset = 0;
1.1       deraadt   935:                /*
                    936:                 * read [.lbs][+-]nnnnn)
                    937:                 */
                    938:                if (*l == '.') {
                    939:                        l++;
1.19      tedu      940:                        switch (*l) {
1.1       deraadt   941:                        case 'l':
1.19      tedu      942:                                m->in_type = FILE_LELONG;
                    943:                                break;
                    944:                        case 'L':
                    945:                                m->in_type = FILE_BELONG;
1.1       deraadt   946:                                break;
1.25    ! chl       947:                        case 'm':
        !           948:                                m->in_type = FILE_MELONG;
        !           949:                                break;
1.1       deraadt   950:                        case 'h':
                    951:                        case 's':
1.19      tedu      952:                                m->in_type = FILE_LESHORT;
                    953:                                break;
                    954:                        case 'H':
                    955:                        case 'S':
                    956:                                m->in_type = FILE_BESHORT;
1.1       deraadt   957:                                break;
                    958:                        case 'c':
                    959:                        case 'b':
1.19      tedu      960:                        case 'C':
                    961:                        case 'B':
                    962:                                m->in_type = FILE_BYTE;
1.1       deraadt   963:                                break;
                    964:                        default:
1.19      tedu      965:                                if (ms->flags & MAGIC_CHECK)
1.25    ! chl       966:                                        file_magwarn(ms,
        !           967:                                            "indirect offset type `%c' invalid",
1.19      tedu      968:                                            *l);
1.1       deraadt   969:                                break;
                    970:                        }
                    971:                        l++;
                    972:                }
1.25    ! chl       973:
        !           974:                m->in_op = 0;
1.19      tedu      975:                if (*l == '~') {
1.25    ! chl       976:                        m->in_op |= FILE_OPINVERSE;
1.19      tedu      977:                        l++;
                    978:                }
1.25    ! chl       979:                if ((op = get_op(*l)) != -1) {
        !           980:                        m->in_op |= op;
1.19      tedu      981:                        l++;
1.25    ! chl       982:                }
        !           983:                if (*l == '(') {
        !           984:                        m->in_op |= FILE_OPINDIRECT;
1.19      tedu      985:                        l++;
1.1       deraadt   986:                }
1.25    ! chl       987:                if (isdigit((unsigned char)*l) || *l == '-') {
        !           988:                        m->in_offset = (int32_t)strtol(l, &t, 0);
        !           989:                        if (l == t)
        !           990:                                if (ms->flags & MAGIC_CHECK)
        !           991:                                        file_magwarn(ms,
        !           992:                                            "in_offset `%s' invalid", l);
        !           993:                        l = t;
        !           994:                }
        !           995:                if (*l++ != ')' ||
        !           996:                    ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
1.19      tedu      997:                        if (ms->flags & MAGIC_CHECK)
1.25    ! chl       998:                                file_magwarn(ms,
        !           999:                                    "missing ')' in indirect offset");
1.1       deraadt  1000:        }
1.25    ! chl      1001:        EATAB;
1.1       deraadt  1002:
1.25    ! chl      1003: #ifdef ENABLE_CONDITIONALS
        !          1004:        m->cond = get_cond(l, &l);
        !          1005:        if (check_cond(ms, m->cond, cont_level) == -1)
        !          1006:                return -1;
1.1       deraadt  1007:
                   1008:        EATAB;
1.25    ! chl      1009: #endif
1.1       deraadt  1010:
                   1011:        if (*l == 'u') {
                   1012:                ++l;
                   1013:                m->flag |= UNSIGNED;
                   1014:        }
                   1015:
1.25    ! chl      1016:        m->type = get_type(l, &l);
        !          1017:        if (m->type == FILE_INVALID) {
1.19      tedu     1018:                if (ms->flags & MAGIC_CHECK)
1.25    ! chl      1019:                        file_magwarn(ms, "type `%s' invalid", l);
1.1       deraadt  1020:                return -1;
                   1021:        }
1.25    ! chl      1022:
1.1       deraadt  1023:        /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
1.19      tedu     1024:        /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
1.25    ! chl      1025:
        !          1026:        m->mask_op = 0;
1.19      tedu     1027:        if (*l == '~') {
1.25    ! chl      1028:                if (!IS_STRING(m->type))
        !          1029:                        m->mask_op |= FILE_OPINVERSE;
        !          1030:                else if (ms->flags & MAGIC_CHECK)
        !          1031:                        file_magwarn(ms, "'~' invalid for string types");
1.1       deraadt  1032:                ++l;
1.19      tedu     1033:        }
1.25    ! chl      1034:        m->str_count = 0;
        !          1035:        m->str_flags = 0;
        !          1036:        m->num_mask = 0;
        !          1037:        if ((op = get_op(*l)) != -1) {
        !          1038:                if (!IS_STRING(m->type)) {
        !          1039:                        uint64_t val;
1.19      tedu     1040:                        ++l;
                   1041:                        m->mask_op |= op;
1.25    ! chl      1042:                        val = (uint64_t)strtoull(l, &t, 0);
        !          1043:                        l = t;
        !          1044:                        m->num_mask = file_signextend(ms, m, val);
1.19      tedu     1045:                        eatsize(&l);
1.25    ! chl      1046:                }
        !          1047:                else if (op == FILE_OPDIVIDE) {
        !          1048:                        int have_count = 0;
1.19      tedu     1049:                        while (!isspace((unsigned char)*++l)) {
                   1050:                                switch (*l) {
1.25    ! chl      1051:                                /* for portability avoid "case '0' ... '9':" */
        !          1052:                                case '0':  case '1':  case '2':
        !          1053:                                case '3':  case '4':  case '5':
        !          1054:                                case '6':  case '7':  case '8':
        !          1055:                                case '9': {
        !          1056:                                        if (have_count && ms->flags & MAGIC_CHECK)
        !          1057:                                                file_magwarn(ms,
        !          1058:                                                    "multiple counts");
        !          1059:                                        have_count = 1;
        !          1060:                                        m->str_count = strtoul(l, &t, 0);
        !          1061:                                        l = t - 1;
1.19      tedu     1062:                                        break;
1.25    ! chl      1063:                                }
1.19      tedu     1064:                                case CHAR_COMPACT_BLANK:
1.25    ! chl      1065:                                        m->str_flags |= STRING_COMPACT_BLANK;
1.19      tedu     1066:                                        break;
                   1067:                                case CHAR_COMPACT_OPTIONAL_BLANK:
1.25    ! chl      1068:                                        m->str_flags |=
1.19      tedu     1069:                                            STRING_COMPACT_OPTIONAL_BLANK;
                   1070:                                        break;
1.25    ! chl      1071:                                case CHAR_IGNORE_LOWERCASE:
        !          1072:                                        m->str_flags |= STRING_IGNORE_LOWERCASE;
        !          1073:                                        break;
        !          1074:                                case CHAR_IGNORE_UPPERCASE:
        !          1075:                                        m->str_flags |= STRING_IGNORE_UPPERCASE;
        !          1076:                                        break;
        !          1077:                                case CHAR_REGEX_OFFSET_START:
        !          1078:                                        m->str_flags |= REGEX_OFFSET_START;
        !          1079:                                        break;
1.19      tedu     1080:                                default:
                   1081:                                        if (ms->flags & MAGIC_CHECK)
1.25    ! chl      1082:                                                file_magwarn(ms,
        !          1083:                                                "string extension `%c' invalid",
1.19      tedu     1084:                                                *l);
                   1085:                                        return -1;
                   1086:                                }
1.25    ! chl      1087:                                /* allow multiple '/' for readability */
        !          1088:                                if (l[1] == '/' && !isspace((unsigned char)l[2]))
        !          1089:                                        l++;
1.19      tedu     1090:                        }
1.25    ! chl      1091:                        if (string_modifier_check(ms, m) == -1)
        !          1092:                                return -1;
        !          1093:                }
        !          1094:                else {
        !          1095:                        if (ms->flags & MAGIC_CHECK)
        !          1096:                                file_magwarn(ms, "invalid string op: %c", *t);
        !          1097:                        return -1;
1.19      tedu     1098:                }
                   1099:        }
                   1100:        /*
                   1101:         * We used to set mask to all 1's here, instead let's just not do
                   1102:         * anything if mask = 0 (unless you have a better idea)
                   1103:         */
1.1       deraadt  1104:        EATAB;
                   1105:
                   1106:        switch (*l) {
                   1107:        case '>':
                   1108:        case '<':
                   1109:        /* Old-style anding: "0 byte &0x80 dynamically linked" */
                   1110:        case '&':
                   1111:        case '^':
                   1112:        case '=':
                   1113:                m->reln = *l;
                   1114:                ++l;
1.19      tedu     1115:                if (*l == '=') {
                   1116:                   /* HP compat: ignore &= etc. */
                   1117:                   ++l;
                   1118:                }
1.1       deraadt  1119:                break;
                   1120:        case '!':
1.25    ! chl      1121:                m->reln = *l;
        !          1122:                ++l;
        !          1123:                break;
1.1       deraadt  1124:        default:
1.25    ! chl      1125:                m->reln = '=';  /* the default relation */
        !          1126:                if (*l == 'x' && ((isascii((unsigned char)l[1]) &&
        !          1127:                    isspace((unsigned char)l[1])) || !l[1])) {
1.1       deraadt  1128:                        m->reln = *l;
                   1129:                        ++l;
                   1130:                }
                   1131:                break;
                   1132:        }
1.25    ! chl      1133:        /*
        !          1134:         * Grab the value part, except for an 'x' reln.
        !          1135:         */
        !          1136:        if (m->reln != 'x' && getvalue(ms, m, &l, action))
1.1       deraadt  1137:                return -1;
1.25    ! chl      1138:
1.1       deraadt  1139:        /*
                   1140:         * TODO finish this macro and start using it!
                   1141:         * #define offsetcheck {if (offset > HOWMANY-1)
1.19      tedu     1142:         *      magwarn("offset too big"); }
1.1       deraadt  1143:         */
                   1144:
                   1145:        /*
1.25    ! chl      1146:         * Now get last part - the description
1.1       deraadt  1147:         */
                   1148:        EATAB;
                   1149:        if (l[0] == '\b') {
                   1150:                ++l;
                   1151:                m->nospflag = 1;
                   1152:        } else if ((l[0] == '\\') && (l[1] == 'b')) {
                   1153:                ++l;
                   1154:                ++l;
                   1155:                m->nospflag = 1;
                   1156:        } else
                   1157:                m->nospflag = 0;
1.25    ! chl      1158:        for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
        !          1159:                continue;
        !          1160:        if (i == sizeof(m->desc)) {
        !          1161:                m->desc[sizeof(m->desc) - 1] = '\0';
        !          1162:                if (ms->flags & MAGIC_CHECK)
        !          1163:                        file_magwarn(ms, "description `%s' truncated", m->desc);
        !          1164:        }
1.21      pedro    1165:
1.25    ! chl      1166:         /*
        !          1167:         * We only do this check while compiling, or if any of the magic
        !          1168:         * files were not compiled.
        !          1169:          */
        !          1170:         if (ms->flags & MAGIC_CHECK) {
        !          1171:                if (check_format(ms, m) == -1)
        !          1172:                        return -1;
        !          1173:        }
1.19      tedu     1174: #ifndef COMPILE_ONLY
                   1175:        if (action == FILE_CHECK) {
                   1176:                file_mdump(m);
1.1       deraadt  1177:        }
1.19      tedu     1178: #endif
1.25    ! chl      1179:        if (m->cont_level == 0)
        !          1180:                ++(*nmentryp);          /* make room for next */
        !          1181:        return 0;
        !          1182: }
        !          1183:
        !          1184: private int
        !          1185: check_format_type(const char *ptr, int type)
        !          1186: {
        !          1187:        int quad = 0;
        !          1188:        if (*ptr == '\0') {
        !          1189:                /* Missing format string; bad */
        !          1190:                return -1;
        !          1191:        }
        !          1192:
        !          1193:        switch (type) {
        !          1194:        case FILE_FMT_QUAD:
        !          1195:                quad = 1;
        !          1196:                /*FALLTHROUGH*/
        !          1197:        case FILE_FMT_NUM:
        !          1198:                if (*ptr == '-')
        !          1199:                        ptr++;
        !          1200:                if (*ptr == '.')
        !          1201:                        ptr++;
        !          1202:                while (isdigit((unsigned char)*ptr)) ptr++;
        !          1203:                if (*ptr == '.')
        !          1204:                        ptr++;
        !          1205:                while (isdigit((unsigned char)*ptr)) ptr++;
        !          1206:                if (quad) {
        !          1207:                        if (*ptr++ != 'l')
        !          1208:                                return -1;
        !          1209:                        if (*ptr++ != 'l')
        !          1210:                                return -1;
        !          1211:                }
        !          1212:
        !          1213:                switch (*ptr++) {
        !          1214:                case 'l':
        !          1215:                        switch (*ptr++) {
        !          1216:                        case 'i':
        !          1217:                        case 'd':
        !          1218:                        case 'u':
        !          1219:                        case 'x':
        !          1220:                        case 'X':
        !          1221:                                return 0;
        !          1222:                        default:
        !          1223:                                return -1;
        !          1224:                        }
        !          1225:
        !          1226:                case 'h':
        !          1227:                        switch (*ptr++) {
        !          1228:                        case 'h':
        !          1229:                                switch (*ptr++) {
        !          1230:                                case 'i':
        !          1231:                                case 'd':
        !          1232:                                case 'u':
        !          1233:                                case 'x':
        !          1234:                                case 'X':
        !          1235:                                        return 0;
        !          1236:                                default:
        !          1237:                                        return -1;
        !          1238:                                }
        !          1239:                        case 'd':
        !          1240:                                return 0;
        !          1241:                        default:
        !          1242:                                return -1;
        !          1243:                        }
        !          1244:
        !          1245:                case 'i':
        !          1246:                case 'c':
        !          1247:                case 'd':
        !          1248:                case 'u':
        !          1249:                case 'x':
        !          1250:                case 'X':
        !          1251:                        return 0;
        !          1252:
        !          1253:                default:
        !          1254:                        return -1;
        !          1255:                }
        !          1256:
        !          1257:        case FILE_FMT_STR:
        !          1258:                if (*ptr == '-')
        !          1259:                        ptr++;
        !          1260:                while (isdigit((unsigned char )*ptr))
        !          1261:                        ptr++;
        !          1262:                if (*ptr == '.') {
        !          1263:                        ptr++;
        !          1264:                        while (isdigit((unsigned char )*ptr))
        !          1265:                                ptr++;
        !          1266:                }
        !          1267:
        !          1268:                switch (*ptr++) {
        !          1269:                case 's':
        !          1270:                        return 0;
        !          1271:                default:
        !          1272:                        return -1;
        !          1273:                }
        !          1274:
        !          1275:        default:
        !          1276:                /* internal error */
        !          1277:                abort();
        !          1278:        }
        !          1279:        /*NOTREACHED*/
        !          1280:        return -1;
        !          1281: }
        !          1282:
        !          1283: /*
        !          1284:  * Check that the optional printf format in description matches
        !          1285:  * the type of the magic.
        !          1286:  */
        !          1287: private int
        !          1288: check_format(struct magic_set *ms, struct magic *m)
        !          1289: {
        !          1290:        char *ptr;
        !          1291:
        !          1292:        for (ptr = m->desc; *ptr; ptr++)
        !          1293:                if (*ptr == '%')
        !          1294:                        break;
        !          1295:        if (*ptr == '\0') {
        !          1296:                /* No format string; ok */
        !          1297:                return 1;
        !          1298:        }
        !          1299:
        !          1300:        assert(file_nformats == file_nnames);
        !          1301:
        !          1302:        if (m->type >= file_nformats) {
        !          1303:                file_error(ms, 0, "Internal error inconsistency between "
        !          1304:                    "m->type and format strings");
        !          1305:                return -1;
        !          1306:        }
        !          1307:        if (file_formats[m->type] == FILE_FMT_NONE) {
        !          1308:                file_error(ms, 0, "No format string for `%s' with description "
        !          1309:                    "`%s'", m->desc, file_names[m->type]);
        !          1310:                return -1;
        !          1311:        }
        !          1312:
        !          1313:        ptr++;
        !          1314:        if (check_format_type(ptr, file_formats[m->type]) == -1) {
        !          1315:                /*
        !          1316:                 * TODO: this error message is unhelpful if the format
        !          1317:                 * string is not one character long
        !          1318:                 */
        !          1319:                file_error(ms, 0, "Printf format `%c' is not valid for type "
        !          1320:                    " `%s' in description `%s'",
        !          1321:                    ptr && *ptr ? *ptr : '?',
        !          1322:                    file_names[m->type], m->desc);
        !          1323:                return -1;
        !          1324:        }
        !          1325:
        !          1326:        for (; *ptr; ptr++) {
        !          1327:                if (*ptr == '%') {
        !          1328:                        file_error(ms, 0,
        !          1329:                            "Too many format strings (should have at most one) "
        !          1330:                            "for `%s' with description `%s'",
        !          1331:                            file_names[m->type], m->desc);
        !          1332:                        return -1;
        !          1333:                }
        !          1334:        }
1.1       deraadt  1335:        return 0;
                   1336: }
                   1337:
                   1338: /*
                   1339:  * Read a numeric value from a pointer, into the value union of a magic
                   1340:  * pointer, according to the magic type.  Update the string pointer to point
                   1341:  * just after the number read.  Return 0 for success, non-zero for failure.
                   1342:  */
1.19      tedu     1343: private int
1.25    ! chl      1344: getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
1.1       deraadt  1345: {
                   1346:        int slen;
                   1347:
1.19      tedu     1348:        switch (m->type) {
1.25    ! chl      1349:        case FILE_BESTRING16:
        !          1350:        case FILE_LESTRING16:
1.19      tedu     1351:        case FILE_STRING:
                   1352:        case FILE_PSTRING:
                   1353:        case FILE_REGEX:
1.25    ! chl      1354:        case FILE_SEARCH:
        !          1355:                *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen, action);
1.19      tedu     1356:                if (*p == NULL) {
                   1357:                        if (ms->flags & MAGIC_CHECK)
1.25    ! chl      1358:                                file_magwarn(ms, "cannot get string from `%s'",
1.19      tedu     1359:                                    m->value.s);
                   1360:                        return -1;
                   1361:                }
1.1       deraadt  1362:                m->vallen = slen;
1.19      tedu     1363:                return 0;
                   1364:        default:
1.1       deraadt  1365:                if (m->reln != 'x') {
1.25    ! chl      1366:                        char *ep;
        !          1367:                        m->value.q = file_signextend(ms, m,
        !          1368:                            (uint64_t)strtoull(*p, &ep, 0));
        !          1369:                        *p = ep;
1.1       deraadt  1370:                        eatsize(p);
                   1371:                }
1.19      tedu     1372:                return 0;
                   1373:        }
1.1       deraadt  1374: }
                   1375:
                   1376: /*
                   1377:  * Convert a string containing C character escapes.  Stop at an unescaped
                   1378:  * space or tab.
                   1379:  * Copy the converted version to "p", returning its length in *slen.
                   1380:  * Return updated scan pointer as function result.
                   1381:  */
1.25    ! chl      1382: private const char *
        !          1383: getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen, int action)
1.1       deraadt  1384: {
1.25    ! chl      1385:        const char *origs = s;
        !          1386:        char    *origp = p;
1.1       deraadt  1387:        char    *pmax = p + plen - 1;
1.11      mpech    1388:        int     c;
                   1389:        int     val;
1.1       deraadt  1390:
                   1391:        while ((c = *s++) != '\0') {
                   1392:                if (isspace((unsigned char) c))
                   1393:                        break;
                   1394:                if (p >= pmax) {
1.19      tedu     1395:                        file_error(ms, 0, "string too long: `%s'", origs);
                   1396:                        return NULL;
1.1       deraadt  1397:                }
1.25    ! chl      1398:                if (c == '\\') {
1.1       deraadt  1399:                        switch(c = *s++) {
                   1400:
                   1401:                        case '\0':
1.25    ! chl      1402:                                if (action == FILE_COMPILE)
        !          1403:                                        file_magwarn(ms, "incomplete escape");
1.1       deraadt  1404:                                goto out;
                   1405:
1.25    ! chl      1406:                        case '\t':
        !          1407:                                if (action == FILE_COMPILE) {
        !          1408:                                        file_magwarn(ms,
        !          1409:                                            "escaped tab found, use \\t instead");
        !          1410:                                        action++;
        !          1411:                                }
        !          1412:                                /*FALLTHROUGH*/
1.1       deraadt  1413:                        default:
1.25    ! chl      1414:                                if (action == FILE_COMPILE) {
        !          1415:                                        if (isprint((unsigned char)c))
        !          1416:                                            file_magwarn(ms,
        !          1417:                                                "no need to escape `%c'", c);
        !          1418:                                        else
        !          1419:                                            file_magwarn(ms,
        !          1420:                                                "unknown escape sequence: \\%03o", c);
        !          1421:                                }
        !          1422:                                /*FALLTHROUGH*/
        !          1423:                        /* space, perhaps force people to use \040? */
        !          1424:                        case ' ':
        !          1425: #if 0
        !          1426:                        /*
        !          1427:                         * Other things people escape, but shouldn't need to,
        !          1428:                         * so we disallow them
        !          1429:                         */
        !          1430:                        case '\'':
        !          1431:                        case '"':
        !          1432:                        case '?':
        !          1433: #endif
        !          1434:                        /* Relations */
        !          1435:                        case '>':
        !          1436:                        case '<':
        !          1437:                        case '&':
        !          1438:                        case '^':
        !          1439:                        case '=':
        !          1440:                        case '!':
        !          1441:                        /* and baskslash itself */
        !          1442:                        case '\\':
1.1       deraadt  1443:                                *p++ = (char) c;
                   1444:                                break;
                   1445:
1.25    ! chl      1446:                        case 'a':
        !          1447:                                *p++ = '\a';
        !          1448:                                break;
        !          1449:
        !          1450:                        case 'b':
        !          1451:                                *p++ = '\b';
        !          1452:                                break;
        !          1453:
        !          1454:                        case 'f':
        !          1455:                                *p++ = '\f';
        !          1456:                                break;
        !          1457:
1.1       deraadt  1458:                        case 'n':
                   1459:                                *p++ = '\n';
                   1460:                                break;
                   1461:
                   1462:                        case 'r':
                   1463:                                *p++ = '\r';
                   1464:                                break;
                   1465:
                   1466:                        case 't':
                   1467:                                *p++ = '\t';
                   1468:                                break;
                   1469:
                   1470:                        case 'v':
                   1471:                                *p++ = '\v';
                   1472:                                break;
                   1473:
                   1474:                        /* \ and up to 3 octal digits */
                   1475:                        case '0':
                   1476:                        case '1':
                   1477:                        case '2':
                   1478:                        case '3':
                   1479:                        case '4':
                   1480:                        case '5':
                   1481:                        case '6':
                   1482:                        case '7':
                   1483:                                val = c - '0';
                   1484:                                c = *s++;  /* try for 2 */
1.25    ! chl      1485:                                if (c >= '0' && c <= '7') {
        !          1486:                                        val = (val << 3) | (c - '0');
1.1       deraadt  1487:                                        c = *s++;  /* try for 3 */
1.25    ! chl      1488:                                        if (c >= '0' && c <= '7')
        !          1489:                                                val = (val << 3) | (c-'0');
1.1       deraadt  1490:                                        else
                   1491:                                                --s;
                   1492:                                }
                   1493:                                else
                   1494:                                        --s;
                   1495:                                *p++ = (char)val;
                   1496:                                break;
                   1497:
1.4       millert  1498:                        /* \x and up to 2 hex digits */
1.1       deraadt  1499:                        case 'x':
                   1500:                                val = 'x';      /* Default if no digits */
                   1501:                                c = hextoint(*s++);     /* Get next char */
                   1502:                                if (c >= 0) {
                   1503:                                        val = c;
                   1504:                                        c = hextoint(*s++);
1.4       millert  1505:                                        if (c >= 0)
1.1       deraadt  1506:                                                val = (val << 4) + c;
1.4       millert  1507:                                        else
1.1       deraadt  1508:                                                --s;
                   1509:                                } else
                   1510:                                        --s;
                   1511:                                *p++ = (char)val;
                   1512:                                break;
                   1513:                        }
                   1514:                } else
                   1515:                        *p++ = (char)c;
                   1516:        }
                   1517: out:
                   1518:        *p = '\0';
                   1519:        *slen = p - origp;
                   1520:        return s;
                   1521: }
                   1522:
                   1523:
                   1524: /* Single hex char to int; -1 if not a hex char. */
1.19      tedu     1525: private int
                   1526: hextoint(int c)
                   1527: {
                   1528:        if (!isascii((unsigned char) c))
                   1529:                return -1;
                   1530:        if (isdigit((unsigned char) c))
                   1531:                return c - '0';
1.25    ! chl      1532:        if ((c >= 'a') && (c <= 'f'))
1.19      tedu     1533:                return c + 10 - 'a';
1.25    ! chl      1534:        if (( c>= 'A') && (c <= 'F'))
1.19      tedu     1535:                return c + 10 - 'A';
                   1536:        return -1;
1.1       deraadt  1537: }
                   1538:
                   1539:
                   1540: /*
                   1541:  * Print a string containing C character escapes.
                   1542:  */
1.19      tedu     1543: protected void
                   1544: file_showstr(FILE *fp, const char *s, size_t len)
1.1       deraadt  1545: {
1.11      mpech    1546:        char    c;
1.1       deraadt  1547:
                   1548:        for (;;) {
                   1549:                c = *s++;
1.19      tedu     1550:                if (len == ~0U) {
1.1       deraadt  1551:                        if (c == '\0')
                   1552:                                break;
                   1553:                }
                   1554:                else  {
                   1555:                        if (len-- == 0)
                   1556:                                break;
                   1557:                }
1.25    ! chl      1558:                if (c >= 040 && c <= 0176)      /* TODO isprint && !iscntrl */
1.1       deraadt  1559:                        (void) fputc(c, fp);
                   1560:                else {
                   1561:                        (void) fputc('\\', fp);
                   1562:                        switch (c) {
1.25    ! chl      1563:                        case '\a':
        !          1564:                                (void) fputc('a', fp);
        !          1565:                                break;
        !          1566:
        !          1567:                        case '\b':
        !          1568:                                (void) fputc('b', fp);
        !          1569:                                break;
        !          1570:
        !          1571:                        case '\f':
        !          1572:                                (void) fputc('f', fp);
        !          1573:                                break;
        !          1574:
1.1       deraadt  1575:                        case '\n':
                   1576:                                (void) fputc('n', fp);
                   1577:                                break;
                   1578:
                   1579:                        case '\r':
                   1580:                                (void) fputc('r', fp);
                   1581:                                break;
                   1582:
                   1583:                        case '\t':
                   1584:                                (void) fputc('t', fp);
                   1585:                                break;
                   1586:
                   1587:                        case '\v':
                   1588:                                (void) fputc('v', fp);
                   1589:                                break;
                   1590:
                   1591:                        default:
                   1592:                                (void) fprintf(fp, "%.3o", c & 0377);
                   1593:                                break;
                   1594:                        }
                   1595:                }
                   1596:        }
                   1597: }
                   1598:
                   1599: /*
                   1600:  * eatsize(): Eat the size spec from a number [eg. 10UL]
                   1601:  */
1.19      tedu     1602: private void
1.25    ! chl      1603: eatsize(const char **p)
1.1       deraadt  1604: {
1.25    ! chl      1605:        const char *l = *p;
1.1       deraadt  1606:
                   1607:        if (LOWCASE(*l) == 'u')
                   1608:                l++;
                   1609:
                   1610:        switch (LOWCASE(*l)) {
                   1611:        case 'l':    /* long */
                   1612:        case 's':    /* short */
                   1613:        case 'h':    /* short */
                   1614:        case 'b':    /* char/byte */
                   1615:        case 'c':    /* char/byte */
                   1616:                l++;
                   1617:                /*FALLTHROUGH*/
                   1618:        default:
                   1619:                break;
                   1620:        }
                   1621:
                   1622:        *p = l;
1.19      tedu     1623: }
                   1624:
                   1625: /*
                   1626:  * handle a compiled file.
                   1627:  */
                   1628: private int
                   1629: apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
                   1630:     const char *fn)
                   1631: {
                   1632:        int fd;
                   1633:        struct stat st;
                   1634:        uint32_t *ptr;
                   1635:        uint32_t version;
                   1636:        int needsbyteswap;
                   1637:        char buf[MAXPATHLEN];
1.25    ! chl      1638:        char *dbname = mkdbname(fn, buf, sizeof(buf), 0);
1.19      tedu     1639:        void *mm = NULL;
                   1640:
                   1641:        if (dbname == NULL)
                   1642:                return -1;
                   1643:
1.25    ! chl      1644:        if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
1.19      tedu     1645:                return -1;
                   1646:
                   1647:        if (fstat(fd, &st) == -1) {
                   1648:                file_error(ms, errno, "cannot stat `%s'", dbname);
                   1649:                goto error;
                   1650:        }
                   1651:        if (st.st_size < 16) {
                   1652:                file_error(ms, 0, "file `%s' is too small", dbname);
                   1653:                goto error;
                   1654:        }
                   1655:
                   1656: #ifdef QUICK
                   1657:        if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
                   1658:            MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
                   1659:                file_error(ms, errno, "cannot map `%s'", dbname);
                   1660:                goto error;
                   1661:        }
                   1662: #define RET    2
                   1663: #else
                   1664:        if ((mm = malloc((size_t)st.st_size)) == NULL) {
1.25    ! chl      1665:                file_oomem(ms, (size_t)st.st_size);
1.19      tedu     1666:                goto error;
                   1667:        }
                   1668:        if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
                   1669:                file_badread(ms);
                   1670:                goto error;
                   1671:        }
                   1672: #define RET    1
                   1673: #endif
                   1674:        *magicp = mm;
                   1675:        (void)close(fd);
                   1676:        fd = -1;
                   1677:        ptr = (uint32_t *)(void *)*magicp;
                   1678:        if (*ptr != MAGICNO) {
                   1679:                if (swap4(*ptr) != MAGICNO) {
                   1680:                        file_error(ms, 0, "bad magic in `%s'");
                   1681:                        goto error;
                   1682:                }
                   1683:                needsbyteswap = 1;
                   1684:        } else
                   1685:                needsbyteswap = 0;
                   1686:        if (needsbyteswap)
                   1687:                version = swap4(ptr[1]);
                   1688:        else
                   1689:                version = ptr[1];
                   1690:        if (version != VERSIONNO) {
                   1691:                file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
                   1692:                    version, VERSIONNO, dbname);
                   1693:                goto error;
                   1694:        }
                   1695:        *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
                   1696:        (*magicp)++;
                   1697:        if (needsbyteswap)
                   1698:                byteswap(*magicp, *nmagicp);
                   1699:        return RET;
                   1700:
                   1701: error:
                   1702:        if (fd != -1)
                   1703:                (void)close(fd);
                   1704:        if (mm) {
                   1705: #ifdef QUICK
                   1706:                (void)munmap((void *)mm, (size_t)st.st_size);
                   1707: #else
                   1708:                free(mm);
                   1709: #endif
                   1710:        } else {
                   1711:                *magicp = NULL;
                   1712:                *nmagicp = 0;
                   1713:        }
                   1714:        return -1;
                   1715: }
                   1716:
                   1717: private const uint32_t ar[] = {
                   1718:     MAGICNO, VERSIONNO
                   1719: };
                   1720: /*
                   1721:  * handle an mmaped file.
                   1722:  */
                   1723: private int
                   1724: apprentice_compile(struct magic_set *ms, struct magic **magicp,
                   1725:     uint32_t *nmagicp, const char *fn)
                   1726: {
                   1727:        int fd;
                   1728:        char buf[MAXPATHLEN];
1.25    ! chl      1729:        char *dbname = mkdbname(fn, buf, sizeof(buf), 1);
1.19      tedu     1730:
                   1731:        if (dbname == NULL)
                   1732:                return -1;
                   1733:
1.25    ! chl      1734:        if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
1.19      tedu     1735:                file_error(ms, errno, "cannot open `%s'", dbname);
                   1736:                return -1;
                   1737:        }
                   1738:
                   1739:        if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
                   1740:                file_error(ms, errno, "error writing `%s'", dbname);
                   1741:                return -1;
                   1742:        }
                   1743:
                   1744:        if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
                   1745:            != sizeof(struct magic)) {
                   1746:                file_error(ms, errno, "error seeking `%s'", dbname);
                   1747:                return -1;
                   1748:        }
                   1749:
                   1750:        if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp))
                   1751:            != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
                   1752:                file_error(ms, errno, "error writing `%s'", dbname);
                   1753:                return -1;
                   1754:        }
                   1755:
                   1756:        (void)close(fd);
                   1757:        return 0;
                   1758: }
                   1759:
                   1760: private const char ext[] = ".mgc";
                   1761: /*
                   1762:  * make a dbname
                   1763:  */
                   1764: private char *
1.25    ! chl      1765: mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)
1.19      tedu     1766: {
1.25    ! chl      1767:        if (strip) {
        !          1768:                const char *p;
        !          1769:                if ((p = strrchr(fn, '/')) != NULL)
        !          1770:                        fn = ++p;
        !          1771:        }
        !          1772:
1.19      tedu     1773:        (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
                   1774:        return buf;
                   1775: }
                   1776:
                   1777: /*
                   1778:  * Byteswap an mmap'ed file if needed
                   1779:  */
                   1780: private void
                   1781: byteswap(struct magic *magic, uint32_t nmagic)
                   1782: {
                   1783:        uint32_t i;
                   1784:        for (i = 0; i < nmagic; i++)
                   1785:                bs1(&magic[i]);
                   1786: }
                   1787:
                   1788: /*
                   1789:  * swap a short
                   1790:  */
                   1791: private uint16_t
                   1792: swap2(uint16_t sv)
                   1793: {
                   1794:        uint16_t rv;
                   1795:        uint8_t *s = (uint8_t *)(void *)&sv;
                   1796:        uint8_t *d = (uint8_t *)(void *)&rv;
                   1797:        d[0] = s[1];
                   1798:        d[1] = s[0];
                   1799:        return rv;
                   1800: }
                   1801:
                   1802: /*
                   1803:  * swap an int
                   1804:  */
                   1805: private uint32_t
                   1806: swap4(uint32_t sv)
                   1807: {
                   1808:        uint32_t rv;
                   1809:        uint8_t *s = (uint8_t *)(void *)&sv;
                   1810:        uint8_t *d = (uint8_t *)(void *)&rv;
                   1811:        d[0] = s[3];
                   1812:        d[1] = s[2];
                   1813:        d[2] = s[1];
                   1814:        d[3] = s[0];
                   1815:        return rv;
                   1816: }
                   1817:
                   1818: /*
1.25    ! chl      1819:  * swap a quad
        !          1820:  */
        !          1821: private uint64_t
        !          1822: swap8(uint64_t sv)
        !          1823: {
        !          1824:        uint32_t rv;
        !          1825:        uint8_t *s = (uint8_t *)(void *)&sv;
        !          1826:        uint8_t *d = (uint8_t *)(void *)&rv;
        !          1827:        d[0] = s[3];
        !          1828:        d[1] = s[2];
        !          1829:        d[2] = s[1];
        !          1830:        d[3] = s[0];
        !          1831:        d[4] = s[7];
        !          1832:        d[5] = s[6];
        !          1833:        d[6] = s[5];
        !          1834:        d[7] = s[4];
        !          1835:        return rv;
        !          1836: }
        !          1837:
        !          1838: /*
1.19      tedu     1839:  * byteswap a single magic entry
                   1840:  */
                   1841: private void
                   1842: bs1(struct magic *m)
                   1843: {
                   1844:        m->cont_level = swap2(m->cont_level);
                   1845:        m->offset = swap4((uint32_t)m->offset);
                   1846:        m->in_offset = swap4((uint32_t)m->in_offset);
1.25    ! chl      1847:        m->lineno = swap4((uint32_t)m->lineno);
        !          1848:        if (IS_STRING(m->type)) {
        !          1849:                m->str_count = swap4(m->str_count);
        !          1850:                m->str_flags = swap4(m->str_flags);
        !          1851:        }
        !          1852:        else {
        !          1853:                m->value.q = swap8(m->value.q);
        !          1854:                m->num_mask = swap8(m->num_mask);
        !          1855:        }
1.1       deraadt  1856: }