file/src/apprentice.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Ian F. Darwin 1986-1995.
00003  * Software written by Ian F. Darwin and others;
00004  * maintained 1995-present by Christos Zoulas and others.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice immediately at the beginning of the file, without modification,
00011  *    this list of conditions, and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  *  
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00017  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
00020  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00021  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00022  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00023  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00024  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00025  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00026  * SUCH DAMAGE.
00027  */
00028 /*
00029  * apprentice - make one pass through /etc/magic, learning its secrets.
00030  */
00031 
00032 #include "file.h"
00033 #include "magic.h"
00034 #include <stdlib.h>
00035 #ifdef HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif
00038 #include <string.h>
00039 #include <assert.h>
00040 #include <ctype.h>
00041 #include <fcntl.h>
00042 #include <sys/stat.h>
00043 #include <sys/param.h>
00044 #ifdef QUICK
00045 #include <sys/mman.h>
00046 #endif
00047 
00048 #ifndef lint
00049 FILE_RCSID("@(#)$File: apprentice.c,v 1.104 2007/01/19 19:54:39 christos Exp $")
00050 #endif  /* lint */
00051 
00052 #define EATAB {while (isascii((unsigned char) *l) && \
00053                       isspace((unsigned char) *l))  ++l;}
00054 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
00055                         tolower((unsigned char) (l)) : (l))
00056 /*
00057  * Work around a bug in headers on Digital Unix.
00058  * At least confirmed for: OSF1 V4.0 878
00059  */
00060 #if defined(__osf__) && defined(__DECC)
00061 #ifdef MAP_FAILED
00062 #undef MAP_FAILED
00063 #endif
00064 #endif
00065 
00066 #ifndef MAP_FAILED
00067 #define MAP_FAILED (void *) -1
00068 #endif
00069 
00070 #ifndef MAP_FILE
00071 #define MAP_FILE 0
00072 #endif
00073 
00074 #ifndef MAXPATHLEN
00075 #define MAXPATHLEN      1024
00076 #endif
00077 
00078 struct magic_entry {
00079         struct magic *mp;       
00080         uint32_t cont_count;
00081         uint32_t max_count;
00082 };
00083     
00084 /*@unchecked@*/ /*@observer@*/
00085 int file_formats[FILE_NAMES_SIZE];
00086 /*@unchecked@*/
00087 const size_t file_nformats = FILE_NAMES_SIZE;
00088 /*@unchecked@*/ /*@observer@*/
00089 const char *file_names[FILE_NAMES_SIZE];
00090 /*@unchecked@*/
00091 const size_t file_nnames = FILE_NAMES_SIZE;
00092 
00093 /*@unchecked@*/
00094 private size_t maxmagic = 0;
00095 /*@unchecked@*/
00096 private size_t magicsize = sizeof(struct magic);
00097 
00098 private int getvalue(struct magic_set *ms, struct magic *m, const char **p,
00099     int action)
00100         /*@globals fileSystem @*/
00101         /*@modifies ms, m, *p, fileSystem @*/;
00102 private int hextoint(int c)
00103         /*@*/;
00104 /*@observer@*/ /*@null@*/
00105 private const char * getstr(struct magic_set *ms, const char *s, char *p,
00106     int plen, int *slen, int action)
00107         /*@globals fileSystem @*/
00108         /*@modifies ms, *p, *slen, fileSystem @*/;
00109 private int parse(struct magic_set *ms, struct magic_entry **mentryp,
00110     uint32_t *nmentryp, const char *line, size_t lineno, int action)
00111         /*@globals maxmagic, fileSystem @*/
00112         /*@modifies ms, *mentryp, *nmentryp, maxmagic, fileSystem @*/;
00113 private void eatsize(const char **p)
00114         /*@modifies *p @*/;
00115 private int apprentice_1(struct magic_set *ms, const char *fn, int action,
00116     struct mlist *mlist)
00117         /*@globals fileSystem, internalState @*/
00118         /*@modifies ms, mlist, fileSystem, internalState @*/;
00119 private size_t apprentice_magic_strength(const struct magic *m)
00120         /*@globals fileSystem @*/
00121         /*@modifies fileSystem @*/;
00122 private int apprentice_sort(const void *a, const void *b)
00123         /*@globals fileSystem @*/
00124         /*@modifies fileSystem @*/;
00125 private int apprentice_file(struct magic_set *ms, struct magic **magicp,
00126     uint32_t *nmagicp, const char *fn, int action)
00127         /*@globals maxmagic, fileSystem @*/
00128         /*@modifies ms, *magicp, *nmagicp, maxmagic, fileSystem @*/;
00129 private void byteswap(struct magic *magic, uint32_t nmagic)
00130         /*@modifies magic @*/;
00131 private void bs1(struct magic *m)
00132         /*@modifies m @*/;
00133 private uint16_t swap2(uint16_t sv)
00134         /*@*/;
00135 private uint32_t swap4(uint32_t sv)
00136         /*@*/;
00137 private uint64_t swap8(uint64_t sv)
00138         /*@*/;
00139 private char * mkdbname(const char *fn, /*@returned@*/ char *buf, size_t bufsiz, int strip)
00140         /*@modifies buf @*/;
00141 private int apprentice_map(struct magic_set *ms, struct magic **magicp,
00142     uint32_t *nmagicp, const char *fn)
00143         /*@globals fileSystem, internalState @*/
00144         /*@modifies ms, *magicp, *nmagicp, fileSystem, internalState @*/;
00145 private int apprentice_compile(struct magic_set *ms, struct magic **magicp,
00146     uint32_t *nmagicp, const char *fn)
00147         /*@globals fileSystem, internalState @*/
00148         /*@modifies ms, *magicp, *nmagicp, fileSystem, internalState @*/;
00149 private int check_format_type(const char *ptr, int type)
00150         /*@*/;
00151 private int check_format(struct magic_set *ms, struct magic *m)
00152         /*@modifies ms @*/;
00153 
00154 #ifdef COMPILE_ONLY
00155 
00156 int main(int, char *[]);
00157 
00158 int
00159 main(int argc, char *argv[])
00160 {
00161         int ret;
00162         struct magic_set *ms;
00163         char *progname;
00164 
00165         if ((progname = strrchr(argv[0], '/')) != NULL)
00166                 progname++;
00167         else
00168                 progname = argv[0];
00169 
00170         if (argc != 2) {
00171                 (void)fprintf(stderr, "Usage: %s file\n", progname);
00172                 return 1;
00173         }
00174 
00175         if ((ms = magic_open(MAGIC_CHECK)) == NULL) {
00176                 (void)fprintf(stderr, "%s: %s\n", progname, strerror(errno));
00177                 return 1;
00178         }
00179         ret = magic_compile(ms, argv[1]) == -1 ? 1 : 0;
00180         if (ret == 1)
00181                 (void)fprintf(stderr, "%s: %s\n", progname, magic_error(ms));
00182         magic_close(ms);
00183         return ret;
00184 }
00185 #endif /* COMPILE_ONLY */
00186 
00187 /*@unchecked@*/ /*@observer@*/
00188 static const struct type_tbl_s {
00189 /*@observer@*/ /*@relnull@*/
00190         const char *name;
00191         const size_t len;
00192         const int type;
00193         const int format;
00194 } type_tbl[] = {
00195 # define XX(s)          s, (sizeof(s) - 1)
00196 # define XX_NULL        NULL, 0
00197         { XX("byte"),           FILE_BYTE,              FILE_FMT_NUM },
00198         { XX("short"),          FILE_SHORT,             FILE_FMT_NUM },
00199         { XX("default"),        FILE_DEFAULT,           FILE_FMT_STR },
00200         { XX("long"),           FILE_LONG,              FILE_FMT_NUM },
00201         { XX("string"),         FILE_STRING,            FILE_FMT_STR },
00202         { XX("date"),           FILE_DATE,              FILE_FMT_STR },
00203         { XX("beshort"),        FILE_BESHORT,           FILE_FMT_NUM },
00204         { XX("belong"),         FILE_BELONG,            FILE_FMT_NUM },
00205         { XX("bedate"),         FILE_BEDATE,            FILE_FMT_STR },
00206         { XX("leshort"),        FILE_LESHORT,           FILE_FMT_NUM },
00207         { XX("lelong"),         FILE_LELONG,            FILE_FMT_NUM },
00208         { XX("ledate"),         FILE_LEDATE,            FILE_FMT_STR },
00209         { XX("pstring"),        FILE_PSTRING,           FILE_FMT_STR },
00210         { XX("ldate"),          FILE_LDATE,             FILE_FMT_STR },
00211         { XX("beldate"),        FILE_BELDATE,           FILE_FMT_STR },
00212         { XX("leldate"),        FILE_LELDATE,           FILE_FMT_STR },
00213         { XX("regex"),          FILE_REGEX,             FILE_FMT_STR },
00214         { XX("bestring16"),     FILE_BESTRING16,        FILE_FMT_STR },
00215         { XX("lestring16"),     FILE_LESTRING16,        FILE_FMT_STR },
00216         { XX("search"),         FILE_SEARCH,            FILE_FMT_STR },
00217         { XX("medate"),         FILE_MEDATE,            FILE_FMT_STR },
00218         { XX("meldate"),        FILE_MELDATE,           FILE_FMT_STR },
00219         { XX("melong"),         FILE_MELONG,            FILE_FMT_NUM },
00220         { XX("quad"),           FILE_QUAD,              FILE_FMT_QUAD },
00221         { XX("lequad"),         FILE_LEQUAD,            FILE_FMT_QUAD },
00222         { XX("bequad"),         FILE_BEQUAD,            FILE_FMT_QUAD },
00223         { XX("qdate"),          FILE_QDATE,             FILE_FMT_STR },
00224         { XX("leqdate"),        FILE_LEQDATE,           FILE_FMT_STR },
00225         { XX("beqdate"),        FILE_BEQDATE,           FILE_FMT_STR },
00226         { XX("qldate"),         FILE_QLDATE,            FILE_FMT_STR },
00227         { XX("leqldate"),       FILE_LEQLDATE,          FILE_FMT_STR },
00228         { XX("beqldate"),       FILE_BEQLDATE,          FILE_FMT_STR },
00229         { XX_NULL,              FILE_INVALID,           FILE_FMT_NONE },
00230 # undef XX
00231 # undef XX_NULL
00232 };
00233 
00234 private int
00235 get_type(const char *l, const char **t)
00236         /*@modifies *t @*/
00237 {
00238         const struct type_tbl_s *p;
00239 
00240         for (p = type_tbl; p->name; p++) {
00241                 if (strncmp(l, p->name, p->len) == 0) {
00242                         if (t)
00243                                 *t = l + p->len;
00244                         break;
00245                 }
00246         }
00247         return p->type;
00248 }
00249 
00250 private void
00251 init_file_tables(void)
00252         /*@globals file_names, file_formats @*/
00253         /*@modifies file_names, file_formats @*/
00254 {
00255         static int done = 0;
00256         const struct type_tbl_s *p;
00257 
00258         if (done)
00259                 return;
00260         done++;
00261 
00262 /*@-dependenttrans@*/
00263         for (p = type_tbl; p->name; p++) {
00264                 assert(p->type < FILE_NAMES_SIZE);
00265                 file_names[p->type] = p->name;
00266                 file_formats[p->type] = p->format;
00267         }
00268 /*@=dependenttrans@*/
00269 }
00270 
00271 /*
00272  * Handle one file.
00273  */
00274 private int
00275 apprentice_1(struct magic_set *ms, const char *fn, int action,
00276     struct mlist *mlist)
00277 {
00278         struct magic *magic = NULL;
00279         uint32_t nmagic = 0;
00280         struct mlist *ml;
00281         int rv = -1;
00282         int mapped;
00283 
00284         if (magicsize != FILE_MAGICSIZE) {
00285                 file_error(ms, 0, "magic element size %lu != %lu",
00286                     (unsigned long)sizeof(*magic),
00287                     (unsigned long)FILE_MAGICSIZE);
00288                 return -1;
00289         }
00290 
00291         if (action == FILE_COMPILE) {
00292                 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
00293                 if (rv != 0)
00294                         return -1;
00295                 rv = apprentice_compile(ms, &magic, &nmagic, fn);
00296                 free(magic);
00297                 return rv;
00298         }
00299 #ifndef COMPILE_ONLY
00300         if ((rv = apprentice_map(ms, &magic, &nmagic, fn)) == -1) {
00301                 if (ms->flags & MAGIC_CHECK)
00302                         file_magwarn(ms, "using regular magic file `%s'", fn);
00303                 rv = apprentice_file(ms, &magic, &nmagic, fn, action);
00304                 if (rv != 0)
00305                         return -1;
00306                 mapped = 0;
00307         }
00308 
00309         mapped = rv;
00310              
00311         if (magic == NULL || nmagic == 0) {
00312                 file_delmagic(magic, mapped, nmagic);
00313                 return -1;
00314         }
00315 
00316         if ((ml = malloc(sizeof(*ml))) == NULL) {
00317                 file_delmagic(magic, mapped, nmagic);
00318                 file_oomem(ms, sizeof(*ml));
00319                 return -1;
00320         }
00321 
00322         ml->magic = magic;
00323         ml->nmagic = nmagic;
00324         ml->mapped = mapped;
00325 
00326         mlist->prev->next = ml;
00327         ml->prev = mlist->prev;
00328         ml->next = mlist;
00329         mlist->prev = ml;
00330 
00331         return 0;
00332 #endif /* COMPILE_ONLY */
00333 }
00334 
00335 protected void
00336 file_delmagic(struct magic *p, int type, size_t entries)
00337 {
00338         if (p == NULL)
00339                 return;
00340         switch (type) {
00341         case 2:
00342                 p--;
00343                 (void)munmap((void *)p, sizeof(*p) * (entries + 1));
00344                 break;
00345         case 1:
00346                 p--;
00347                 /*@fallthrough@*/
00348         case 0:
00349                 free(p);
00350                 break;
00351         default:
00352                 abort();
00353         }
00354 }
00355 
00356 
00357 /* const char *fn: list of magic files */
00358 protected struct mlist *
00359 file_apprentice(struct magic_set *ms, const char *fn, int action)
00360 {
00361         char *p, *mfn, *afn = NULL;
00362         int file_err, errs = -1;
00363         struct mlist *mlist;
00364         static const char mime[] = ".mime";
00365 
00366         init_file_tables();
00367 
00368         if (fn == NULL)
00369                 fn = getenv("MAGIC");
00370         if (fn == NULL)
00371                 fn = MAGIC;
00372 
00373         if ((fn = mfn = strdup(fn)) == NULL) {
00374                 file_oomem(ms, strlen(fn));
00375                 return NULL;
00376         }
00377 
00378         if ((mlist = malloc(sizeof(*mlist))) == NULL) {
00379                 free(mfn);
00380                 file_oomem(ms, sizeof(*mlist));
00381                 return NULL;
00382         }
00383         mlist->next = mlist->prev = mlist;
00384 
00385         while (fn) {
00386                 p = strchr(fn, PATHSEP);
00387                 if (p)
00388                         *p++ = '\0';
00389                 if (*fn == '\0')
00390                         break;
00391                 if (ms->flags & MAGIC_MIME) {
00392                         size_t len = strlen(fn) + sizeof(mime);
00393                         if ((afn = malloc(len)) == NULL) {
00394                                 free(mfn);
00395                                 free(mlist);
00396                                 file_oomem(ms, len);
00397                                 return NULL;
00398                         }
00399                         (void)strcpy(afn, fn);
00400                         (void)strcat(afn, mime);
00401                         fn = afn;
00402                 }
00403                 file_err = apprentice_1(ms, fn, action, mlist);
00404                 if (file_err > errs)
00405                         errs = file_err;
00406                 if (afn) {
00407                         free(afn);
00408                         afn = NULL;
00409                 }
00410                 fn = p;
00411         }
00412         if (errs == -1) {
00413                 free(mfn);
00414                 free(mlist);
00415                 mlist = NULL;
00416                 file_error(ms, 0, "could not find any magic files!");
00417                 return NULL;
00418         }
00419         free(mfn);
00420         return mlist;
00421 }
00422 
00423 /*
00424  * Get weight of this magic entry, for sorting purposes.
00425  */
00426 private size_t
00427 apprentice_magic_strength(const struct magic *m)
00428 {
00429 #define MULT 10
00430         size_t val = 2 * MULT;  /* baseline strength */
00431 
00432         switch (m->type) {
00433         case FILE_DEFAULT:      /* make sure this sorts last */
00434                 return 0;
00435 
00436         case FILE_BYTE:
00437                 val += 1 * MULT;
00438                 break;
00439 
00440         case FILE_SHORT:
00441         case FILE_LESHORT:
00442         case FILE_BESHORT:
00443                 val += 2 * MULT;
00444                 break;
00445 
00446         case FILE_LONG:
00447         case FILE_LELONG:
00448         case FILE_BELONG:
00449         case FILE_MELONG:
00450                 val += 4 * MULT;
00451                 break;
00452 
00453         case FILE_PSTRING:
00454         case FILE_STRING:
00455                 val += m->vallen * MULT;
00456                 break;
00457 
00458         case FILE_BESTRING16:
00459         case FILE_LESTRING16:
00460                 val += m->vallen * MULT / 2;
00461                 break;
00462 
00463         case FILE_SEARCH:
00464         case FILE_REGEX:
00465                 val += m->vallen;
00466                 break;
00467 
00468         case FILE_DATE:
00469         case FILE_LEDATE:
00470         case FILE_BEDATE:
00471         case FILE_MEDATE:
00472         case FILE_LDATE:
00473         case FILE_LELDATE:
00474         case FILE_BELDATE:
00475         case FILE_MELDATE:
00476                 val += 4 * MULT;
00477                 break;
00478 
00479         case FILE_QUAD:
00480         case FILE_BEQUAD:
00481         case FILE_LEQUAD:
00482         case FILE_QDATE:
00483         case FILE_LEQDATE:
00484         case FILE_BEQDATE:
00485         case FILE_QLDATE:
00486         case FILE_LEQLDATE:
00487         case FILE_BEQLDATE:
00488                 val += 8 * MULT;
00489                 break;
00490 
00491         default:
00492                 val = 0;
00493                 (void)fprintf(stderr, "Bad type %d\n", m->type);
00494                 abort();
00495         }
00496 
00497         switch (m->reln) {
00498         case 'x':       /* matches anything penalize */
00499                 val = 0;
00500                 break;
00501 
00502         case '!':
00503         case '=':       /* Exact match, prefer */
00504                 val += MULT;
00505                 break;
00506 
00507         case '>':
00508         case '<':       /* comparison match reduce strength */
00509                 val -= 2 * MULT;
00510                 break;
00511 
00512         case '^':
00513         case '&':       /* masking bits, we could count them too */
00514                 val -= MULT;
00515                 break;
00516 
00517         default:
00518                 (void)fprintf(stderr, "Bad relation %c\n", m->reln);
00519                 abort();
00520         }
00521 
00522         if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
00523                 val = 1;
00524 
00525         return val;
00526 }
00527 
00528 /*  
00529  * Sort callback for sorting entries by "strength" (basically length)
00530  */
00531 private int
00532 apprentice_sort(const void *a, const void *b)
00533 {
00534         const struct magic_entry *ma = a;
00535         const struct magic_entry *mb = b;
00536         size_t sa = apprentice_magic_strength(ma->mp);
00537         size_t sb = apprentice_magic_strength(mb->mp);
00538         if (sa == sb)
00539                 return 0;
00540         else if (sa > sb)
00541                 return -1;
00542         else
00543                 return 1;
00544 }
00545 
00546 /*
00547  * parse from a file
00548  * const char *fn: name of magic file
00549  */
00550 private int
00551 apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
00552     const char *fn, int action)
00553 {
00554         private const char hdr[] =
00555                 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
00556         FILE *f;
00557         char line[BUFSIZ+1];
00558         int errs = 0;
00559         struct magic_entry *marray;
00560         uint32_t marraycount, i, mentrycount = 0;
00561         size_t lineno = 0;
00562 
00563         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
00564 
00565         f = fopen(ms->file = fn, "r");
00566         if (f == NULL) {
00567                 if (errno != ENOENT)
00568                         file_error(ms, errno, "cannot read magic file `%s'",
00569                             fn);
00570                 return -1;
00571         }
00572 
00573         maxmagic = MAXMAGIS;
00574         if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
00575                 (void)fclose(f);
00576                 file_oomem(ms, maxmagic * sizeof(*marray));
00577                 return -1;
00578         }
00579         marraycount = 0;
00580 
00581         /* print silly verbose header for USG compat. */
00582         if (action == FILE_CHECK)
00583                 (void)fprintf(stderr, "%s\n", hdr);
00584 
00585         /* read and parse this file */
00586         for (ms->line = 1; fgets(line, BUFSIZ, f) != NULL; ms->line++) {
00587                 size_t len;
00588                 len = strlen(line);
00589                 if (len == 0) /* null line, garbage, etc */
00590                         continue;
00591                 if (line[len - 1] == '\n') {
00592                         lineno++;
00593                 line[len - 1] = '\0'; /* delete newline */
00594                 }
00595                 if (line[0] == '\0')    /* empty, do not parse */
00596                         continue;
00597                 if (line[0] == '#')     /* comment, do not parse */
00598                         continue;
00599                 if (parse(ms, &marray, &marraycount, line, lineno, action) != 0)
00600                         errs++;
00601         }
00602 
00603         (void)fclose(f);
00604         if (errs)
00605                 goto out;
00606 
00607 #ifndef NOORDER
00608         qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
00609         /*
00610          * Make sure that any level 0 "default" line is last (if one exists).
00611          */
00612         for (i = 0; i < marraycount; i++) {
00613                 if (marray[i].mp->cont_level == 0 &&
00614                     marray[i].mp->type == FILE_DEFAULT) {
00615                         while (++i < marraycount)
00616                                 if (marray[i].mp->cont_level == 0)
00617                                         /*@innerbreak@*/ break;
00618                         if (i != marraycount) {
00619                                 ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
00620                                 file_magwarn(ms,
00621                                     "level 0 \"default\" did not sort last");
00622                         }
00623                         break;                                      
00624                 }
00625         }
00626 #endif
00627 
00628         for (i = 0; i < marraycount; i++)
00629                 mentrycount += marray[i].cont_count;
00630 
00631         if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) {
00632                 file_oomem(ms, sizeof(**magicp) * mentrycount);
00633                 errs++;
00634                 goto out;
00635         }
00636 
00637         mentrycount = 0;
00638         for (i = 0; i < marraycount; i++) {
00639                 (void)memcpy(*magicp + mentrycount, marray[i].mp,
00640                     marray[i].cont_count * sizeof(**magicp));
00641                 mentrycount += marray[i].cont_count;
00642         }
00643 out:
00644         for (i = 0; i < marraycount; i++)
00645                 free(marray[i].mp);
00646         free(marray);
00647         if (errs) {
00648                 *magicp = NULL;
00649                 *nmagicp = 0;
00650         return errs;
00651         } else {
00652                 *nmagicp = mentrycount;
00653                 return 0;
00654         }
00655 
00656 }
00657 
00658 /*
00659  * extend the sign bit if the comparison is to be signed
00660  */
00661 protected uint64_t
00662 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
00663 {
00664         if (!(m->flag & UNSIGNED)) {
00665                 switch(m->type) {
00666                 /*
00667                  * Do not remove the casts below.  They are
00668                  * vital.  When later compared with the data,
00669                  * the sign extension must have happened.
00670                  */
00671                 case FILE_BYTE:
00672                         v = (char) v;
00673                         break;
00674                 case FILE_SHORT:
00675                 case FILE_BESHORT:
00676                 case FILE_LESHORT:
00677                         v = (short) v;
00678                         break;
00679                 case FILE_DATE:
00680                 case FILE_BEDATE:
00681                 case FILE_LEDATE:
00682                 case FILE_MEDATE:
00683                 case FILE_LDATE:
00684                 case FILE_BELDATE:
00685                 case FILE_LELDATE:
00686                 case FILE_MELDATE:
00687                 case FILE_LONG:
00688                 case FILE_BELONG:
00689                 case FILE_LELONG:
00690                 case FILE_MELONG:
00691                         v = (int32_t) v;
00692                         break;
00693                 case FILE_QUAD:
00694                 case FILE_BEQUAD:
00695                 case FILE_LEQUAD:
00696                 case FILE_QDATE:
00697                 case FILE_QLDATE:
00698                 case FILE_BEQDATE:
00699                 case FILE_BEQLDATE:
00700                 case FILE_LEQDATE:
00701                 case FILE_LEQLDATE:
00702                         v = (int64_t) v;
00703                         break;
00704                 case FILE_STRING:
00705                 case FILE_PSTRING:
00706                 case FILE_BESTRING16:
00707                 case FILE_LESTRING16:
00708                 case FILE_REGEX:
00709                 case FILE_SEARCH:
00710                 case FILE_DEFAULT:
00711                         break;
00712                 default:
00713                         if (ms->flags & MAGIC_CHECK)
00714                             file_magwarn(ms, "cannot happen: m->type=%d\n",
00715                                     m->type);
00716                         return ~0U;
00717                 }
00718         }
00719         return v;
00720 }
00721 
00722 private int
00723 string_modifier_check(struct magic_set *ms, struct magic const *m)
00724         /*@globals fileSystem @*/
00725         /*@modifies ms, fileSystem @*/
00726 {
00727         if ((ms->flags & MAGIC_CHECK) == 0)
00728                 return 0;
00729 
00730         switch (m->type) {
00731         case FILE_BESTRING16:
00732         case FILE_LESTRING16:
00733                 if (m->str_flags != 0) {
00734                         file_magwarn(ms, "no modifiers allowed for 16-bit strings\n");
00735                         return -1;
00736                 }
00737                 break;
00738         case FILE_STRING:
00739         case FILE_PSTRING:
00740                 if ((m->str_flags & REGEX_OFFSET_START) != 0) {
00741                         file_magwarn(ms, "'/%c' only allowed on regex and search\n",
00742                             CHAR_REGEX_OFFSET_START);
00743                         return -1;
00744                 }
00745                 break;
00746         case FILE_SEARCH:
00747                 break;
00748         case FILE_REGEX:
00749                 if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
00750                         file_magwarn(ms, "'/%c' not allowed on regex\n",
00751                             CHAR_COMPACT_BLANK);
00752                         return -1;
00753                 }
00754                 if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
00755                         file_magwarn(ms, "'/%c' not allowed on regex\n",
00756                             CHAR_COMPACT_OPTIONAL_BLANK);
00757                         return -1;
00758                 }
00759                 break;
00760         default:
00761                 file_magwarn(ms, "coding error: m->type=%d\n",
00762                     m->type);
00763                 return -1;
00764         }
00765         return 0;
00766 }
00767 
00768 private int
00769 get_op(char c)
00770         /*@*/
00771 {
00772         switch (c) {
00773         case '&':
00774                 return FILE_OPAND;
00775         case '|':
00776                 return FILE_OPOR;
00777         case '^':
00778                 return FILE_OPXOR;
00779         case '+':
00780                 return FILE_OPADD;
00781         case '-':
00782                 return FILE_OPMINUS;
00783         case '*':
00784                 return FILE_OPMULTIPLY;
00785         case '/':
00786                 return FILE_OPDIVIDE;
00787         case '%':
00788                 return FILE_OPMODULO;
00789         default:
00790                 return -1;
00791         }
00792 }
00793 
00794 #ifdef ENABLE_CONDITIONALS
00795 private int
00796 get_cond(const char *l, const char **t)
00797         /*@modifies *t @*/
00798 {
00799         /*@observer@*/
00800         static struct cond_tbl_s {
00801         /*@observer@*/ /*@null@*/
00802                 const char *name;
00803                 const size_t len;
00804                 const int cond;
00805         } cond_tbl[] = {
00806                 { "if",         2,      COND_IF },
00807                 { "elif",       4,      COND_ELIF },
00808                 { "else",       4,      COND_ELSE },
00809                 { NULL,         0,      COND_NONE },
00810         };
00811         struct cond_tbl_s *p;
00812 
00813         for (p = cond_tbl; p->name; p++) {
00814                 if (strncmp(l, p->name, p->len) == 0 &&
00815                     isspace((unsigned char)l[p->len])) {
00816                         if (t)
00817                                 *t = l + p->len;
00818                         break;
00819                 }
00820         }
00821         return p->cond;
00822 }
00823 
00824 private int
00825 check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
00826         /*@globals fileSystem @*/
00827         /*@modifies ms, fileSystem @*/
00828 {
00829         int last_cond;
00830         last_cond = ms->c.li[cont_level].last_cond;
00831 
00832         switch (cond) {
00833         case COND_IF:
00834                 if (last_cond != COND_NONE && last_cond != COND_ELIF) {
00835                         if (ms->flags & MAGIC_CHECK)
00836                                 file_magwarn(ms, "syntax error: `if'");
00837                         return -1;
00838                 }
00839                 last_cond = COND_IF;
00840                 break;
00841 
00842         case COND_ELIF:
00843                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
00844                         if (ms->flags & MAGIC_CHECK)
00845                                 file_magwarn(ms, "syntax error: `elif'");
00846                         return -1;
00847                 }
00848                 last_cond = COND_ELIF;
00849                 break;
00850 
00851         case COND_ELSE:
00852                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
00853                         if (ms->flags & MAGIC_CHECK)
00854                                 file_magwarn(ms, "syntax error: `else'");
00855                         return -1;
00856                 }
00857                 last_cond = COND_NONE;
00858                 break;
00859 
00860         case COND_NONE:
00861                 last_cond = COND_NONE;
00862                 break;
00863         }
00864 
00865         ms->c.li[cont_level].last_cond = last_cond;
00866         return 0;
00867 }
00868 #endif /* ENABLE_CONDITIONALS */
00869 
00870 /*
00871  * parse one line from magic file, put into magic[index++] if valid
00872  */
00873 private int
00874 parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, 
00875     const char *line, size_t lineno, int action)
00876 {
00877 #ifdef ENABLE_CONDITIONALS
00878         static uint32_t last_cont_level = 0;
00879 #endif
00880         size_t i;
00881         struct magic_entry *me;
00882         struct magic *m;
00883         const char *l = line;
00884         char *t;
00885         int op;
00886         uint32_t cont_level;
00887 
00888         cont_level = 0;
00889 
00890         while (*l == '>') {
00891                 ++l;            /* step over */
00892                 cont_level++; 
00893         }
00894 #ifdef ENABLE_CONDITIONALS
00895         if (cont_level == 0 || cont_level > last_cont_level)
00896                 if (file_check_mem(ms, cont_level) == -1)
00897                         return -1;
00898         last_cont_level = cont_level;
00899 #endif
00900 
00901 #define ALLOC_CHUNK     (size_t)10
00902 #define ALLOC_INCR      (size_t)200
00903 
00904         if (cont_level != 0) {
00905                 if (*nmentryp == 0) {
00906                         file_error(ms, 0, "No current entry for continuation");
00907                         return -1;
00908                 }
00909                 me = &(*mentryp)[*nmentryp - 1];
00910                 if (me->cont_count == me->max_count) {
00911                         struct magic *nm;
00912                         size_t cnt = me->max_count + ALLOC_CHUNK;
00913                         if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) {
00914                                 file_oomem(ms, sizeof(*nm) * cnt);
00915                                 return -1;
00916                         }
00917                         me->mp = m = nm;
00918                         me->max_count = cnt;
00919                 }
00920                 m = &me->mp[me->cont_count++];
00921                 (void)memset(m, 0, sizeof(*m));
00922                 m->cont_level = cont_level;
00923         } else {
00924                 if (*nmentryp == maxmagic) {
00925                         struct magic_entry *mp;
00926 
00927                 maxmagic += ALLOC_INCR;
00928 /*@i@*/                 if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) ==
00929                             NULL) {
00930                                 file_oomem(ms, sizeof(*mp) * maxmagic);
00931                         return -1;
00932                 }
00933                         (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
00934                             ALLOC_INCR);
00935                         *mentryp = mp;
00936                 }
00937                 me = &(*mentryp)[*nmentryp];
00938                 if (me->mp == NULL) {
00939                         if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) {
00940                                 file_oomem(ms, sizeof(*m) * ALLOC_CHUNK);
00941                                 return -1;
00942         }
00943                         me->mp = m;
00944                         me->max_count = ALLOC_CHUNK;
00945                 } else
00946                         m = me->mp;
00947                 (void)memset(m, 0, sizeof(*m));
00948         m->cont_level = 0;
00949                 me->cont_count = 1;
00950         }
00951         m->lineno = lineno;
00952 
00953         if (*l == '&') {  /* m->cont_level == 0 checked below. */
00954                 ++l;            /* step over */
00955                 m->flag |= OFFADD;
00956         }
00957         if (*l == '(') {
00958                 ++l;            /* step over */
00959                 m->flag |= INDIR;
00960                 if (m->flag & OFFADD)
00961                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
00962 
00963                 if (*l == '&') {  /* m->cont_level == 0 checked below */
00964                 ++l;            /* step over */
00965                 m->flag |= OFFADD;
00966         }
00967         }
00968         /* Indirect offsets are not valid at level 0. */
00969         if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
00970                 if (ms->flags & MAGIC_CHECK)
00971                         file_magwarn(ms, "relative offset at level 0");
00972 
00973         /* get offset, then skip over it */
00974         m->offset = (uint32_t)strtoul(l, &t, 0);
00975         if (l == t)
00976                 if (ms->flags & MAGIC_CHECK)
00977                         file_magwarn(ms, "offset `%s' invalid", l);
00978         l = t;
00979 
00980         if (m->flag & INDIR) {
00981                 m->in_type = FILE_LONG;
00982                 m->in_offset = 0;
00983                 /*
00984                  * read [.lbs][+-]nnnnn)
00985                  */
00986                 if (*l == '.') {
00987                         l++;
00988                         switch (*l) {
00989                         case 'l':
00990                                 m->in_type = FILE_LELONG;
00991                                 break;
00992                         case 'L':
00993                                 m->in_type = FILE_BELONG;
00994                                 break;
00995                         case 'm':
00996                                 m->in_type = FILE_MELONG;
00997                                 break;
00998                         case 'h':
00999                         case 's':
01000                                 m->in_type = FILE_LESHORT;
01001                                 break;
01002                         case 'H':
01003                         case 'S':
01004                                 m->in_type = FILE_BESHORT;
01005                                 break;
01006                         case 'c':
01007                         case 'b':
01008                         case 'C':
01009                         case 'B':
01010                                 m->in_type = FILE_BYTE;
01011                                 break;
01012                         default:
01013                                 if (ms->flags & MAGIC_CHECK)
01014