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                                         file_magwarn(ms,
01015                                             "indirect offset type `%c' invalid",
01016                                             *l);
01017                                 break;
01018                         }
01019                         l++;
01020                 }
01021 
01022                 m->in_op = 0;
01023                 if (*l == '~') {
01024                         m->in_op |= FILE_OPINVERSE;
01025                         l++;
01026                 }
01027                 if ((op = get_op(*l)) != -1) {
01028                         m->in_op |= op;
01029                         l++;
01030                 }
01031                 if (*l == '(') {
01032                         m->in_op |= FILE_OPINDIRECT;
01033                         l++;
01034                 }
01035                 if (isdigit((unsigned char)*l) || *l == '-') {
01036                         m->in_offset = (int32_t)strtol(l, &t, 0);
01037                         if (l == t)
01038                         if (ms->flags & MAGIC_CHECK)
01039                                 file_magwarn(ms,
01040                                             "in_offset `%s' invalid", l);
01041                 l = t;
01042         }
01043                 if (*l++ != ')' || 
01044                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
01045                         if (ms->flags & MAGIC_CHECK)
01046                                 file_magwarn(ms,
01047                                     "missing ')' in indirect offset");
01048         }
01049         EATAB;
01050 
01051 #ifdef ENABLE_CONDITIONALS
01052         m->cond = get_cond(l, &l);
01053         if (check_cond(ms, m->cond, cont_level) == -1)
01054                 return -1;
01055 
01056         EATAB;
01057 #endif
01058 
01059         if (*l == 'u') {
01060                 ++l;
01061                 m->flag |= UNSIGNED;
01062         }
01063 
01064         m->type = get_type(l, &l);
01065         if (m->type == FILE_INVALID) {
01066                 if (ms->flags & MAGIC_CHECK)
01067                         file_magwarn(ms, "type `%s' invalid", l);
01068                 return -1;
01069         }
01070 
01071         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
01072         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
01073 
01074         m->mask_op = 0;
01075         if (*l == '~') {
01076                 if (!IS_STRING(m->type))
01077                         m->mask_op |= FILE_OPINVERSE;
01078                 else if (ms->flags & MAGIC_CHECK)
01079                         file_magwarn(ms, "'~' invalid for string types");
01080                 ++l;
01081         }
01082         m->str_count = 0;
01083         m->str_flags = 0;
01084         m->num_mask = 0;
01085         if ((op = get_op(*l)) != -1) {
01086                 if (!IS_STRING(m->type)) {
01087                         uint64_t val;
01088                         ++l;
01089                         m->mask_op |= op;
01090                         val = (uint64_t)strtoull(l, &t, 0);
01091                         l = t;
01092                         m->num_mask = file_signextend(ms, m, val);
01093                         eatsize(&l);
01094                 }
01095                 else if (op == FILE_OPDIVIDE) {
01096                         int have_count = 0;
01097                         while (!isspace((unsigned char)*++l)) {
01098                                 switch (*l) {
01099                                 /* for portability avoid "case '0' ... '9':" */
01100                                 case '0':  case '1':  case '2':
01101                                 case '3':  case '4':  case '5':
01102                                 case '6':  case '7':  case '8':
01103                                 case '9': {
01104                                         if (have_count && ms->flags & MAGIC_CHECK)
01105                                                 file_magwarn(ms,
01106                                                     "multiple counts");
01107                                         have_count = 1;
01108                                         m->str_count = strtoul(l, &t, 0);
01109                                         l = t - 1;
01110                                         /*@switchbreak@*/ break;
01111                                 }
01112                                 case CHAR_COMPACT_BLANK:
01113                                         m->str_flags |= STRING_COMPACT_BLANK;
01114                                         /*@switchbreak@*/ break;
01115                                 case CHAR_COMPACT_OPTIONAL_BLANK:
01116                                         m->str_flags |=
01117                                             STRING_COMPACT_OPTIONAL_BLANK;
01118                                         /*@switchbreak@*/ break;
01119                                 case CHAR_IGNORE_LOWERCASE:
01120                                         m->str_flags |= STRING_IGNORE_LOWERCASE;
01121                                         /*@switchbreak@*/ break;
01122                                 case CHAR_IGNORE_UPPERCASE:
01123                                         m->str_flags |= STRING_IGNORE_UPPERCASE;
01124                                         /*@switchbreak@*/ break;
01125                                 case CHAR_REGEX_OFFSET_START:
01126                                         m->str_flags |= REGEX_OFFSET_START;
01127                                         /*@switchbreak@*/ break;
01128                                 default:
01129                                         if (ms->flags & MAGIC_CHECK)
01130                                                 file_magwarn(ms,
01131                                                 "string extension `%c' invalid",
01132                                                 *l);
01133                                         return -1;
01134                                 }
01135                                 /* allow multiple '/' for readability */
01136                                 if (l[1] == '/' && !isspace((unsigned char)l[2]))
01137                                         l++;
01138                         }
01139                         if (string_modifier_check(ms, m) == -1)
01140                                 return -1;
01141                 }
01142                 else {
01143                         if (ms->flags & MAGIC_CHECK)
01144                                 file_magwarn(ms, "invalid string op: %c", *t);
01145                         return -1;
01146                 }
01147         }
01148         /*
01149          * We used to set mask to all 1's here, instead let's just not do
01150          * anything if mask = 0 (unless you have a better idea)
01151          */
01152         EATAB;
01153   
01154         switch (*l) {
01155         case '>':
01156         case '<':
01157         /* Old-style anding: "0 byte &0x80 dynamically linked" */
01158         case '&':
01159         case '^':
01160         case '=':
01161                 m->reln = *l;
01162                 ++l;
01163                 if (*l == '=') {
01164                    /* HP compat: ignore &= etc. */
01165                    ++l;
01166                 }
01167                 break;
01168         case '!':
01169                 m->reln = *l;
01170                 ++l;
01171                 break;
01172         default:
01173                 m->reln = '=';  /* the default relation */
01174                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
01175                     isspace((unsigned char)l[1])) || !l[1])) {
01176                         m->reln = *l;
01177                         ++l;
01178                 }
01179                 break;
01180         }
01181         /*
01182          * Grab the value part, except for an 'x' reln.
01183          */
01184         if (m->reln != 'x' && getvalue(ms, m, &l, action))
01185                 return -1;
01186 
01187         /*
01188          * TODO finish this macro and start using it!
01189          * #define offsetcheck {if (offset > HOWMANY-1) 
01190          *      magwarn("offset too big"); }
01191          */
01192 
01193         /*
01194          * Now get last part - the description
01195          */
01196         EATAB;
01197         if (l[0] == '\b') {
01198                 ++l;
01199                 m->nospflag = 1;
01200         } else if ((l[0] == '\\') && (l[1] == 'b')) {
01201                 ++l;
01202                 ++l;
01203                 m->nospflag = 1;
01204         } else
01205                 m->nospflag = 0;
01206         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
01207                 continue;
01208         if (i == sizeof(m->desc)) {
01209                 m->desc[sizeof(m->desc) - 1] = '\0';
01210                 if (ms->flags & MAGIC_CHECK)
01211                         file_magwarn(ms, "description `%s' truncated", m->desc);
01212         }
01213 
01214         /*
01215          * We only do this check while compiling, or if any of the magic
01216          * files were not compiled.
01217          */
01218         if (ms->flags & MAGIC_CHECK) {
01219                 if (check_format(ms, m) == -1)
01220                         return -1;
01221         }
01222 #ifndef COMPILE_ONLY
01223         if (action == FILE_CHECK) {
01224                 file_mdump(m);
01225         }
01226 #endif
01227         if (m->cont_level == 0)
01228                 ++(*nmentryp);          /* make room for next */
01229         return 0;
01230 }
01231 
01232 private int
01233 check_format_type(const char *ptr, int type)
01234 {
01235         int quad = 0;
01236         if (*ptr == '\0') {
01237                 /* Missing format string; bad */
01238                 return -1;
01239         }
01240 
01241         switch (type) {
01242         case FILE_FMT_QUAD:
01243                 quad = 1;
01244                 /*@fallthrough@*/
01245         case FILE_FMT_NUM:
01246                 if (*ptr == '-')
01247                         ptr++;
01248                 if (*ptr == '.')
01249                         ptr++;
01250                 while (isdigit((unsigned char)*ptr)) ptr++;
01251                 if (*ptr == '.')
01252                         ptr++;
01253                 while (isdigit((unsigned char)*ptr)) ptr++;
01254                 if (quad) {
01255                         if (*ptr++ != 'l')
01256                                 return -1;
01257                         if (*ptr++ != 'l')
01258                                 return -1;
01259                 }
01260         
01261                 switch (*ptr++) {
01262                 case 'l':
01263                         switch (*ptr++) {
01264                         case 'i':
01265                         case 'd':
01266                         case 'u':
01267                         case 'x':
01268                         case 'X':
01269                                 return 0;
01270                         default:
01271                                 return -1;
01272                         }
01273                 
01274                 case 'h':
01275                         switch (*ptr++) {
01276                         case 'h':
01277                                 switch (*ptr++) {
01278                                 case 'i':
01279                                 case 'd':
01280                                 case 'u':
01281                                 case 'x':
01282                                 case 'X':
01283                                         return 0;
01284                                 default:
01285                                         return -1;
01286                                 }
01287                         case 'd':
01288                                 return 0;
01289                         default:
01290                                 return -1;
01291                         }
01292 
01293                 case 'i':
01294                 case 'c':
01295                 case 'd':
01296                 case 'u':
01297                 case 'x':
01298                 case 'X':
01299                         return 0;
01300                         
01301                 default:
01302                         return -1;
01303                 }
01304                 
01305         case FILE_FMT_STR:
01306                 if (*ptr == '-')
01307                         ptr++;
01308                 while (isdigit((unsigned char )*ptr))
01309                         ptr++;
01310                 if (*ptr == '.') {
01311                         ptr++;
01312                         while (isdigit((unsigned char )*ptr))
01313                                 ptr++;
01314                 }
01315                 
01316                 switch (*ptr++) {
01317                 case 's':
01318         return 0;
01319                 default:
01320                         return -1;
01321                 }
01322                 
01323         default:
01324                 /* internal error */
01325                 abort();
01326         }
01327         /*@notreached@*/
01328         return -1;
01329 }
01330 
01331 /*
01332  * Check that the optional printf format in description matches
01333  * the type of the magic.
01334  */
01335 private int
01336 check_format(struct magic_set *ms, struct magic *m)
01337 {
01338         char *ptr;
01339 
01340         for (ptr = m->desc; *ptr; ptr++)
01341                 if (*ptr == '%')
01342                         break;
01343         if (*ptr == '\0') {
01344                 /* No format string; ok */
01345                 return 1;
01346         }
01347 
01348         assert(file_nformats == file_nnames);
01349 
01350         if (m->type >= file_nformats) {
01351                 file_error(ms, 0, "Internal error inconsistency between "
01352                     "m->type and format strings");              
01353                 return -1;
01354         }
01355         if (file_formats[m->type] == FILE_FMT_NONE) {
01356                 file_error(ms, 0, "No format string for `%s' with description "
01357                     "`%s'", m->desc, file_names[m->type]);
01358                 return -1;
01359         }
01360 
01361         ptr++;
01362         if (check_format_type(ptr, file_formats[m->type]) == -1) {
01363                 /*
01364                  * TODO: this error message is unhelpful if the format
01365                  * string is not one character long
01366                  */
01367                 file_error(ms, 0, "Printf format `%c' is not valid for type "
01368                     " `%s' in description `%s'", *ptr,
01369                     file_names[m->type], m->desc);
01370                 return -1;
01371                 }
01372         
01373         for (; *ptr; ptr++) {
01374                 if (*ptr == '%') {
01375                         file_error(ms, 0,
01376                             "Too many format strings (should have at most one) "
01377                             "for `%s' with description `%s'",
01378                             file_names[m->type], m->desc);
01379                         return -1;
01380         }
01381         }
01382                 return 0;
01383         }
01384 
01385 /* 
01386  * Read a numeric value from a pointer, into the value union of a magic 
01387  * pointer, according to the magic type.  Update the string pointer to point 
01388  * just after the number read.  Return 0 for success, non-zero for failure.
01389  */
01390 private int
01391 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
01392 {
01393         int slen;
01394 
01395         switch (m->type) {
01396         case FILE_BESTRING16:
01397         case FILE_LESTRING16:
01398         case FILE_STRING:
01399         case FILE_PSTRING:
01400         case FILE_REGEX:
01401         case FILE_SEARCH:
01402 /*@i@*/         *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen, action);
01403                 if (*p == NULL) {
01404                         if (ms->flags & MAGIC_CHECK)
01405                                 file_magwarn(ms, "cannot get string from `%s'",
01406                                     m->value.s);
01407                         return -1;
01408                 }
01409                 m->vallen = slen;
01410                 return 0;
01411         default:
01412                 if (m->reln != 'x') {
01413                         char *ep;
01414                         m->value.q = file_signextend(ms, m,
01415                             (uint64_t)strtoull(*p, &ep, 0));
01416                         *p = ep;
01417                         eatsize(p);
01418                 }
01419                 return 0;
01420         }
01421 }
01422 
01423 /*
01424  * Convert a string containing C character escapes.  Stop at an unescaped
01425  * space or tab.
01426  * Copy the converted version to "p", returning its length in *slen.
01427  * Return updated scan pointer as function result.
01428  */
01429 private const char *
01430 getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen, int action)
01431 {
01432         const char *origs = s;
01433         char    *origp = p;
01434         char    *pmax = p + plen - 1;
01435         int     c;
01436         int     val;
01437 
01438         while ((c = *s++) != '\0') {
01439                 if (isspace((unsigned char) c))
01440                         break;
01441                 if (p >= pmax) {
01442                         file_error(ms, 0, "string too long: `%s'", origs);
01443                         return NULL;
01444                 }
01445                 if(c == '\\') {
01446                         switch(c = *s++) {
01447 
01448                         case '\0':
01449                                 if (action == FILE_COMPILE)
01450                                         file_magwarn(ms, "incomplete escape");
01451                                 goto out;
01452 
01453                         case '\t':
01454                                 if (action == FILE_COMPILE) {
01455                                         file_magwarn(ms,
01456                                             "escaped tab found, use \\t instead");
01457                                         action++;
01458                                 }
01459                                 /*@fallthrough@*/
01460                         default:
01461                                 if (action == FILE_COMPILE) {
01462                                         if (isprint((unsigned char)c))
01463                                             file_magwarn(ms,
01464                                                 "no need to escape `%c'", c);
01465                                         else
01466                                             file_magwarn(ms,
01467                                                 "unknown escape sequence: \\%03o", c);
01468                                 }
01469                                 /*@fallthrough@*/
01470                         /* space, perhaps force people to use \040? */
01471                         case ' ':
01472 #if 0
01473                         /*
01474                          * Other things people escape, but shouldn't need to,
01475                          * so we disallow them
01476                          */
01477                         case '\'':
01478                         case '"':
01479                         case '?':
01480 #endif
01481                         /* Relations */
01482                         case '>':
01483                         case '<':
01484                         case '&':
01485                         case '^':
01486                         case '=':
01487                         case '!':
01488                         /* and baskslash itself */
01489                         case '\\':
01490                                 *p++ = (char) c;
01491                                 /*@switchbreak@*/ break;
01492 
01493                         case 'a':
01494                                 *p++ = '\a';
01495                                 /*@switchbreak@*/ break;
01496 
01497                         case 'b':
01498                                 *p++ = '\b';
01499                                 /*@switchbreak@*/ break;
01500 
01501                         case 'f':
01502                                 *p++ = '\f';
01503                                 /*@switchbreak@*/ break;
01504 
01505                         case 'n':
01506                                 *p++ = '\n';
01507                                 /*@switchbreak@*/ break;
01508 
01509                         case 'r':
01510                                 *p++ = '\r';
01511                                 /*@switchbreak@*/ break;
01512 
01513                         case 't':
01514                                 *p++ = '\t';
01515                                 /*@switchbreak@*/ break;
01516 
01517                         case 'v':
01518                                 *p++ = '\v';
01519                                 /*@switchbreak@*/ break;
01520 
01521                         /* \ and up to 3 octal digits */
01522                         case '0':
01523                         case '1':
01524                         case '2':
01525                         case '3':
01526                         case '4':
01527                         case '5':
01528                         case '6':
01529                         case '7':
01530                                 val = c - '0';
01531                                 c = *s++;  /* try for 2 */
01532                                 if(c >= '0' && c <= '7') {
01533                                         val = (val<<3) | (c - '0');
01534                                         c = *s++;  /* try for 3 */
01535                                         if(c >= '0' && c <= '7')
01536                                                 val = (val<<3) | (c-'0');
01537                                         else
01538                                                 --s;
01539                                 }
01540                                 else
01541                                         --s;
01542                                 *p++ = (char)val;
01543                                 /*@switchbreak@*/ break;
01544 
01545                         /* \x and up to 2 hex digits */
01546                         case 'x':
01547                                 val = 'x';      /* Default if no digits */
01548                                 c = hextoint(*s++);     /* Get next char */
01549                                 if (c >= 0) {
01550                                         val = c;
01551                                         c = hextoint(*s++);
01552                                         if (c >= 0)
01553                                                 val = (val << 4) + c;
01554                                         else
01555                                                 --s;
01556                                 } else
01557                                         --s;
01558                                 *p++ = (char)val;
01559                                 /*@switchbreak@*/ break;
01560                         }
01561                 } else
01562                         *p++ = (char)c;
01563         }
01564 out:
01565         *p = '\0';
01566         *slen = p - origp;
01567         return s;
01568 }
01569 
01570 
01571 /* Single hex char to int; -1 if not a hex char. */
01572 private int
01573 hextoint(int c)
01574 {
01575         if (!isascii((unsigned char) c))
01576                 return -1;
01577         if (isdigit((unsigned char) c))
01578                 return c - '0';
01579         if ((c >= 'a')&&(c <= 'f'))
01580                 return c + 10 - 'a';
01581         if (( c>= 'A')&&(c <= 'F'))
01582                 return c + 10 - 'A';
01583         return -1;
01584 }
01585 
01586 
01587 /*
01588  * Print a string containing C character escapes.
01589  */
01590 protected void
01591 file_showstr(FILE *fp, const char *s, size_t len)
01592 {
01593         char    c;
01594 
01595         for (;;) {
01596                 c = *s++;
01597                 if (len == ~0U) {
01598                         if (c == '\0')
01599                                 break;
01600                 }
01601                 else  {
01602                         if (len-- == 0)
01603                                 break;
01604                 }
01605                 if(c >= 040 && c <= 0176)       /* TODO isprint && !iscntrl */
01606                         (void) fputc(c, fp);
01607                 else {
01608                         (void) fputc('\\', fp);
01609                         switch (c) {
01610                         case '\a':
01611                                 (void) fputc('a', fp);
01612                                 /*@switchbreak@*/ break;
01613 
01614                         case '\b':
01615                                 (void) fputc('b', fp);
01616                                 /*@switchbreak@*/ break;
01617 
01618                         case '\f':
01619                                 (void) fputc('f', fp);
01620                                 /*@switchbreak@*/ break;
01621                         
01622                         case '\n':
01623                                 (void) fputc('n', fp);
01624                                 /*@switchbreak@*/ break;
01625 
01626                         case '\r':
01627                                 (void) fputc('r', fp);
01628                                 /*@switchbreak@*/ break;
01629 
01630                         case '\t':
01631                                 (void) fputc('t', fp);
01632                                 /*@switchbreak@*/ break;
01633 
01634                         case '\v':
01635                                 (void) fputc('v', fp);
01636                                 /*@switchbreak@*/ break;
01637 
01638                         default:
01639                                 (void) fprintf(fp, "%.3o", c & 0377);
01640                                 /*@switchbreak@*/ break;
01641                         }
01642                 }
01643         }
01644 }
01645 
01646 /*
01647  * eatsize(): Eat the size spec from a number [eg. 10UL]
01648  */
01649 private void
01650 eatsize(const char **p)
01651 {
01652         const char *l = *p;
01653 
01654         if (LOWCASE(*l) == 'u') 
01655                 l++;
01656 
01657         switch (LOWCASE(*l)) {
01658         case 'l':    /* long */
01659         case 's':    /* short */
01660         case 'h':    /* short */
01661         case 'b':    /* char/byte */
01662         case 'c':    /* char/byte */
01663                 l++;
01664                 /*@fallthrough@*/
01665         default:
01666                 break;
01667         }
01668 
01669         *p = l;
01670 }
01671 
01672 /*
01673  * handle a compiled file.
01674  */
01675 private int
01676 apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
01677     const char *fn)
01678 {
01679         int fd;
01680         struct stat st;
01681         uint32_t *ptr;
01682         uint32_t version;
01683         int needsbyteswap;
01684         char buf[MAXPATHLEN];
01685         char *dbname = mkdbname(fn, buf, sizeof(buf), 0);
01686         void *mm = NULL;
01687 
01688         if (dbname == NULL)
01689                 return -1;
01690 
01691         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
01692                 return -1;
01693 
01694         if (fstat(fd, &st) == -1) {
01695                 file_error(ms, errno, "cannot stat `%s'", dbname);
01696                 goto error;
01697         }
01698         if (st.st_size < 16) {
01699                 file_error(ms, 0, "file `%s' is too small", dbname);
01700                 goto error;
01701         }
01702 
01703 #ifdef QUICK
01704         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
01705             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
01706                 file_error(ms, errno, "cannot map `%s'", dbname);
01707                 goto error;
01708         }
01709 #define RET     2
01710 #else
01711         if ((mm = malloc((size_t)st.st_size)) == NULL) {
01712                 file_oomem(ms, (size_t)st.st_size);
01713                 goto error;
01714         }
01715         if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
01716                 file_badread(ms);
01717                 goto error;
01718         }
01719 #define RET     1
01720 #endif
01721         *magicp = mm;
01722         (void)close(fd);
01723         fd = -1;
01724         ptr = (uint32_t *)(void *)*magicp;
01725         if (*ptr != MAGICNO) {
01726                 if (swap4(*ptr) != MAGICNO) {
01727                         file_error(ms, 0, "bad magic in `%s'");
01728                         goto error;
01729                 }
01730                 needsbyteswap = 1;
01731         } else
01732                 needsbyteswap = 0;
01733         if (needsbyteswap)
01734                 version = swap4(ptr[1]);
01735         else
01736                 version = ptr[1];
01737         if (version != VERSIONNO) {
01738                 file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
01739                     version, VERSIONNO, dbname);
01740                 goto error;
01741         }
01742         *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
01743         (*magicp)++;
01744         if (needsbyteswap)
01745                 byteswap(*magicp, *nmagicp);
01746         return RET;
01747 
01748 error:
01749         if (fd != -1)
01750                 (void)close(fd);
01751         if (mm) {
01752 #ifdef QUICK
01753                 (void)munmap((void *)mm, (size_t)st.st_size);
01754 #else
01755                 free(mm);
01756 #endif
01757         } else {
01758                 *magicp = NULL;
01759                 *nmagicp = 0;
01760         }
01761         return -1;
01762 }
01763 
01764 /*@unchecked@*/ /*@observer@*/
01765 private const uint32_t ar[] = {
01766     MAGICNO, VERSIONNO
01767 };
01768 /*
01769  * handle an mmaped file.
01770  */
01771 private int
01772 apprentice_compile(struct magic_set *ms, struct magic **magicp,
01773     uint32_t *nmagicp, const char *fn)
01774 {
01775         int fd;
01776         char buf[MAXPATHLEN];
01777         char *dbname = mkdbname(fn, buf, sizeof(buf), 1);
01778 
01779         if (dbname == NULL) 
01780                 return -1;
01781 
01782         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
01783                 file_error(ms, errno, "cannot open `%s'", dbname);
01784                 return -1;
01785         }
01786 
01787         if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
01788                 file_error(ms, errno, "error writing `%s'", dbname);
01789                 return -1;
01790         }
01791 
01792         if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
01793             != sizeof(struct magic)) {
01794                 file_error(ms, errno, "error seeking `%s'", dbname);
01795                 return -1;
01796         }
01797 
01798         if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) 
01799             != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
01800                 file_error(ms, errno, "error writing `%s'", dbname);
01801                 return -1;
01802         }
01803 
01804         (void)close(fd);
01805         return 0;
01806 }
01807 
01808 /*@unchecked@*/ /*@observer@*/
01809 private const char ext[] = ".mgc";
01810 /*
01811  * make a dbname
01812  */
01813 private char *
01814 mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)
01815 {
01816         if (strip) {
01817                 const char *p;
01818                 if ((p = strrchr(fn, '/')) != NULL)
01819                         fn = ++p;
01820         }
01821 
01822         (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
01823         return buf;
01824 }
01825 
01826 /*
01827  * Byteswap an mmap'ed file if needed
01828  */
01829 private void
01830 byteswap(struct magic *magic, uint32_t nmagic)
01831 {
01832         uint32_t i;
01833         for (i = 0; i < nmagic; i++)
01834                 bs1(&magic[i]);
01835 }
01836 
01837 /*
01838  * swap a short
01839  */
01840 private uint16_t
01841 swap2(uint16_t sv)
01842 {
01843         uint16_t rv;
01844         uint8_t *s = (uint8_t *)(void *)&sv; 
01845         uint8_t *d = (uint8_t *)(void *)&rv; 
01846         d[0] = s[1];
01847         d[1] = s[0];
01848         return rv;
01849 }
01850 
01851 /*
01852  * swap an int
01853  */
01854 private uint32_t
01855 swap4(uint32_t sv)
01856 {
01857         uint32_t rv;
01858         uint8_t *s = (uint8_t *)(void *)&sv; 
01859         uint8_t *d = (uint8_t *)(void *)&rv; 
01860         d[0] = s[3];
01861         d[1] = s[2];
01862         d[2] = s[1];
01863         d[3] = s[0];
01864         return rv;
01865 }
01866 
01867 /*
01868  * swap a quad
01869  */
01870 private uint64_t
01871 swap8(uint64_t sv)
01872 {
01873         uint32_t rv;
01874         uint8_t *s = (uint8_t *)(void *)&sv; 
01875         uint8_t *d = (uint8_t *)(void *)&rv; 
01876         d[0] = s[3];
01877         d[1] = s[2];
01878         d[2] = s[1];
01879         d[3] = s[0];
01880         d[4] = s[7];
01881         d[5] = s[6];
01882         d[6] = s[5];
01883         d[7] = s[4];
01884         return rv;
01885 }
01886 
01887 /*
01888  * byteswap a single magic entry
01889  */
01890 private void
01891 bs1(struct magic *m)
01892 {
01893         m->cont_level = swap2(m->cont_level);
01894         m->offset = swap4((uint32_t)m->offset);
01895         m->in_offset = swap4((uint32_t)m->in_offset);
01896         m->lineno = swap4((uint32_t)m->lineno);
01897         if (IS_STRING(m->type)) {
01898                 m->str_count = swap4(m->str_count);
01899                 m->str_flags = swap4(m->str_flags);
01900         }
01901         else {
01902                 m->value.q = swap8(m->value.q);
01903                 m->num_mask = swap8(m->num_mask);
01904         }
01905 }

Generated on Fri May 25 21:18:11 2007 for rpm by  doxygen 1.5.2