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

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