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.105 2007/05/16 20:51:40 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 ((mfn = strdup(fn)) == NULL) {
00374                 file_oomem(ms, strlen(fn));
00375                 return NULL;
00376         }
00377         fn = mfn;
00378 
00379         if ((mlist = malloc(sizeof(*mlist))) == NULL) {
00380                 free(mfn);
00381                 file_oomem(ms, sizeof(*mlist));
00382                 return NULL;
00383         }
00384         mlist->next = mlist->prev = mlist;
00385 
00386         while (fn) {
00387                 p = strchr(fn, PATHSEP);
00388                 if (p)
00389                         *p++ = '\0';
00390                 if (*fn == '\0')
00391                         break;
00392                 if (ms->flags & MAGIC_MIME) {
00393                         size_t len = strlen(fn) + sizeof(mime);
00394                         if ((afn = malloc(len)) == NULL) {
00395                                 free(mfn);
00396                                 free(mlist);
00397                                 file_oomem(ms, len);
00398                                 return NULL;
00399                         }
00400                         (void)strcpy(afn, fn);
00401                         (void)strcat(afn, mime);
00402                         fn = afn;
00403                 }
00404                 file_err = apprentice_1(ms, fn, action, mlist);
00405                 if (file_err > errs)
00406                         errs = file_err;
00407                 if (afn) {
00408                         free(afn);
00409                         afn = NULL;
00410                 }
00411                 fn = p;
00412         }
00413         if (errs == -1) {
00414                 free(mfn);
00415                 free(mlist);
00416                 mlist = NULL;
00417                 file_error(ms, 0, "could not find any magic files!");
00418                 return NULL;
00419         }
00420         free(mfn);
00421         return mlist;
00422 }
00423 
00424 /*
00425  * Get weight of this magic entry, for sorting purposes.
00426  */
00427 private size_t
00428 apprentice_magic_strength(const struct magic *m)
00429 {
00430 #define MULT 10
00431         size_t val = 2 * MULT;  /* baseline strength */
00432 
00433         switch (m->type) {
00434         case FILE_DEFAULT:      /* make sure this sorts last */
00435                 return 0;
00436 
00437         case FILE_BYTE:
00438                 val += 1 * MULT;
00439                 break;
00440 
00441         case FILE_SHORT:
00442         case FILE_LESHORT:
00443         case FILE_BESHORT:
00444                 val += 2 * MULT;
00445                 break;
00446 
00447         case FILE_LONG:
00448         case FILE_LELONG:
00449         case FILE_BELONG:
00450         case FILE_MELONG:
00451                 val += 4 * MULT;
00452                 break;
00453 
00454         case FILE_PSTRING:
00455         case FILE_STRING:
00456                 val += m->vallen * MULT;
00457                 break;
00458 
00459         case FILE_BESTRING16:
00460         case FILE_LESTRING16:
00461                 val += m->vallen * MULT / 2;
00462                 break;
00463 
00464         case FILE_SEARCH:
00465         case FILE_REGEX:
00466                 val += m->vallen;
00467                 break;
00468 
00469         case FILE_DATE:
00470         case FILE_LEDATE:
00471         case FILE_BEDATE:
00472         case FILE_MEDATE:
00473         case FILE_LDATE:
00474         case FILE_LELDATE:
00475         case FILE_BELDATE:
00476         case FILE_MELDATE:
00477                 val += 4 * MULT;
00478                 break;
00479 
00480         case FILE_QUAD:
00481         case FILE_BEQUAD:
00482         case FILE_LEQUAD:
00483         case FILE_QDATE:
00484         case FILE_LEQDATE:
00485         case FILE_BEQDATE:
00486         case FILE_QLDATE:
00487         case FILE_LEQLDATE:
00488         case FILE_BEQLDATE:
00489                 val += 8 * MULT;
00490                 break;
00491 
00492         default:
00493                 val = 0;
00494                 (void)fprintf(stderr, "Bad type %d\n", m->type);
00495                 abort();
00496         }
00497 
00498         switch (m->reln) {
00499         case 'x':       /* matches anything penalize */
00500                 val = 0;
00501                 break;
00502 
00503         case '!':
00504         case '=':       /* Exact match, prefer */
00505                 val += MULT;
00506                 break;
00507 
00508         case '>':
00509         case '<':       /* comparison match reduce strength */
00510                 val -= 2 * MULT;
00511                 break;
00512 
00513         case '^':
00514         case '&':       /* masking bits, we could count them too */
00515                 val -= MULT;
00516                 break;
00517 
00518         default:
00519                 (void)fprintf(stderr, "Bad relation %c\n", m->reln);
00520                 abort();
00521         }
00522 
00523         if (val == 0)   /* ensure we only return 0 for FILE_DEFAULT */
00524                 val = 1;
00525 
00526         return val;
00527 }
00528 
00529 /*  
00530  * Sort callback for sorting entries by "strength" (basically length)
00531  */
00532 private int
00533 apprentice_sort(const void *a, const void *b)
00534 {
00535         const struct magic_entry *ma = a;
00536         const struct magic_entry *mb = b;
00537         size_t sa = apprentice_magic_strength(ma->mp);
00538         size_t sb = apprentice_magic_strength(mb->mp);
00539         if (sa == sb)
00540                 return 0;
00541         else if (sa > sb)
00542                 return -1;
00543         else
00544                 return 1;
00545 }
00546 
00547 /*
00548  * parse from a file
00549  * const char *fn: name of magic file
00550  */
00551 private int
00552 apprentice_file(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
00553     const char *fn, int action)
00554 {
00555         private const char hdr[] =
00556                 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
00557         FILE *f;
00558         char line[BUFSIZ+1];
00559         int errs = 0;
00560         struct magic_entry *marray;
00561         uint32_t marraycount, i, mentrycount = 0;
00562         size_t lineno = 0;
00563 
00564         ms->flags |= MAGIC_CHECK;       /* Enable checks for parsed files */
00565 
00566         f = fopen(ms->file = fn, "r");
00567         if (f == NULL) {
00568                 if (errno != ENOENT)
00569                         file_error(ms, errno, "cannot read magic file `%s'",
00570                             fn);
00571                 return -1;
00572         }
00573 
00574         maxmagic = MAXMAGIS;
00575         if ((marray = calloc(maxmagic, sizeof(*marray))) == NULL) {
00576                 (void)fclose(f);
00577                 file_oomem(ms, maxmagic * sizeof(*marray));
00578                 return -1;
00579         }
00580         marraycount = 0;
00581 
00582         /* print silly verbose header for USG compat. */
00583         if (action == FILE_CHECK)
00584                 (void)fprintf(stderr, "%s\n", hdr);
00585 
00586         /* read and parse this file */
00587         for (ms->line = 1; fgets(line, BUFSIZ, f) != NULL; ms->line++) {
00588                 size_t len;
00589                 len = strlen(line);
00590                 if (len == 0) /* null line, garbage, etc */
00591                         continue;
00592                 if (line[len - 1] == '\n') {
00593                         lineno++;
00594                 line[len - 1] = '\0'; /* delete newline */
00595                 }
00596                 if (line[0] == '\0')    /* empty, do not parse */
00597                         continue;
00598                 if (line[0] == '#')     /* comment, do not parse */
00599                         continue;
00600                 if (parse(ms, &marray, &marraycount, line, lineno, action) != 0)
00601                         errs++;
00602         }
00603 
00604         (void)fclose(f);
00605         if (errs)
00606                 goto out;
00607 
00608 #ifndef NOORDER
00609         qsort(marray, marraycount, sizeof(*marray), apprentice_sort);
00610         /*
00611          * Make sure that any level 0 "default" line is last (if one exists).
00612          */
00613         for (i = 0; i < marraycount; i++) {
00614                 if (marray[i].mp->cont_level == 0 &&
00615                     marray[i].mp->type == FILE_DEFAULT) {
00616                         while (++i < marraycount)
00617                                 if (marray[i].mp->cont_level == 0)
00618                                         /*@innerbreak@*/ break;
00619                         if (i != marraycount) {
00620                                 ms->line = marray[i].mp->lineno; /* XXX - Ugh! */
00621                                 file_magwarn(ms,
00622                                     "level 0 \"default\" did not sort last");
00623                         }
00624                         break;                                      
00625                 }
00626         }
00627 #endif
00628 
00629         for (i = 0; i < marraycount; i++)
00630                 mentrycount += marray[i].cont_count;
00631 
00632         if ((*magicp = malloc(sizeof(**magicp) * mentrycount)) == NULL) {
00633                 file_oomem(ms, sizeof(**magicp) * mentrycount);
00634                 errs++;
00635                 goto out;
00636         }
00637 
00638         mentrycount = 0;
00639         for (i = 0; i < marraycount; i++) {
00640                 (void)memcpy(*magicp + mentrycount, marray[i].mp,
00641                     marray[i].cont_count * sizeof(**magicp));
00642                 mentrycount += marray[i].cont_count;
00643         }
00644 out:
00645         for (i = 0; i < marraycount; i++)
00646                 free(marray[i].mp);
00647         free(marray);
00648         if (errs) {
00649                 *magicp = NULL;
00650                 *nmagicp = 0;
00651         return errs;
00652         } else {
00653                 *nmagicp = mentrycount;
00654                 return 0;
00655         }
00656 
00657 }
00658 
00659 /*
00660  * extend the sign bit if the comparison is to be signed
00661  */
00662 protected uint64_t
00663 file_signextend(struct magic_set *ms, struct magic *m, uint64_t v)
00664 {
00665         if (!(m->flag & UNSIGNED)) {
00666                 switch(m->type) {
00667                 /*
00668                  * Do not remove the casts below.  They are
00669                  * vital.  When later compared with the data,
00670                  * the sign extension must have happened.
00671                  */
00672                 case FILE_BYTE:
00673                         v = (char) v;
00674                         break;
00675                 case FILE_SHORT:
00676                 case FILE_BESHORT:
00677                 case FILE_LESHORT:
00678                         v = (short) v;
00679                         break;
00680                 case FILE_DATE:
00681                 case FILE_BEDATE:
00682                 case FILE_LEDATE:
00683                 case FILE_MEDATE:
00684                 case FILE_LDATE:
00685                 case FILE_BELDATE:
00686                 case FILE_LELDATE:
00687                 case FILE_MELDATE:
00688                 case FILE_LONG:
00689                 case FILE_BELONG:
00690                 case FILE_LELONG:
00691                 case FILE_MELONG:
00692                         v = (int32_t) v;
00693                         break;
00694                 case FILE_QUAD:
00695                 case FILE_BEQUAD:
00696                 case FILE_LEQUAD:
00697                 case FILE_QDATE:
00698                 case FILE_QLDATE:
00699                 case FILE_BEQDATE:
00700                 case FILE_BEQLDATE:
00701                 case FILE_LEQDATE:
00702                 case FILE_LEQLDATE:
00703                         v = (int64_t) v;
00704                         break;
00705                 case FILE_STRING:
00706                 case FILE_PSTRING:
00707                 case FILE_BESTRING16:
00708                 case FILE_LESTRING16:
00709                 case FILE_REGEX:
00710                 case FILE_SEARCH:
00711                 case FILE_DEFAULT:
00712                         break;
00713                 default:
00714                         if (ms->flags & MAGIC_CHECK)
00715                             file_magwarn(ms, "cannot happen: m->type=%d\n",
00716                                     m->type);
00717                         return ~0U;
00718                 }
00719         }
00720         return v;
00721 }
00722 
00723 private int
00724 string_modifier_check(struct magic_set *ms, struct magic const *m)
00725         /*@globals fileSystem @*/
00726         /*@modifies ms, fileSystem @*/
00727 {
00728         if ((ms->flags & MAGIC_CHECK) == 0)
00729                 return 0;
00730 
00731         switch (m->type) {
00732         case FILE_BESTRING16:
00733         case FILE_LESTRING16:
00734                 if (m->str_flags != 0) {
00735                         file_magwarn(ms, "no modifiers allowed for 16-bit strings\n");
00736                         return -1;
00737                 }
00738                 break;
00739         case FILE_STRING:
00740         case FILE_PSTRING:
00741                 if ((m->str_flags & REGEX_OFFSET_START) != 0) {
00742                         file_magwarn(ms, "'/%c' only allowed on regex and search\n",
00743                             CHAR_REGEX_OFFSET_START);
00744                         return -1;
00745                 }
00746                 break;
00747         case FILE_SEARCH:
00748                 break;
00749         case FILE_REGEX:
00750                 if ((m->str_flags & STRING_COMPACT_BLANK) != 0) {
00751                         file_magwarn(ms, "'/%c' not allowed on regex\n",
00752                             CHAR_COMPACT_BLANK);
00753                         return -1;
00754                 }
00755                 if ((m->str_flags & STRING_COMPACT_OPTIONAL_BLANK) != 0) {
00756                         file_magwarn(ms, "'/%c' not allowed on regex\n",
00757                             CHAR_COMPACT_OPTIONAL_BLANK);
00758                         return -1;
00759                 }
00760                 break;
00761         default:
00762                 file_magwarn(ms, "coding error: m->type=%d\n",
00763                     m->type);
00764                 return -1;
00765         }
00766         return 0;
00767 }
00768 
00769 private int
00770 get_op(char c)
00771         /*@*/
00772 {
00773         switch (c) {
00774         case '&':
00775                 return FILE_OPAND;
00776         case '|':
00777                 return FILE_OPOR;
00778         case '^':
00779                 return FILE_OPXOR;
00780         case '+':
00781                 return FILE_OPADD;
00782         case '-':
00783                 return FILE_OPMINUS;
00784         case '*':
00785                 return FILE_OPMULTIPLY;
00786         case '/':
00787                 return FILE_OPDIVIDE;
00788         case '%':
00789                 return FILE_OPMODULO;
00790         default:
00791                 return -1;
00792         }
00793 }
00794 
00795 #ifdef ENABLE_CONDITIONALS
00796 private int
00797 get_cond(const char *l, const char **t)
00798         /*@modifies *t @*/
00799 {
00800         /*@observer@*/
00801         static struct cond_tbl_s {
00802         /*@observer@*/ /*@null@*/
00803                 const char *name;
00804                 const size_t len;
00805                 const int cond;
00806         } cond_tbl[] = {
00807                 { "if",         2,      COND_IF },
00808                 { "elif",       4,      COND_ELIF },
00809                 { "else",       4,      COND_ELSE },
00810                 { NULL,         0,      COND_NONE },
00811         };
00812         struct cond_tbl_s *p;
00813 
00814         for (p = cond_tbl; p->name; p++) {
00815                 if (strncmp(l, p->name, p->len) == 0 &&
00816                     isspace((unsigned char)l[p->len])) {
00817                         if (t)
00818                                 *t = l + p->len;
00819                         break;
00820                 }
00821         }
00822         return p->cond;
00823 }
00824 
00825 private int
00826 check_cond(struct magic_set *ms, int cond, uint32_t cont_level)
00827         /*@globals fileSystem @*/
00828         /*@modifies ms, fileSystem @*/
00829 {
00830         int last_cond;
00831         last_cond = ms->c.li[cont_level].last_cond;
00832 
00833         switch (cond) {
00834         case COND_IF:
00835                 if (last_cond != COND_NONE && last_cond != COND_ELIF) {
00836                         if (ms->flags & MAGIC_CHECK)
00837                                 file_magwarn(ms, "syntax error: `if'");
00838                         return -1;
00839                 }
00840                 last_cond = COND_IF;
00841                 break;
00842 
00843         case COND_ELIF:
00844                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
00845                         if (ms->flags & MAGIC_CHECK)
00846                                 file_magwarn(ms, "syntax error: `elif'");
00847                         return -1;
00848                 }
00849                 last_cond = COND_ELIF;
00850                 break;
00851 
00852         case COND_ELSE:
00853                 if (last_cond != COND_IF && last_cond != COND_ELIF) {
00854                         if (ms->flags & MAGIC_CHECK)
00855                                 file_magwarn(ms, "syntax error: `else'");
00856                         return -1;
00857                 }
00858                 last_cond = COND_NONE;
00859                 break;
00860 
00861         case COND_NONE:
00862                 last_cond = COND_NONE;
00863                 break;
00864         }
00865 
00866         ms->c.li[cont_level].last_cond = last_cond;
00867         return 0;
00868 }
00869 #endif /* ENABLE_CONDITIONALS */
00870 
00871 /*
00872  * parse one line from magic file, put into magic[index++] if valid
00873  */
00874 private int
00875 parse(struct magic_set *ms, struct magic_entry **mentryp, uint32_t *nmentryp, 
00876     const char *line, size_t lineno, int action)
00877 {
00878 #ifdef ENABLE_CONDITIONALS
00879         static uint32_t last_cont_level = 0;
00880 #endif
00881         size_t i;
00882         struct magic_entry *me;
00883         struct magic *m;
00884         const char *l = line;
00885         char *t;
00886         int op;
00887         uint32_t cont_level;
00888 
00889         cont_level = 0;
00890 
00891         while (*l == '>') {
00892                 ++l;            /* step over */
00893                 cont_level++; 
00894         }
00895 #ifdef ENABLE_CONDITIONALS
00896         if (cont_level == 0 || cont_level > last_cont_level)
00897                 if (file_check_mem(ms, cont_level) == -1)
00898                         return -1;
00899         last_cont_level = cont_level;
00900 #endif
00901 
00902 #define ALLOC_CHUNK     (size_t)10
00903 #define ALLOC_INCR      (size_t)200
00904 
00905         if (cont_level != 0) {
00906                 if (*nmentryp == 0) {
00907                         file_error(ms, 0, "No current entry for continuation");
00908                         return -1;
00909                 }
00910                 me = &(*mentryp)[*nmentryp - 1];
00911                 if (me->cont_count == me->max_count) {
00912                         struct magic *nm;
00913                         size_t cnt = me->max_count + ALLOC_CHUNK;
00914                         if ((nm = realloc(me->mp, sizeof(*nm) * cnt)) == NULL) {
00915                                 file_oomem(ms, sizeof(*nm) * cnt);
00916                                 return -1;
00917                         }
00918                         me->mp = m = nm;
00919                         me->max_count = cnt;
00920                 }
00921                 m = &me->mp[me->cont_count++];
00922                 (void)memset(m, 0, sizeof(*m));
00923                 m->cont_level = cont_level;
00924         } else {
00925                 if (*nmentryp == maxmagic) {
00926                         struct magic_entry *mp;
00927 
00928                 maxmagic += ALLOC_INCR;
00929 /*@i@*/                 if ((mp = realloc(*mentryp, sizeof(*mp) * maxmagic)) ==
00930                             NULL) {
00931                                 file_oomem(ms, sizeof(*mp) * maxmagic);
00932                         return -1;
00933                 }
00934                         (void)memset(&mp[*nmentryp], 0, sizeof(*mp) *
00935                             ALLOC_INCR);
00936                         *mentryp = mp;
00937                 }
00938                 me = &(*mentryp)[*nmentryp];
00939                 if (me->mp == NULL) {
00940                         if ((m = malloc(sizeof(*m) * ALLOC_CHUNK)) == NULL) {
00941                                 file_oomem(ms, sizeof(*m) * ALLOC_CHUNK);
00942                                 return -1;
00943         }
00944                         me->mp = m;
00945                         me->max_count = ALLOC_CHUNK;
00946                 } else
00947                         m = me->mp;
00948                 (void)memset(m, 0, sizeof(*m));
00949         m->cont_level = 0;
00950                 me->cont_count = 1;
00951         }
00952         m->lineno = lineno;
00953 
00954         if (*l == '&') {  /* m->cont_level == 0 checked below. */
00955                 ++l;            /* step over */
00956                 m->flag |= OFFADD;
00957         }
00958         if (*l == '(') {
00959                 ++l;            /* step over */
00960                 m->flag |= INDIR;
00961                 if (m->flag & OFFADD)
00962                         m->flag = (m->flag & ~OFFADD) | INDIROFFADD;
00963 
00964                 if (*l == '&') {  /* m->cont_level == 0 checked below */
00965                 ++l;            /* step over */
00966                 m->flag |= OFFADD;
00967         }
00968         }
00969         /* Indirect offsets are not valid at level 0. */
00970         if (m->cont_level == 0 && (m->flag & (OFFADD | INDIROFFADD)))
00971                 if (ms->flags & MAGIC_CHECK)
00972                         file_magwarn(ms, "relative offset at level 0");
00973 
00974         /* get offset, then skip over it */
00975         m->offset = (uint32_t)strtoul(l, &t, 0);
00976         if (l == t)
00977                 if (ms->flags & MAGIC_CHECK)
00978                         file_magwarn(ms, "offset `%s' invalid", l);
00979         l = t;
00980 
00981         if (m->flag & INDIR) {
00982                 m->in_type = FILE_LONG;
00983                 m->in_offset = 0;
00984                 /*
00985                  * read [.lbs][+-]nnnnn)
00986                  */
00987                 if (*l == '.') {
00988                         l++;
00989                         switch (*l) {
00990                         case 'l':
00991                                 m->in_type = FILE_LELONG;
00992                                 break;
00993                         case 'L':
00994                                 m->in_type = FILE_BELONG;
00995                                 break;
00996                         case 'm':
00997                                 m->in_type = FILE_MELONG;
00998                                 break;
00999                         case 'h':
01000                         case 's':
01001                                 m->in_type = FILE_LESHORT;
01002                                 break;
01003                         case 'H':
01004                         case 'S':
01005                                 m->in_type = FILE_BESHORT;
01006                                 break;
01007                         case 'c':
01008                         case 'b':
01009                         case 'C':
01010                         case 'B':
01011                                 m->in_type = FILE_BYTE;
01012                                 break;
01013                         default:
01014                                 if (ms->flags & MAGIC_CHECK)
01015                                         file_magwarn(ms,
01016                                             "indirect offset type `%c' invalid",
01017                                             *l);
01018                                 break;
01019                         }
01020                         l++;
01021                 }
01022 
01023                 m->in_op = 0;
01024                 if (*l == '~') {
01025                         m->in_op |= FILE_OPINVERSE;
01026                         l++;
01027                 }
01028                 if ((op = get_op(*l)) != -1) {
01029                         m->in_op |= op;
01030                         l++;
01031                 }
01032                 if (*l == '(') {
01033                         m->in_op |= FILE_OPINDIRECT;
01034                         l++;
01035                 }
01036                 if (isdigit((unsigned char)*l) || *l == '-') {
01037                         m->in_offset = (int32_t)strtol(l, &t, 0);
01038                         if (l == t)
01039                         if (ms->flags & MAGIC_CHECK)
01040                                 file_magwarn(ms,
01041                                             "in_offset `%s' invalid", l);
01042                 l = t;
01043         }
01044                 if (*l++ != ')' || 
01045                     ((m->in_op & FILE_OPINDIRECT) && *l++ != ')'))
01046                         if (ms->flags & MAGIC_CHECK)
01047                                 file_magwarn(ms,
01048                                     "missing ')' in indirect offset");
01049         }
01050         EATAB;
01051 
01052 #ifdef ENABLE_CONDITIONALS
01053         m->cond = get_cond(l, &l);
01054         if (check_cond(ms, m->cond, cont_level) == -1)
01055                 return -1;
01056 
01057         EATAB;
01058 #endif
01059 
01060         if (*l == 'u') {
01061                 ++l;
01062                 m->flag |= UNSIGNED;
01063         }
01064 
01065         m->type = get_type(l, &l);
01066         if (m->type == FILE_INVALID) {
01067                 if (ms->flags & MAGIC_CHECK)
01068                         file_magwarn(ms, "type `%s' invalid", l);
01069                 return -1;
01070         }
01071 
01072         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
01073         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
01074 
01075         m->mask_op = 0;
01076         if (*l == '~') {
01077                 if (!IS_STRING(m->type))
01078                         m->mask_op |= FILE_OPINVERSE;
01079                 else if (ms->flags & MAGIC_CHECK)
01080                         file_magwarn(ms, "'~' invalid for string types");
01081                 ++l;
01082         }
01083         m->str_count = 0;
01084         m->str_flags = 0;
01085         m->num_mask = 0;
01086         if ((op = get_op(*l)) != -1) {
01087                 if (!IS_STRING(m->type)) {
01088                         uint64_t val;
01089                         ++l;
01090                         m->mask_op |= op;
01091                         val = (uint64_t)strtoull(l, &t, 0);
01092                         l = t;
01093                         m->num_mask = file_signextend(ms, m, val);
01094                         eatsize(&l);
01095                 }
01096                 else if (op == FILE_OPDIVIDE) {
01097                         int have_count = 0;
01098                         while (!isspace((unsigned char)*++l)) {
01099                                 switch (*l) {
01100                                 /* for portability avoid "case '0' ... '9':" */
01101                                 case '0':  case '1':  case '2':
01102                                 case '3':  case '4':  case '5':
01103                                 case '6':  case '7':  case '8':
01104                                 case '9': {
01105                                         if (have_count && ms->flags & MAGIC_CHECK)
01106                                                 file_magwarn(ms,
01107                                                     "multiple counts");
01108                                         have_count = 1;
01109                                         m->str_count = strtoul(l, &t, 0);
01110                                         l = t - 1;
01111                                         /*@switchbreak@*/ break;
01112                                 }
01113                                 case CHAR_COMPACT_BLANK:
01114                                         m->str_flags |= STRING_COMPACT_BLANK;
01115                                         /*@switchbreak@*/ break;
01116                                 case CHAR_COMPACT_OPTIONAL_BLANK:
01117                                         m->str_flags |=
01118                                             STRING_COMPACT_OPTIONAL_BLANK;
01119                                         /*@switchbreak@*/ break;
01120                                 case CHAR_IGNORE_LOWERCASE:
01121                                         m->str_flags |= STRING_IGNORE_LOWERCASE;
01122                                         /*@switchbreak@*/ break;
01123                                 case CHAR_IGNORE_UPPERCASE:
01124                                         m->str_flags |= STRING_IGNORE_UPPERCASE;
01125                                         /*@switchbreak@*/ break;
01126                                 case CHAR_REGEX_OFFSET_START:
01127                                         m->str_flags |= REGEX_OFFSET_START;
01128                                         /*@switchbreak@*/ break;
01129                                 default:
01130                                         if (ms->flags & MAGIC_CHECK)
01131                                                 file_magwarn(ms,
01132                                                 "string extension `%c' invalid",
01133                                                 *l);
01134                                         return -1;
01135                                 }
01136                                 /* allow multiple '/' for readability */
01137                                 if (l[1] == '/' && !isspace((unsigned char)l[2]))
01138                                         l++;
01139                         }
01140                         if (string_modifier_check(ms, m) == -1)
01141                                 return -1;
01142                 }
01143                 else {
01144                         if (ms->flags & MAGIC_CHECK)
01145                                 file_magwarn(ms, "invalid string op: %c", *t);
01146                         return -1;
01147                 }
01148         }
01149         /*
01150          * We used to set mask to all 1's here, instead let's just not do
01151          * anything if mask = 0 (unless you have a better idea)
01152          */
01153         EATAB;
01154   
01155         switch (*l) {
01156         case '>':
01157         case '<':
01158         /* Old-style anding: "0 byte &0x80 dynamically linked" */
01159         case '&':
01160         case '^':
01161         case '=':
01162                 m->reln = *l;
01163                 ++l;
01164                 if (*l == '=') {
01165                    /* HP compat: ignore &= etc. */
01166                    ++l;
01167                 }
01168                 break;
01169         case '!':
01170                 m->reln = *l;
01171                 ++l;
01172                 break;
01173         default:
01174                 m->reln = '=';  /* the default relation */
01175                 if (*l == 'x' && ((isascii((unsigned char)l[1]) && 
01176                     isspace((unsigned char)l[1])) || !l[1])) {
01177                         m->reln = *l;
01178                         ++l;
01179                 }
01180                 break;
01181         }
01182         /*
01183          * Grab the value part, except for an 'x' reln.
01184          */
01185         if (m->reln != 'x' && getvalue(ms, m, &l, action))
01186                 return -1;
01187 
01188         /*
01189          * TODO finish this macro and start using it!
01190          * #define offsetcheck {if (offset > HOWMANY-1) 
01191          *      magwarn("offset too big"); }
01192          */
01193 
01194         /*
01195          * Now get last part - the description
01196          */
01197         EATAB;
01198         if (l[0] == '\b') {
01199                 ++l;
01200                 m->nospflag = 1;
01201         } else if ((l[0] == '\\') && (l[1] == 'b')) {
01202                 ++l;
01203                 ++l;
01204                 m->nospflag = 1;
01205         } else
01206                 m->nospflag = 0;
01207         for (i = 0; (m->desc[i++] = *l++) != '\0' && i < sizeof(m->desc); )
01208                 continue;
01209         if (i == sizeof(m->desc)) {
01210                 m->desc[sizeof(m->desc) - 1] = '\0';
01211                 if (ms->flags & MAGIC_CHECK)
01212                         file_magwarn(ms, "description `%s' truncated", m->desc);
01213         }
01214 
01215         /*
01216          * We only do this check while compiling, or if any of the magic
01217          * files were not compiled.
01218          */
01219         if (ms->flags & MAGIC_CHECK) {
01220                 if (check_format(ms, m) == -1)
01221                         return -1;
01222         }
01223 #ifndef COMPILE_ONLY
01224         if (action == FILE_CHECK) {
01225                 file_mdump(m);
01226         }
01227 #endif
01228         if (m->cont_level == 0)
01229                 ++(*nmentryp);          /* make room for next */
01230         return 0;
01231 }
01232 
01233 private int
01234 check_format_type(const char *ptr, int type)
01235 {
01236         int quad = 0;
01237         if (*ptr == '\0') {
01238                 /* Missing format string; bad */
01239                 return -1;
01240         }
01241 
01242         switch (type) {
01243         case FILE_FMT_QUAD:
01244                 quad = 1;
01245                 /*@fallthrough@*/
01246         case FILE_FMT_NUM:
01247                 if (*ptr == '-')
01248                         ptr++;
01249                 if (*ptr == '.')
01250                         ptr++;
01251                 while (isdigit((unsigned char)*ptr)) ptr++;
01252                 if (*ptr == '.')
01253                         ptr++;
01254                 while (isdigit((unsigned char)*ptr)) ptr++;
01255                 if (quad) {
01256                         if (*ptr++ != 'l')
01257                                 return -1;
01258                         if (*ptr++ != 'l')
01259                                 return -1;
01260                 }
01261         
01262                 switch (*ptr++) {
01263                 case 'l':
01264                         switch (*ptr++) {
01265                         case 'i':
01266                         case 'd':
01267                         case 'u':
01268                         case 'x':
01269                         case 'X':
01270                                 return 0;
01271                         default:
01272                                 return -1;
01273                         }
01274                 
01275                 case 'h':
01276                         switch (*ptr++) {
01277                         case 'h':
01278                                 switch (*ptr++) {
01279                                 case 'i':
01280                                 case 'd':
01281                                 case 'u':
01282                                 case 'x':
01283                                 case 'X':
01284                                         return 0;
01285                                 default:
01286                                         return -1;
01287                                 }
01288                         case 'd':
01289                                 return 0;
01290                         default:
01291                                 return -1;
01292                         }
01293 
01294                 case 'i':
01295                 case 'c':
01296                 case 'd':
01297                 case 'u':
01298                 case 'x':
01299                 case 'X':
01300                         return 0;
01301                         
01302                 default:
01303                         return -1;
01304                 }
01305                 
01306         case FILE_FMT_STR:
01307                 if (*ptr == '-')
01308                         ptr++;
01309                 while (isdigit((unsigned char )*ptr))
01310                         ptr++;
01311                 if (*ptr == '.') {
01312                         ptr++;
01313                         while (isdigit((unsigned char )*ptr))
01314                                 ptr++;
01315                 }
01316                 
01317                 switch (*ptr++) {
01318                 case 's':
01319         return 0;
01320                 default:
01321                         return -1;
01322                 }
01323                 
01324         default:
01325                 /* internal error */
01326                 abort();
01327         }
01328         /*@notreached@*/
01329         return -1;
01330 }
01331 
01332 /*
01333  * Check that the optional printf format in description matches
01334  * the type of the magic.
01335  */
01336 private int
01337 check_format(struct magic_set *ms, struct magic *m)
01338 {
01339         char *ptr;
01340 
01341         for (ptr = m->desc; *ptr; ptr++)
01342                 if (*ptr == '%')
01343                         break;
01344         if (*ptr == '\0') {
01345                 /* No format string; ok */
01346                 return 1;
01347         }
01348 
01349         assert(file_nformats == file_nnames);
01350 
01351         if (m->type >= file_nformats) {
01352                 file_error(ms, 0, "Internal error inconsistency between "
01353                     "m->type and format strings");              
01354                 return -1;
01355         }
01356         if (file_formats[m->type] == FILE_FMT_NONE) {
01357                 file_error(ms, 0, "No format string for `%s' with description "
01358                     "`%s'", m->desc, file_names[m->type]);
01359                 return -1;
01360         }
01361 
01362         ptr++;
01363         if (check_format_type(ptr, file_formats[m->type]) == -1) {
01364                 /*
01365                  * TODO: this error message is unhelpful if the format
01366                  * string is not one character long
01367                  */
01368                 file_error(ms, 0, "Printf format `%c' is not valid for type "
01369                     " `%s' in description `%s'", *ptr,
01370                     file_names[m->type], m->desc);
01371                 return -1;
01372                 }
01373         
01374         for (; *ptr; ptr++) {
01375                 if (*ptr == '%') {
01376                         file_error(ms, 0,
01377                             "Too many format strings (should have at most one) "
01378                             "for `%s' with description `%s'",
01379                             file_names[m->type], m->desc);
01380                         return -1;
01381         }
01382         }
01383                 return 0;
01384         }
01385 
01386 /* 
01387  * Read a numeric value from a pointer, into the value union of a magic 
01388  * pointer, according to the magic type.  Update the string pointer to point 
01389  * just after the number read.  Return 0 for success, non-zero for failure.
01390  */
01391 private int
01392 getvalue(struct magic_set *ms, struct magic *m, const char **p, int action)
01393 {
01394         int slen;
01395 
01396         switch (m->type) {
01397         case FILE_BESTRING16:
01398         case FILE_LESTRING16:
01399         case FILE_STRING:
01400         case FILE_PSTRING:
01401         case FILE_REGEX:
01402         case FILE_SEARCH:
01403 /*@i@*/         *p = getstr(ms, *p, m->value.s, sizeof(m->value.s), &slen, action);
01404                 if (*p == NULL) {
01405                         if (ms->flags & MAGIC_CHECK)
01406                                 file_magwarn(ms, "cannot get string from `%s'",
01407                                     m->value.s);
01408                         return -1;
01409                 }
01410                 m->vallen = slen;
01411                 return 0;
01412         default:
01413                 if (m->reln != 'x') {
01414                         char *ep;
01415                         m->value.q = file_signextend(ms, m,
01416                             (uint64_t)strtoull(*p, &ep, 0));
01417                         *p = ep;
01418                         eatsize(p);
01419                 }
01420                 return 0;
01421         }
01422 }
01423 
01424 /*
01425  * Convert a string containing C character escapes.  Stop at an unescaped
01426  * space or tab.
01427  * Copy the converted version to "p", returning its length in *slen.
01428  * Return updated scan pointer as function result.
01429  */
01430 private const char *
01431 getstr(struct magic_set *ms, const char *s, char *p, int plen, int *slen, int action)
01432 {
01433         const char *origs = s;
01434         char    *origp = p;
01435         char    *pmax = p + plen - 1;
01436         int     c;
01437         int     val;
01438 
01439         while ((c = *s++) != '\0') {
01440                 if (isspace((unsigned char) c))
01441                         break;
01442                 if (p >= pmax) {
01443                         file_error(ms, 0, "string too long: `%s'", origs);
01444                         return NULL;
01445                 }
01446                 if(c == '\\') {
01447                         switch(c = *s++) {
01448 
01449                         case '\0':
01450                                 if (action == FILE_COMPILE)
01451                                         file_magwarn(ms, "incomplete escape");
01452                                 goto out;
01453 
01454                         case '\t':
01455                                 if (action == FILE_COMPILE) {
01456                                         file_magwarn(ms,
01457                                             "escaped tab found, use \\t instead");
01458                                         action++;
01459                                 }
01460                                 /*@fallthrough@*/
01461                         default:
01462                                 if (action == FILE_COMPILE) {
01463                                         if (isprint((unsigned char)c))
01464                                             file_magwarn(ms,
01465                                                 "no need to escape `%c'", c);
01466                                         else
01467                                             file_magwarn(ms,
01468                                                 "unknown escape sequence: \\%03o", c);
01469                                 }
01470                                 /*@fallthrough@*/
01471                         /* space, perhaps force people to use \040? */
01472                         case ' ':
01473 #if 0
01474                         /*
01475                          * Other things people escape, but shouldn't need to,
01476                          * so we disallow them
01477                          */
01478                         case '\'':
01479                         case '"':
01480                         case '?':
01481 #endif
01482                         /* Relations */
01483                         case '>':
01484                         case '<':
01485                         case '&':
01486                         case '^':
01487                         case '=':
01488                         case '!':
01489                         /* and baskslash itself */
01490                         case '\\':
01491                                 *p++ = (char) c;
01492                                 /*@switchbreak@*/ break;
01493 
01494                         case 'a':
01495                                 *p++ = '\a';
01496                                 /*@switchbreak@*/ break;
01497 
01498                         case 'b':
01499                                 *p++ = '\b';
01500                                 /*@switchbreak@*/ break;
01501 
01502                         case 'f':
01503                                 *p++ = '\f';
01504                                 /*@switchbreak@*/ break;
01505 
01506                         case 'n':
01507                                 *p++ = '\n';
01508                                 /*@switchbreak@*/ break;
01509 
01510                         case 'r':
01511                                 *p++ = '\r';
01512                                 /*@switchbreak@*/ break;
01513 
01514                         case 't':
01515                                 *p++ = '\t';
01516                                 /*@switchbreak@*/ break;
01517 
01518                         case 'v':
01519                                 *p++ = '\v';
01520                                 /*@switchbreak@*/ break;
01521 
01522                         /* \ and up to 3 octal digits */
01523                         case '0':
01524                         case '1':
01525                         case '2':
01526                         case '3':
01527                         case '4':
01528                         case '5':
01529                         case '6':
01530                         case '7':
01531                                 val = c - '0';
01532                                 c = *s++;  /* try for 2 */
01533                                 if(c >= '0' && c <= '7') {
01534                                         val = (val<<3) | (c - '0');
01535                                         c = *s++;  /* try for 3 */
01536                                         if(c >= '0' && c <= '7')
01537                                                 val = (val<<3) | (c-'0');
01538                                         else
01539                                                 --s;
01540                                 }
01541                                 else
01542                                         --s;
01543                                 *p++ = (char)val;
01544                                 /*@switchbreak@*/ break;
01545 
01546                         /* \x and up to 2 hex digits */
01547                         case 'x':
01548                                 val = 'x';      /* Default if no digits */
01549                                 c = hextoint(*s++);     /* Get next char */
01550                                 if (c >= 0) {
01551                                         val = c;
01552                                         c = hextoint(*s++);
01553                                         if (c >= 0)
01554                                                 val = (val << 4) + c;
01555                                         else
01556                                                 --s;
01557                                 } else
01558                                         --s;
01559                                 *p++ = (char)val;
01560                                 /*@switchbreak@*/ break;
01561                         }
01562                 } else
01563                         *p++ = (char)c;
01564         }
01565 out:
01566         *p = '\0';
01567         *slen = p - origp;
01568         return s;
01569 }
01570 
01571 
01572 /* Single hex char to int; -1 if not a hex char. */
01573 private int
01574 hextoint(int c)
01575 {
01576         if (!isascii((unsigned char) c))
01577                 return -1;
01578         if (isdigit((unsigned char) c))
01579                 return c - '0';
01580         if ((c >= 'a')&&(c <= 'f'))
01581                 return c + 10 - 'a';
01582         if (( c>= 'A')&&(c <= 'F'))
01583                 return c + 10 - 'A';
01584         return -1;
01585 }
01586 
01587 
01588 /*
01589  * Print a string containing C character escapes.
01590  */
01591 protected void
01592 file_showstr(FILE *fp, const char *s, size_t len)
01593 {
01594         char    c;
01595 
01596         for (;;) {
01597                 c = *s++;
01598                 if (len == ~0U) {
01599                         if (c == '\0')
01600                                 break;
01601                 }
01602                 else  {
01603                         if (len-- == 0)
01604                                 break;
01605                 }
01606                 if(c >= 040 && c <= 0176)       /* TODO isprint && !iscntrl */
01607                         (void) fputc(c, fp);
01608                 else {
01609                         (void) fputc('\\', fp);
01610                         switch (c) {
01611                         case '\a':
01612                                 (void) fputc('a', fp);
01613                                 /*@switchbreak@*/ break;
01614 
01615                         case '\b':
01616                                 (void) fputc('b', fp);
01617                                 /*@switchbreak@*/ break;
01618 
01619                         case '\f':
01620                                 (void) fputc('f', fp);
01621                                 /*@switchbreak@*/ break;
01622                         
01623                         case '\n':
01624                                 (void) fputc('n', fp);
01625                                 /*@switchbreak@*/ break;
01626 
01627                         case '\r':
01628                                 (void) fputc('r', fp);
01629                                 /*@switchbreak@*/ break;
01630 
01631                         case '\t':
01632                                 (void) fputc('t', fp);
01633                                 /*@switchbreak@*/ break;
01634 
01635                         case '\v':
01636                                 (void) fputc('v', fp);
01637                                 /*@switchbreak@*/ break;
01638 
01639                         default:
01640                                 (void) fprintf(fp, "%.3o", c & 0377);
01641                                 /*@switchbreak@*/ break;
01642                         }
01643                 }
01644         }
01645 }
01646 
01647 /*
01648  * eatsize(): Eat the size spec from a number [eg. 10UL]
01649  */
01650 private void
01651 eatsize(const char **p)
01652 {
01653         const char *l = *p;
01654 
01655         if (LOWCASE(*l) == 'u') 
01656                 l++;
01657 
01658         switch (LOWCASE(*l)) {
01659         case 'l':    /* long */
01660         case 's':    /* short */
01661         case 'h':    /* short */
01662         case 'b':    /* char/byte */
01663         case 'c':    /* char/byte */
01664                 l++;
01665                 /*@fallthrough@*/
01666         default:
01667                 break;
01668         }
01669 
01670         *p = l;
01671 }
01672 
01673 /*
01674  * handle a compiled file.
01675  */
01676 private int
01677 apprentice_map(struct magic_set *ms, struct magic **magicp, uint32_t *nmagicp,
01678     const char *fn)
01679 {
01680         int fd;
01681         struct stat st;
01682         uint32_t *ptr;
01683         uint32_t version;
01684         int needsbyteswap;
01685         char buf[MAXPATHLEN];
01686         char *dbname = mkdbname(fn, buf, sizeof(buf), 0);
01687         void *mm = NULL;
01688 
01689         if (dbname == NULL)
01690                 return -1;
01691 
01692         if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1)
01693                 return -1;
01694 
01695         if (fstat(fd, &st) == -1) {
01696                 file_error(ms, errno, "cannot stat `%s'", dbname);
01697                 goto error;
01698         }
01699         if (st.st_size < 16) {
01700                 file_error(ms, 0, "file `%s' is too small", dbname);
01701                 goto error;
01702         }
01703 
01704 #ifdef QUICK
01705         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
01706             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
01707                 file_error(ms, errno, "cannot map `%s'", dbname);
01708                 goto error;
01709         }
01710 #define RET     2
01711 #else
01712         if ((mm = malloc((size_t)st.st_size)) == NULL) {
01713                 file_oomem(ms, (size_t)st.st_size);
01714                 goto error;
01715         }
01716         if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
01717                 file_badread(ms);
01718                 goto error;
01719         }
01720 #define RET     1
01721 #endif
01722         *magicp = mm;
01723         (void)close(fd);
01724         fd = -1;
01725         ptr = (uint32_t *)(void *)*magicp;
01726         if (*ptr != MAGICNO) {
01727                 if (swap4(*ptr) != MAGICNO) {
01728                         file_error(ms, 0, "bad magic in `%s'");
01729                         goto error;
01730                 }
01731                 needsbyteswap = 1;
01732         } else
01733                 needsbyteswap = 0;
01734         if (needsbyteswap)
01735                 version = swap4(ptr[1]);
01736         else
01737                 version = ptr[1];
01738         if (version != VERSIONNO) {
01739                 file_error(ms, 0, "version mismatch (%d != %d) in `%s'",
01740                     version, VERSIONNO, dbname);
01741                 goto error;
01742         }
01743         *nmagicp = (uint32_t)(st.st_size / sizeof(struct magic)) - 1;
01744         (*magicp)++;
01745         if (needsbyteswap)
01746                 byteswap(*magicp, *nmagicp);
01747         return RET;
01748 
01749 error:
01750         if (fd != -1)
01751                 (void)close(fd);
01752         if (mm) {
01753 #ifdef QUICK
01754                 (void)munmap((void *)mm, (size_t)st.st_size);
01755 #else
01756                 free(mm);
01757 #endif
01758         } else {
01759                 *magicp = NULL;
01760                 *nmagicp = 0;
01761         }
01762         return -1;
01763 }
01764 
01765 /*@unchecked@*/ /*@observer@*/
01766 private const uint32_t ar[] = {
01767     MAGICNO, VERSIONNO
01768 };
01769 /*
01770  * handle an mmaped file.
01771  */
01772 private int
01773 apprentice_compile(struct magic_set *ms, struct magic **magicp,
01774     uint32_t *nmagicp, const char *fn)
01775 {
01776         int fd;
01777         char buf[MAXPATHLEN];
01778         char *dbname = mkdbname(fn, buf, sizeof(buf), 1);
01779 
01780         if (dbname == NULL) 
01781                 return -1;
01782 
01783         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) {
01784                 file_error(ms, errno, "cannot open `%s'", dbname);
01785                 return -1;
01786         }
01787 
01788         if (write(fd, ar, sizeof(ar)) != (ssize_t)sizeof(ar)) {
01789                 file_error(ms, errno, "error writing `%s'", dbname);
01790                 return -1;
01791         }
01792 
01793         if (lseek(fd, (off_t)sizeof(struct magic), SEEK_SET)
01794             != sizeof(struct magic)) {
01795                 file_error(ms, errno, "error seeking `%s'", dbname);
01796                 return -1;
01797         }
01798 
01799         if (write(fd, *magicp, (sizeof(struct magic) * *nmagicp)) 
01800             != (ssize_t)(sizeof(struct magic) * *nmagicp)) {
01801                 file_error(ms, errno, "error writing `%s'", dbname);
01802                 return -1;
01803         }
01804 
01805         (void)close(fd);
01806         return 0;
01807 }
01808 
01809 /*@unchecked@*/ /*@observer@*/
01810 private const char ext[] = ".mgc";
01811 /*
01812  * make a dbname
01813  */
01814 private char *
01815 mkdbname(const char *fn, char *buf, size_t bufsiz, int strip)
01816 {
01817         if (strip) {
01818                 const char *p;
01819                 if ((p = strrchr(fn, '/')) != NULL)
01820                         fn = ++p;
01821         }
01822 
01823         (void)snprintf(buf, bufsiz, "%s%s", fn, ext);
01824         return buf;
01825 }
01826 
01827 /*
01828  * Byteswap an mmap'ed file if needed
01829  */
01830 private void
01831 byteswap(struct magic *magic, uint32_t nmagic)
01832 {
01833         uint32_t i;
01834         for (i = 0; i < nmagic; i++)
01835                 bs1(&magic[i]);
01836 }
01837 
01838 /*
01839  * swap a short
01840  */
01841 private uint16_t
01842 swap2(uint16_t sv)
01843 {
01844         uint16_t rv;
01845         uint8_t *s = (uint8_t *)(void *)&sv; 
01846         uint8_t *d = (uint8_t *)(void *)&rv; 
01847         d[0] = s[1];
01848         d[1] = s[0];
01849         return rv;
01850 }
01851 
01852 /*
01853  * swap an int
01854  */
01855 private uint32_t
01856 swap4(uint32_t sv)
01857 {
01858         uint32_t rv;
01859         uint8_t *s = (uint8_t *)(void *)&sv; 
01860         uint8_t *d = (uint8_t *)(void *)&rv; 
01861         d[0] = s[3];
01862         d[1] = s[2];
01863         d[2] = s[1];
01864         d[3] = s[0];
01865         return rv;
01866 }
01867 
01868 /*
01869  * swap a quad
01870  */
01871 private uint64_t
01872 swap8(uint64_t sv)
01873 {
01874         uint32_t rv;
01875         uint8_t *s = (uint8_t *)(void *)&sv; 
01876         uint8_t *d = (uint8_t *)(void *)&rv; 
01877         d[0] = s[3];
01878         d[1] = s[2];
01879         d[2] = s[1];
01880         d[3] = s[0];
01881         d[4] = s[7];
01882         d[5] = s[6];
01883         d[6] = s[5];
01884         d[7] = s[4];
01885         return rv;
01886 }
01887 
01888 /*
01889  * byteswap a single magic entry
01890  */
01891 private void
01892 bs1(struct magic *m)
01893 {
01894         m->cont_level = swap2(m->cont_level);
01895         m->offset = swap4((uint32_t)m->offset);
01896         m->in_offset = swap4((uint32_t)m->in_offset);
01897         m->lineno = swap4((uint32_t)m->lineno);
01898         if (IS_STRING(m->type)) {
01899                 m->str_count = swap4(m->str_count);
01900                 m->str_flags = swap4(m->str_flags);
01901         }
01902         else {
01903                 m->value.q = swap8(m->value.q);
01904                 m->num_mask = swap8(m->num_mask);
01905         }
01906 }

Generated on Fri Aug 31 11:02:21 2007 for rpm by  doxygen 1.5.1