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: }