]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/file/apprentice.c
This commit was generated by cvs2svn to compensate for changes in r168777,
[FreeBSD/FreeBSD.git] / contrib / file / apprentice.c
1 /*
2  * Copyright (c) Ian F. Darwin 1986-1995.
3  * Software written by Ian F. Darwin and others;
4  * maintained 1995-present by Christos Zoulas and others.
5  * 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice immediately at the beginning of the file, without modification,
11  *    this list of conditions, and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *  
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 /*
29  * apprentice - make one pass through /etc/magic, learning its secrets.
30  */
31
32 #include "file.h"
33 #include "magic.h"
34 #include <stdlib.h>
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <string.h>
39 #include <ctype.h>
40 #include <fcntl.h>
41 #include <sys/stat.h>
42 #include <sys/param.h>
43 #ifdef QUICK
44 #include <sys/mman.h>
45 #endif
46
47 #ifndef lint
48 FILE_RCSID("@(#)$Id: apprentice.c,v 1.87 2006/03/02 22:08:57 christos Exp $")
49 #endif  /* lint */
50
51 #define EATAB {while (isascii((unsigned char) *l) && \
52                       isspace((unsigned char) *l))  ++l;}
53 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
54                         tolower((unsigned char) (l)) : (l))
55 /*
56  * Work around a bug in headers on Digital Unix.
57  * At least confirmed for: OSF1 V4.0 878
58  */
59 #if defined(__osf__) && defined(__DECC)
60 #ifdef MAP_FAILED
61 #undef MAP_FAILED
62 #endif
63 #endif
64
65 #ifndef MAP_FAILED
66 #define MAP_FAILED (void *) -1
67 #endif
68
69 #ifndef MAP_FILE
70 #define MAP_FILE 0
71 #endif
72
73 #ifndef MAXPATHLEN
74 #define MAXPATHLEN      1024
75 #endif
76
77 #define IS_PLAINSTRING(t) ((t) == FILE_STRING || (t) == FILE_PSTRING || \
78     (t) == FILE_BESTRING16 || (t) == FILE_LESTRING16)
79     
80 #define IS_STRING(t) (IS_PLAINSTRING(t) || (t) == FILE_REGEX || \
81     (t) == FILE_SEARCH)
82
83 struct magic_entry {
84         struct magic *mp;       
85         uint32_t cont_count;
86         uint32_t max_count;
87 };
88
89 private int getvalue(struct magic_set *ms, struct magic *, const char **);
90 private int hextoint(int);
91 private const char *getstr(struct magic_set *, const char *, char *, int,
92     int *);
93 private int parse(struct magic_set *, struct magic_entry **, uint32_t *,
94     const char *, int);
95 private void eatsize(const char **);
96 private int apprentice_1(struct magic_set *, const char *, int, struct mlist *);
97 private size_t apprentice_magic_strength(const struct magic *);
98 private int apprentice_sort(const void *, const void *);
99 private int apprentice_file(struct magic_set *, struct magic **, uint32_t *,
100     const char *, int);
101 private void byteswap(struct magic *, uint32_t);
102 private void bs1(struct magic *);
103 private uint16_t swap2(uint16_t);
104 private uint32_t swap4(uint32_t);
105 private char *mkdbname(const char *, char *, size_t, int);
106 private int apprentice_map(struct magic_set *, struct magic **, uint32_t *,
107     const char *);
108 private int apprentice_compile(struct magic_set *, struct magic **, uint32_t *,
109     const char *);
110 private int check_format(struct magic_set *, struct magic *);
111
112 private size_t maxmagic = 0;
113 private size_t magicsize = sizeof(struct magic);
114
115
116 #ifdef COMPILE_ONLY
117
118 int main(int, char *[]);
119
120 int
121 main(int argc, char *argv[])
122 {
123         int ret;
124         struct magic_set *ms;
125         char *progname;
126
127         if ((progname = strrchr(argv[0], '/')) != NULL)
128                 progname++;
129         else
130                 progname = argv[0];
131
132         if (argc != 2) {
133                 (void)fprintf(stderr, "Usage: %s file\n", progname);
134                 return 1;
135         }
136
137         if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
138                 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
139                 return 1;
140         }
141         ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
142         if (ret == 1)
143                 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
144         magic_close(ms);
145         return ret;
146 }
147 #endif /* COMPILE_ONLY */
148
149
150 /*
151  * Handle one file.
152  */
153 private int
154 apprentice_1(struct magic_set *ms, const char *fn, int action,
155     struct mlist *mlist)
156 {
157         struct magic *magic = NULL;
158         uint32_t nmagic = 0;
159         struct mlist *ml;
160         int rv = -1;
161         int mapped;
162
163         if (magicsize != FILE_MAGICSIZE) {
164                 file_error(ms, 0, "magic element size %lu != %lu",
165                     (unsigned long)sizeof(*magic),
166                     (unsigned long)FILE_MAGICSIZE);
167                 return -1;
168         }
169
170         if (action == FILE_COMPILE) {
171                 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
172                 if (rv != 0)
173                         return -1;
174                 rv = apprentice_compile(ms, &magic, &nmagic, fn);
175                 free(magic);
176                 return rv;
177         }
178
179 #ifndef COMPILE_ONLY
180         if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
181                 if (ms->flags & MAGIC_CHECK)
182                         file_magwarn(ms, "using regular magic file `%s'", fn);
183                 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
184                 if (rv != 0)
185                         return -1;
186                 mapped = 0;
187         }
188
189         if (rv == -1)
190                 return rv;
191         mapped = rv;
192              
193         if (magic == NULL || nmagic == 0) {
194                 file_delmagic(magic, mapped, nmagic);
195                 return -1;
196         }
197
198         if ((ml = malloc(sizeof(*ml))) == NULL) {
199                 file_delmagic(magic, mapped, nmagic);
200                 file_oomem(ms);
201                 return -1;
202         }
203
204         ml->magic = magic;
205         ml->nmagic = nmagic;
206         ml->mapped = mapped;
207
208         mlist->prev->next = ml;
209         ml->prev = mlist->prev;
210         ml->next = mlist;
211         mlist->prev = ml;
212
213         return 0;
214 #endif /* COMPILE_ONLY */
215 }
216
217 protected void
218 file_delmagic(struct magic *p, int type, size_t entries)
219 {
220         if (p == NULL)
221                 return;
222         switch (type) {
223         case 2:
224                 p--;
225                 (void)munmap((void *)p, sizeof(*p) * (entries + 1));
226                 break;
227         case 1:
228                 p--;
229                 /*FALLTHROUGH*/
230         case 0:
231                 free(p);
232                 break;
233         default:
234                 abort();
235         }
236 }
237
238
239 /* const char *fn: list of magic files */
240 protected struct mlist *
241 file_apprentice(struct magic_set *ms, const char *fn, int action)
242 {
243         char *p, *mfn, *afn = NULL;
244         int file_err, errs = -1;
245         struct mlist *mlist;
246
247         if (fn == NULL)
248                 fn = getenv("MAGIC");
249         if (fn == NULL)
250                 fn = MAGIC;
251
252         if ((fn = mfn = strdup(fn)) == NULL) {
253                 file_oomem(ms);
254                 return NULL;
255         }
256
257         if ((mlist = malloc(sizeof(*mlist))) == NULL) {
258                 free(mfn);
259                 file_oomem(ms);
260                 return NULL;
261         }
262         mlist->next = mlist->prev = mlist;
263
264         while (fn) {
265                 p = strchr(fn, PATHSEP);
266                 if (p)
267                         *p++ = '\0';
268                 if (*fn == '\0')
269                         break;
270                 if (ms->flags & MAGIC_MIME) {
271                         if ((afn = malloc(strlen(fn) + 5 + 1)) == NULL) {
272                                 free(mfn);
273                                 free(mlist);
274                                 file_oomem(ms);
275                                 return NULL;
276                         }
277                         (void)strcpy(afn, fn);
278                         (void)strcat(afn, ".mime");
279                         fn = afn;
280                 }
281                 file_err = apprentice_1(ms, fn, action, mlist);
282                 if (file_err > errs)
283                         errs = file_err;
284                 if (afn) {
285                         free(afn);
286                         afn = NULL;
287                 }
288                 fn = p;
289         }
290         if (errs == -1) {
291                 free(mfn);
292                 free(mlist);
293                 mlist = NULL;
294                 file_error(ms, 0, "could not find any magic files!");
295                 return NULL;
296         }
297         free(mfn);
298         return mlist;
299 }
300
301 private size_t
302 apprentice_magic_strength(const struct magic *m)
303 {
304         switch (m->type) {
305         case FILE_BYTE:
306                 return 1;
307
308         case FILE_SHORT:
309         case FILE_LESHORT:
310         case FILE_BESHORT:
311                 return 2;
312
313         case FILE_LONG:
314         case FILE_LELONG:
315         case FILE_BELONG:
316         case FILE_MELONG:
317                 return 4;
318
319         case FILE_PSTRING:
320         case FILE_STRING:
321         case FILE_REGEX:
322         case FILE_BESTRING16:
323         case FILE_LESTRING16:
324         case FILE_SEARCH:
325                 return m->vallen;
326
327         case FILE_DATE:
328         case FILE_LEDATE:
329         case FILE_BEDATE:
330         case FILE_MEDATE:
331                 return 4;
332
333         case FILE_LDATE:
334         case FILE_LELDATE:
335         case FILE_BELDATE:
336         case FILE_MELDATE:
337                 return 8;
338
339         default:
340                 return 0;
341         }
342 }
343
344 private int
345 apprentice_sort(const void *a, const void *b)
346 {
347         const struct magic_entry *ma = a;
348         const struct magic_entry *mb = b;
349         size_t sa = apprentice_magic_strength(ma->mp);
350         size_t sb = apprentice_magic_strength(mb->mp);
351         if (sa == sb)
352                 return 0;
353         else if (sa > sb)
354                 return -1;
355         else
356                 return 1;
357 }
358
359 /*
360  * parse from a file
361  * const char *fn: name of magic file
362  */
363 private int
364 apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
365     const char *fn, int action)
366 {
367         private const char hdr[] =
368                 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
369         FILE *f;
370         char line[BUFSIZ+1];
371         int errs = 0;
372         struct magic_entry *marray;
373         uint32_t marraycount, i, mentrycount;
374
375         f = fopen(ms->file = fn, "r");
376         if (f == NULL) {
377                 if (errno != ENOENT)
378                         file_error(ms, errno, "cannot read magic file `%s'",
379                             fn);
380                 return -1;
381         }
382
383         maxmagic = MAXMAGIS;
384         if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
385                 (void)fclose(f);
386                 file_oomem(ms);
387                 return -1;
388         }
389         marraycount = 0;
390
391         /* print silly verbose header for USG compat. */
392         if (action == FILE_CHECK)
393                 (void)fprintf(stderr, "%s\n", hdr);
394
395         /* parse it */
396         for (ms->line = 1; fgets(line, BUFSIZ, f) != NULL; ms->line++) {
397                 size_t len;
398                 if (line[0] == '#')     /* comment, do not parse */
399                         continue;
400                 len = strlen(line);
401                 if (len < 2) /* null line, garbage, etc */
402                         continue;
403                 if (line[len - 1] == '\n')
404                         line[len - 1] = '\0'; /* delete newline */
405                 if (parse(ms, &marray, &marraycount, line, action) != 0)
406                         errs++;
407         }
408
409         (void)fclose(f);
410         if (errs)
411                 goto out;
412
413 #ifndef NOORDER
414         qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
415 #endif
416
417         for (i = 0, mentrycount = 0; i < marraycount; i++)
418                 mentrycount += marray[i].cont_count;
419
420         if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) {
421                 file_oomem(ms);
422                 errs++;
423                 goto out;
424         }
425
426         mentrycount = 0;
427         for (i = 0; i < marraycount; i++) {
428                 (void)memcpy(*magicp + mentrycount, marray[i].mp,
429                     marray[i].cont_count * sizeof(**magicp));
430                 mentrycount += marray[i].cont_count;
431         }
432 out:
433         for (i = 0; i < marraycount; i++)
434                 free(marray[i].mp);
435         free(marray);
436         if (errs) {
437                 *magicp = NULL;
438                 *nmagicp = 0;
439                 return errs;
440         } else {
441                 *nmagicp = mentrycount;
442                 return 0;
443         }
444
445 }
446
447 /*
448  * extend the sign bit if the comparison is to be signed
449  */
450 protected uint32_t
451 file_signextend(struct magic_set *ms, struct magic *m, uint32_t v)
452 {
453         if (!(m->flag & UNSIGNED))
454                 switch(m->type) {
455                 /*
456                  * Do not remove the casts below.  They are
457                  * vital.  When later compared with the data,
458                  * the sign extension must have happened.
459                  */
460                 case FILE_BYTE:
461                         v = (char) v;
462                         break;
463                 case FILE_SHORT:
464                 case FILE_BESHORT:
465                 case FILE_LESHORT:
466                         v = (short) v;
467                         break;
468                 case FILE_DATE:
469                 case FILE_BEDATE:
470                 case FILE_LEDATE:
471                 case FILE_MEDATE:
472                 case FILE_LDATE:
473                 case FILE_BELDATE:
474                 case FILE_LELDATE:
475                 case FILE_MELDATE:
476                 case FILE_LONG:
477                 case FILE_BELONG:
478                 case FILE_LELONG:
479                 case FILE_MELONG:
480                         v = (int32_t) v;
481                         break;
482                 case FILE_STRING:
483                 case FILE_PSTRING:
484                 case FILE_BESTRING16:
485                 case FILE_LESTRING16:
486                 case FILE_REGEX:
487                 case FILE_SEARCH:
488                         break;
489                 default:
490                         if (ms->flags & MAGIC_CHECK)
491                             file_magwarn(ms, "cannot happen: m->type=%d\n",
492                                     m->type);
493                         return ~0U;
494                 }
495         return v;
496 }
497
498 /*
499  * parse one line from magic file, put into magic[index++] if valid
500  */
501 private int
502 parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, 
503     const char *line, int action)
504 {
505         int i = 0;
506         struct magic_entry *me;
507         struct magic *m;
508         const char *l = line;
509         char *t;
510         private const char *fops = FILE_OPS;
511         uint32_t val;
512         uint32_t cont_level;
513
514         cont_level = 0;
515
516         while (*l == '>') {
517                 ++l;            /* step over */
518                 cont_level++; 
519         }
520
521 #define ALLOC_CHUNK     (size_t)10
522 #define ALLOC_INCR      (size_t)200
523
524         if (cont_level != 0) {
525                 if (*nmentryp == 0) {
526                         file_error(ms, 0, "No current entry for continuation");
527                         return -1;
528                 }
529                 me = &(*mentryp)[*nmentryp - 1];
530                 if (me->cont_count == me->max_count) {
531                         struct magic *nm;
532                         size_t cnt = me->max_count + ALLOC_CHUNK;
533                         if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) {
534                                 file_oomem(ms);
535                                 return -1;
536                         }
537                         me->mp = m = nm;
538                         me->max_count = cnt;
539                 }
540                 m = &me->mp[me->cont_count++];
541                 memset(m, 0, sizeof(*m));
542                 m->cont_level = cont_level;
543         } else {
544                 if (*nmentryp == maxmagic) {
545                         struct magic_entry *mp;
546
547                         maxmagic += ALLOC_INCR;
548                         if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) ==
549                             NULL) {
550                                 file_oomem(ms);
551                                 return -1;
552                         }
553                         (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
554                             ALLOC_INCR);
555                         *mentryp = mp;
556                 }
557                 me = &(*mentryp)[*nmentryp];
558                 if (me->mp == NULL) {
559                         if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) {
560                                 file_oomem(ms);
561                                 return -1;
562                         }
563                         me->mp = m;
564                         me->max_count = ALLOC_CHUNK;
565                 } else
566                         m = me->mp;
567                 memset(m, 0, sizeof(*m));
568                 m->cont_level = 0;
569                 me->cont_count = 1;
570         }
571
572         if (m->cont_level != 0 && *l == '&') {
573                 ++l;            /* step over */
574                 m->flag |= OFFADD;
575         }
576         if (m->cont_level != 0 && *l == '(') {
577                 ++l;            /* step over */
578                 m->flag |= INDIR;
579                 if (m->flag & OFFADD)
580                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
581         }
582         if (m->cont_level != 0 && *l == '&') {
583                 ++l;            /* step over */
584                 m->flag |= OFFADD;
585         }
586
587         /* get offset, then skip over it */
588         m->offset = (uint32_t)strtoul(l, &t, 0);
589         if (l == t)
590                 if (ms->flags & MAGIC_CHECK)
591                         file_magwarn(ms, "offset `%s' invalid", l);
592         l = t;
593
594         if (m->flag & INDIR) {
595                 m->in_type = FILE_LONG;
596                 m->in_offset = 0;
597                 /*
598                  * read [.lbs][+-]nnnnn)
599                  */
600                 if (*l == '.') {
601                         l++;
602                         switch (*l) {
603                         case 'l':
604                                 m->in_type = FILE_LELONG;
605                                 break;
606                         case 'L':
607                                 m->in_type = FILE_BELONG;
608                                 break;
609                         case 'm':
610                                 m->in_type = FILE_MELONG;
611                                 break;
612                         case 'h':
613                         case 's':
614                                 m->in_type = FILE_LESHORT;
615                                 break;
616                         case 'H':
617                         case 'S':
618                                 m->in_type = FILE_BESHORT;
619                                 break;
620                         case 'c':
621                         case 'b':
622                         case 'C':
623                         case 'B':
624                                 m->in_type = FILE_BYTE;
625                                 break;
626                         default:
627                                 if (ms->flags & MAGIC_CHECK)
628                                         file_magwarn(ms,
629                                             "indirect offset type `%c' invalid",
630                                             *l);
631                                 break;
632                         }
633                         l++;
634                 }
635                 if (*l == '~') {
636                         m->in_op |= FILE_OPINVERSE;
637                         l++;
638                 }
639                 switch (*l) {
640                 case '&':
641                         m->in_op |= FILE_OPAND;
642                         l++;
643                         break;
644                 case '|':
645                         m->in_op |= FILE_OPOR;
646                         l++;
647                         break;
648                 case '^':
649                         m->in_op |= FILE_OPXOR;
650                         l++;
651                         break;
652                 case '+':
653                         m->in_op |= FILE_OPADD;
654                         l++;
655                         break;
656                 case '-':
657                         m->in_op |= FILE_OPMINUS;
658                         l++;
659                         break;
660                 case '*':
661                         m->in_op |= FILE_OPMULTIPLY;
662                         l++;
663                         break;
664                 case '/':
665                         m->in_op |= FILE_OPDIVIDE;
666                         l++;
667                         break;
668                 case '%':
669                         m->in_op |= FILE_OPMODULO;
670                         l++;
671                         break;
672                 }
673                 if (*l == '(') {
674                         m->in_op |= FILE_OPINDIRECT;
675                         l++;
676                 }
677                 if (isdigit((unsigned char)*l) || *l == '-') {
678                         m->in_offset = (int32_t)strtol(l, &t, 0);
679                         l = t;
680                 }
681                 if (*l++ != ')' || 
682                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
683                         if (ms->flags & MAGIC_CHECK)
684                                 file_magwarn(ms,
685                                     "missing ')' in indirect offset");
686         }
687
688
689         while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
690                 ++l;
691         EATAB;
692
693 #define NBYTE           4
694 #define NSHORT          5
695 #define NLONG           4
696 #define NSTRING         6
697 #define NDATE           4
698 #define NBESHORT        7
699 #define NBELONG         6
700 #define NBEDATE         6
701 #define NLESHORT        7
702 #define NLELONG         6
703 #define NMELONG         6
704 #define NLEDATE         6
705 #define NMEDATE         6
706 #define NPSTRING        7
707 #define NLDATE          5
708 #define NBELDATE        7
709 #define NLELDATE        7
710 #define NMELDATE        7
711 #define NREGEX          5
712 #define NBESTRING16     10
713 #define NLESTRING16     10
714 #define NSEARCH         6
715
716         if (*l == 'u') {
717                 ++l;
718                 m->flag |= UNSIGNED;
719         }
720
721         /* get type, skip it */
722         if (strncmp(l, "char", NBYTE)==0) {     /* HP/UX compat */
723                 m->type = FILE_BYTE;
724                 l += NBYTE;
725         } else if (strncmp(l, "byte", NBYTE)==0) {
726                 m->type = FILE_BYTE;
727                 l += NBYTE;
728         } else if (strncmp(l, "short", NSHORT)==0) {
729                 m->type = FILE_SHORT;
730                 l += NSHORT;
731         } else if (strncmp(l, "long", NLONG)==0) {
732                 m->type = FILE_LONG;
733                 l += NLONG;
734         } else if (strncmp(l, "string", NSTRING)==0) {
735                 m->type = FILE_STRING;
736                 l += NSTRING;
737         } else if (strncmp(l, "date", NDATE)==0) {
738                 m->type = FILE_DATE;
739                 l += NDATE;
740         } else if (strncmp(l, "beshort", NBESHORT)==0) {
741                 m->type = FILE_BESHORT;
742                 l += NBESHORT;
743         } else if (strncmp(l, "belong", NBELONG)==0) {
744                 m->type = FILE_BELONG;
745                 l += NBELONG;
746         } else if (strncmp(l, "bedate", NBEDATE)==0) {
747                 m->type = FILE_BEDATE;
748                 l += NBEDATE;
749         } else if (strncmp(l, "leshort", NLESHORT)==0) {
750                 m->type = FILE_LESHORT;
751                 l += NLESHORT;
752         } else if (strncmp(l, "lelong", NLELONG)==0) {
753                 m->type = FILE_LELONG;
754                 l += NLELONG;
755         } else if (strncmp(l, "melong", NMELONG)==0) {
756                 m->type = FILE_MELONG;
757                 l += NMELONG;
758         } else if (strncmp(l, "ledate", NLEDATE)==0) {
759                 m->type = FILE_LEDATE;
760                 l += NLEDATE;
761         } else if (strncmp(l, "medate", NMEDATE)==0) {
762                 m->type = FILE_MEDATE;
763                 l += NMEDATE;
764         } else if (strncmp(l, "pstring", NPSTRING)==0) {
765                 m->type = FILE_PSTRING;
766                 l += NPSTRING;
767         } else if (strncmp(l, "ldate", NLDATE)==0) {
768                 m->type = FILE_LDATE;
769                 l += NLDATE;
770         } else if (strncmp(l, "beldate", NBELDATE)==0) {
771                 m->type = FILE_BELDATE;
772                 l += NBELDATE;
773         } else if (strncmp(l, "leldate", NLELDATE)==0) {
774                 m->type = FILE_LELDATE;
775                 l += NLELDATE;
776         } else if (strncmp(l, "meldate", NMELDATE)==0) {
777                 m->type = FILE_MELDATE;
778                 l += NMELDATE;
779         } else if (strncmp(l, "regex", NREGEX)==0) {
780                 m->type = FILE_REGEX;
781                 l += NREGEX;
782         } else if (strncmp(l, "bestring16", NBESTRING16)==0) {
783                 m->type = FILE_BESTRING16;
784                 l += NBESTRING16;
785         } else if (strncmp(l, "lestring16", NLESTRING16)==0) {
786                 m->type = FILE_LESTRING16;
787                 l += NLESTRING16;
788         } else if (strncmp(l, "search", NSEARCH)==0) {
789                 m->type = FILE_SEARCH;
790                 l += NSEARCH;
791         } else {
792                 if (ms->flags & MAGIC_CHECK)
793                         file_magwarn(ms, "type `%s' invalid", l);
794                 return -1;
795         }
796         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
797         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
798         if (*l == '~') {
799                 if (!IS_STRING(m->type))
800                         m->mask_op |= FILE_OPINVERSE;
801                 ++l;
802         }
803         if ((t = strchr(fops,  *l)) != NULL) {
804                 uint32_t op = (uint32_t)(t - fops);
805                 if (op != FILE_OPDIVIDE || !IS_PLAINSTRING(m->type)) {
806                         ++l;
807                         m->mask_op |= op;
808                         val = (uint32_t)strtoul(l, &t, 0);
809                         l = t;
810                         m->mask = file_signextend(ms, m, val);
811                         eatsize(&l);
812                 } else {
813                         m->mask = 0L;
814                         while (!isspace((unsigned char)*++l)) {
815                                 switch (*l) {
816                                 case CHAR_IGNORE_LOWERCASE:
817                                         m->mask |= STRING_IGNORE_LOWERCASE;
818                                         break;
819                                 case CHAR_COMPACT_BLANK:
820                                         m->mask |= STRING_COMPACT_BLANK;
821                                         break;
822                                 case CHAR_COMPACT_OPTIONAL_BLANK:
823                                         m->mask |=
824                                             STRING_COMPACT_OPTIONAL_BLANK;
825                                         break;
826                                 default:
827                                         if (ms->flags & MAGIC_CHECK)
828                                                 file_magwarn(ms,
829                                                 "string extension `%c' invalid",
830                                                 *l);
831                                         return -1;
832                                 }
833                         }
834                         ++l;
835                 }
836         }
837         /*
838          * We used to set mask to all 1's here, instead let's just not do
839          * anything if mask = 0 (unless you have a better idea)
840          */
841         EATAB;
842   
843         switch (*l) {
844         case '>':
845         case '<':
846         /* Old-style anding: "0 byte &0x80 dynamically linked" */
847         case '&':
848         case '^':
849         case '=':
850                 m->reln = *l;
851                 ++l;
852                 if (*l == '=') {
853                    /* HP compat: ignore &= etc. */
854                    ++l;
855                 }
856                 break;
857         case '!':
858                 m->reln = *l;
859                 ++l;
860                 break;
861         default:
862                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
863                     isspace((unsigned char)l[1])) || !l[1])) {
864                         m->reln = *l;
865                         ++l;
866                         goto GetDesc;   /* Bill The Cat */
867                 }
868                 m->reln = '=';
869                 break;
870         }
871         EATAB;
872   
873         if (getvalue(ms, m, &l))
874                 return -1;
875         /*
876          * TODO finish this macro and start using it!
877          * #define offsetcheck {if (offset > HOWMANY-1) 
878          *      magwarn("offset too big"); }
879          */
880
881         /*
882          * now get last part - the description
883          */
884 GetDesc:
885         EATAB;
886         if (l[0] == '\b') {
887                 ++l;
888                 m->nospflag = 1;
889         } else if ((l[0] == '\\') && (l[1] == 'b')) {
890                 ++l;
891                 ++l;
892                 m->nospflag = 1;
893         } else
894                 m->nospflag = 0;
895         while ((m->desc[i++] = *l++) != '\0' && i < MAXDESC)
896                 /* NULLBODY */;
897
898         if (ms->flags & MAGIC_CHECK) {
899                 if (!check_format(ms, m))
900                         return -1;
901         }
902 #ifndef COMPILE_ONLY
903         if (action == FILE_CHECK) {
904                 file_mdump(m);
905         }
906 #endif
907         if (m->cont_level == 0)
908                 ++(*nmentryp);          /* make room for next */
909         return 0;
910 }
911
912 /*
913  * Check that the optional printf format in description matches
914  * the type of the magic.
915  */
916 private int
917 check_format(struct magic_set *ms, struct magic *m)
918 {
919         static const char *formats[] = { FILE_FORMAT_STRING };
920         static const char *names[] = { FILE_FORMAT_NAME };
921         char *ptr;
922
923         for (ptr = m->desc; *ptr; ptr++)
924                 if (*ptr == '%')
925                         break;
926         if (*ptr == '\0') {
927                 /* No format string; ok */
928                 return 1;
929         }
930         if (m->type >= sizeof(formats)/sizeof(formats[0])) {
931                 file_magwarn(ms, "Internal error inconsistency between m->type"
932                     " and format strings");
933                 return 0;
934         }
935         if (formats[m->type] == NULL) {
936                 file_magwarn(ms, "No format string for `%s' with description "
937                     "`%s'", m->desc, names[m->type]);
938                 return 0;
939         }
940         for (; *ptr; ptr++) {
941                 if (*ptr == 'l' || *ptr == 'h') {
942                         /* XXX: we should really fix this one day */
943                         continue;
944                 }
945                 if (islower((unsigned char)*ptr) || *ptr == 'X')
946                         break;
947         }
948         if (*ptr == '\0') {
949                 /* Missing format string; bad */
950                 file_magwarn(ms, "Invalid format `%s' for type `%s'",
951                         m->desc, names[m->type]);
952                 return 0;
953         }
954         if (strchr(formats[m->type], *ptr) == NULL) {
955                 file_magwarn(ms, "Printf format `%c' is not valid for type `%s'"
956                     " in description `%s'",
957                         *ptr, names[m->type], m->desc);
958                 return 0;
959         }
960         return 1;
961 }
962
963 /* 
964  * Read a numeric value from a pointer, into the value union of a magic 
965  * pointer, according to the magic type.  Update the string pointer to point 
966  * just after the number read.  Return 0 for success, non-zero for failure.
967  */
968 private int
969 getvalue(struct magic_set *ms, struct magic *m, const char **p)
970 {
971         int slen;
972
973         switch (m->type) {
974         case FILE_BESTRING16:
975         case FILE_LESTRING16:
976         case FILE_STRING:
977         case FILE_PSTRING:
978         case FILE_REGEX:
979         case FILE_SEARCH:
980                 *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen);
981                 if (*p == NULL) {
982                         if (ms->flags & MAGIC_CHECK)
983                                 file_magwarn(ms, "cannot get string from `%s'",
984                                     m->value.s);
985                         return -1;
986                 }
987                 m->vallen = slen;
988                 return 0;
989         default:
990                 if (m->reln != 'x') {
991                         char *ep;
992                         m->value.l = file_signextend(ms, m,
993                             (uint32_t)strtoul(*p, &ep, 0));
994                         *p = ep;
995                         eatsize(p);
996                 }
997                 return 0;
998         }
999 }
1000
1001 /*
1002  * Convert a string containing C character escapes.  Stop at an unescaped
1003  * space or tab.
1004  * Copy the converted version to "p", returning its length in *slen.
1005  * Return updated scan pointer as function result.
1006  */
1007 private const char *
1008 getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen)
1009 {
1010         const char *origs = s;
1011         char    *origp = p;
1012         char    *pmax = p + plen - 1;
1013         int     c;
1014         int     val;
1015
1016         while ((c = *s++) != '\0') {
1017                 if (isspace((unsigned char) c))
1018                         break;
1019                 if (p >= pmax) {
1020                         file_error(ms, 0, "string too long: `%s'", origs);
1021                         return NULL;
1022                 }
1023                 if(c == '\\') {
1024                         switch(c = *s++) {
1025
1026                         case '\0':
1027                                 goto out;
1028
1029                         default:
1030                                 *p++ = (char) c;
1031                                 break;
1032
1033                         case 'n':
1034                                 *p++ = '\n';
1035                                 break;
1036
1037                         case 'r':
1038                                 *p++ = '\r';
1039                                 break;
1040
1041                         case 'b':
1042                                 *p++ = '\b';
1043                                 break;
1044
1045                         case 't':
1046                                 *p++ = '\t';
1047                                 break;
1048
1049                         case 'f':
1050                                 *p++ = '\f';
1051                                 break;
1052
1053                         case 'v':
1054                                 *p++ = '\v';
1055                                 break;
1056
1057                         /* \ and up to 3 octal digits */
1058                         case '0':
1059                         case '1':
1060                         case '2':
1061                         case '3':
1062                         case '4':
1063                         case '5':
1064                         case '6':
1065                         case '7':
1066                                 val = c - '0';
1067                                 c = *s++;  /* try for 2 */
1068                                 if(c >= '0' && c <= '7') {
1069                                         val = (val<<3) | (c - '0');
1070                                         c = *s++;  /* try for 3 */
1071                                         if(c >= '0' && c <= '7')
1072                                                 val = (val<<3) | (c-'0');
1073                                         else
1074                                                 --s;
1075                                 }
1076                                 else
1077                                         --s;
1078                                 *p++ = (char)val;
1079                                 break;
1080
1081                         /* \x and up to 2 hex digits */
1082                         case 'x':
1083                                 val = 'x';      /* Default if no digits */
1084                                 c = hextoint(*s++);     /* Get next char */
1085                                 if (c >= 0) {
1086                                         val = c;
1087                                         c = hextoint(*s++);
1088                                         if (c >= 0)
1089                                                 val = (val << 4) + c;
1090                                         else
1091                                                 --s;
1092                                 } else
1093                                         --s;
1094                                 *p++ = (char)val;
1095                                 break;
1096                         }
1097                 } else
1098                         *p++ = (char)c;
1099         }
1100 out:
1101         *p = '\0';
1102         *slen = p - origp;
1103         return s;
1104 }
1105
1106
1107 /* Single hex char to int; -1 if not a hex char. */
1108 private int
1109 hextoint(int c)
1110 {
1111         if (!isascii((unsigned char) c))
1112                 return -1;
1113         if (isdigit((unsigned char) c))
1114                 return c - '0';
1115         if ((c >= 'a')&&(c <= 'f'))
1116                 return c + 10 - 'a';
1117         if (( c>= 'A')&&(c <= 'F'))
1118                 return c + 10 - 'A';
1119         return -1;
1120 }
1121
1122
1123 /*
1124  * Print a string containing C character escapes.
1125  */
1126 protected void
1127 file_showstr(FILE *fp, const char *s, size_t len)
1128 {
1129         char    c;
1130
1131         for (;;) {
1132                 c = *s++;
1133                 if (len == ~0U) {
1134                         if (c == '\0')
1135                                 break;
1136                 }
1137                 else  {
1138                         if (len-- == 0)
1139                                 break;
1140                 }
1141                 if(c >= 040 && c <= 0176)       /* TODO isprint && !iscntrl */
1142                         (void) fputc(c, fp);
1143                 else {
1144                         (void) fputc('\\', fp);
1145                         switch (c) {
1146                         
1147                         case '\n':
1148                                 (void) fputc('n', fp);
1149                                 break;
1150
1151                         case '\r':
1152                                 (void) fputc('r', fp);
1153                                 break;
1154
1155                         case '\b':
1156                                 (void) fputc('b', fp);
1157                                 break;
1158
1159                         case '\t':
1160                                 (void) fputc('t', fp);
1161                                 break;
1162
1163                         case '\f':
1164                                 (void) fputc('f', fp);
1165                                 break;
1166
1167                         case '\v':
1168                                 (void) fputc('v', fp);
1169                                 break;
1170
1171                         default:
1172                                 (void) fprintf(fp, "%.3o", c & 0377);
1173                                 break;
1174                         }
1175                 }
1176         }
1177 }
1178
1179 /*
1180  * eatsize(): Eat the size spec from a number [eg. 10UL]
1181  */
1182 private void
1183 eatsize(const char **p)
1184 {
1185         const char *l = *p;
1186
1187         if (LOWCASE(*l) == 'u') 
1188                 l++;
1189
1190         switch (LOWCASE(*l)) {
1191         case 'l':    /* long */
1192         case 's':    /* short */
1193         case 'h':    /* short */
1194         case 'b':    /* char/byte */
1195         case 'c':    /* char/byte */
1196                 l++;
1197                 /*FALLTHROUGH*/
1198         default:
1199                 break;
1200         }
1201
1202         *p = l;
1203 }
1204
1205 /*
1206  * handle a compiled file.
1207  */
1208 private int
1209 apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
1210     const char *fn)
1211 {
1212         int fd;
1213         struct stat st;
1214         uint32_t *ptr;
1215         uint32_t version;
1216         int needsbyteswap;
1217         char buf[MAXPATHLEN];
1218         char *dbname = mkdbname(fn, buf, sizeof(buf), 0);
1219         void *mm = NULL;
1220
1221         if (dbname == NULL)
1222                 return -1;
1223
1224         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
1225                 return -1;
1226
1227         if (fstat(fd, &st) == -1) {
1228                 file_error(ms, errno, "cannot stat `%s'", dbname);
1229                 goto error;
1230         }
1231         if (st.st_size < 16) {
1232                 file_error(ms, 0, "file `%s' is too small", dbname);
1233                 goto error;
1234         }
1235
1236 #ifdef QUICK
1237         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
1238             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
1239                 file_error(ms, errno, "cannot map `%s'", dbname);
1240                 goto error;
1241         }
1242 #define RET     2
1243 #else
1244         if ((mm = malloc((size_t)st.st_size)) == NULL) {
1245                 file_oomem(ms);
1246                 goto error;
1247         }
1248         if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
1249                 file_badread(ms);
1250                 goto error;
1251         }
1252 #define RET     1
1253 #endif
1254         *magicp = mm;
1255         (void)close(fd);
1256         fd = -1;
1257         ptr = (uint32_t *)(void *)*magicp;
1258         if (*ptr != MAGICNO) {
1259                 if (swap4(*ptr) != MAGICNO) {
1260                         file_error(ms, 0, "bad magic in `%s'");
1261                         goto error;
1262                 }
1263                 needsbyteswap = 1;
1264         } else
1265                 needsbyteswap = 0;
1266         if (needsbyteswap)
1267                 version = swap4(ptr[1]);
1268         else
1269                 version = ptr[1];
1270         if (version != VERSIONNO) {
1271                 file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
1272                     version, VERSIONNO, dbname);
1273                 goto error;
1274         }
1275         *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
1276         (*magicp)++;
1277         if (needsbyteswap)
1278                 byteswap(*magicp, *nmagicp);
1279         return RET;
1280
1281 error:
1282         if (fd != -1)
1283                 (void)close(fd);
1284         if (mm) {
1285 #ifdef QUICK
1286                 (void)munmap((void *)mm, (size_t)st.st_size);
1287 #else
1288                 free(mm);
1289 #endif
1290         } else {
1291                 *magicp = NULL;
1292                 *nmagicp = 0;
1293         }
1294         return -1;
1295 }
1296
1297 private const uint32_t ar[] = {
1298     MAGICNO, VERSIONNO
1299 };
1300 /*
1301  * handle an mmaped file.
1302  */
1303 private int
1304 apprentice_compile(struct magic_set *ms, struct magic **magicp,
1305     uint32_t *nmagicp, const char *fn)
1306 {
1307         int fd;
1308         char buf[MAXPATHLEN];
1309         char *dbname = mkdbname(fn, buf, sizeof(buf), 1);
1310
1311         if (dbname == NULL) 
1312                 return -1;
1313
1314         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
1315                 file_error(ms, errno, "cannot open `%s'", dbname);
1316                 return -1;
1317         }
1318
1319         if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
1320                 file_error(ms, errno, "error writing `%s'", dbname);
1321                 return -1;
1322         }
1323
1324         if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
1325             != sizeof(struct magic)) {
1326                 file_error(ms, errno, "error seeking `%s'", dbname);
1327                 return -1;
1328         }
1329
1330         if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) 
1331             != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
1332                 file_error(ms, errno, "error writing `%s'", dbname);
1333                 return -1;
1334         }
1335
1336         (void)close(fd);
1337         return 0;
1338 }
1339
1340 private const char ext[] = ".mgc";
1341 /*
1342  * make a dbname
1343  */
1344 private char *
1345 mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)
1346 {
1347         if (strip) {
1348                 const char *p;
1349                 if ((p = strrchr(fn, '/')) != NULL)
1350                         fn = ++p;
1351         }
1352
1353         (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
1354         return buf;
1355 }
1356
1357 /*
1358  * Byteswap an mmap'ed file if needed
1359  */
1360 private void
1361 byteswap(struct magic *magic, uint32_t nmagic)
1362 {
1363         uint32_t i;
1364         for (i = 0; i < nmagic; i++)
1365                 bs1(&magic[i]);
1366 }
1367
1368 /*
1369  * swap a short
1370  */
1371 private uint16_t
1372 swap2(uint16_t sv)
1373 {
1374         uint16_t rv;
1375         uint8_t *s = (uint8_t *)(void *)&sv; 
1376         uint8_t *d = (uint8_t *)(void *)&rv; 
1377         d[0] = s[1];
1378         d[1] = s[0];
1379         return rv;
1380 }
1381
1382 /*
1383  * swap an int
1384  */
1385 private uint32_t
1386 swap4(uint32_t sv)
1387 {
1388         uint32_t rv;
1389         uint8_t *s = (uint8_t *)(void *)&sv; 
1390         uint8_t *d = (uint8_t *)(void *)&rv; 
1391         d[0] = s[3];
1392         d[1] = s[2];
1393         d[2] = s[1];
1394         d[3] = s[0];
1395         return rv;
1396 }
1397
1398 /*
1399  * byteswap a single magic entry
1400  */
1401 private void
1402 bs1(struct magic *m)
1403 {
1404         m->cont_level = swap2(m->cont_level);
1405         m->offset = swap4((uint32_t)m->offset);
1406         m->in_offset = swap4((uint32_t)m->in_offset);
1407         if (!IS_STRING(m->type))
1408                 m->value.l = swap4(m->value.l);
1409         m->mask = swap4(m->mask);
1410 }