Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

file/apprentice.c

Go to the documentation of this file.
00001 /*
00002  * apprentice - make one pass through /etc/magic, learning its secrets.
00003  *
00004  * Copyright (c) Ian F. Darwin, 1987.
00005  * Written by Ian F. Darwin.
00006  *
00007  * This software is not subject to any license of the American Telephone
00008  * and Telegraph Company or of the Regents of the University of California.
00009  *
00010  * Permission is granted to anyone to use this software for any purpose on
00011  * any computer system, and to alter it and redistribute it freely, subject
00012  * to the following restrictions:
00013  *
00014  * 1. The author is not responsible for the consequences of use of this
00015  *    software, no matter how awful, even if they arise from flaws in it.
00016  *
00017  * 2. The origin of this software must not be misrepresented, either by
00018  *    explicit claim or by omission.  Since few users ever read sources,
00019  *    credits must appear in the documentation.
00020  *
00021  * 3. Altered versions must be plainly marked as such, and must not be
00022  *    misrepresented as being the original software.  Since few users
00023  *    ever read sources, credits must appear in the documentation.
00024  *
00025  * 4. This notice may not be removed or altered.
00026  */
00027 
00028 #include "system.h"
00029 #include "file.h"
00030 #include "debug.h"
00031 
00032 FILE_RCSID("@(#)Id: apprentice.c,v 1.49 2002/07/03 19:00:41 christos Exp ")
00033 
00034 /*@access fmagic @*/
00035 
00036 #define EATAB {while (isascii((unsigned char) *l) && \
00037                       isspace((unsigned char) *l))  ++l;}
00038 #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
00039                         tolower((unsigned char) (l)) : (l))
00040 /*
00041  * Work around a bug in headers on Digital Unix.
00042  * At least confirmed for: OSF1 V4.0 878
00043  */
00044 #if defined(__osf__) && defined(__DECC)
00045 #ifdef MAP_FAILED
00046 #undef MAP_FAILED
00047 #endif
00048 #endif
00049 
00050 #ifndef MAP_FAILED
00051 #define MAP_FAILED (void *) -1
00052 #endif
00053 
00054 #ifndef MAP_FILE
00055 #define MAP_FILE 0
00056 #endif
00057 
00058 /*@unchecked@*/
00059 #ifdef __EMX__
00060   static char PATHSEP=';';
00061 #else
00062   static char PATHSEP=':';
00063 #endif
00064 
00065 /*@unchecked@*/
00066 static int maxmagic = 0;
00067 
00068 #ifndef MAGIC
00069 # define MAGIC "/etc/magic"
00070 #endif
00071 
00072 /*@unchecked@*/ /*@observer@*/
00073 const char *default_magicfile = MAGIC;
00074 
00075 /*
00076  * extend the sign bit if the comparison is to be signed
00077  */
00078 uint32_t
00079 signextend(struct magic *m, uint32_t v)
00080 {
00081         if (!(m->flag & UNSIGNED))
00082                 switch(m->type) {
00083                 /*
00084                  * Do not remove the casts below.  They are
00085                  * vital.  When later compared with the data,
00086                  * the sign extension must have happened.
00087                  */
00088                 case BYTE:
00089                         v = (char) v;
00090                         break;
00091                 case SHORT:
00092                 case BESHORT:
00093                 case LESHORT:
00094                         v = (short) v;
00095                         break;
00096                 case DATE:
00097                 case BEDATE:
00098                 case LEDATE:
00099                 case LDATE:
00100                 case BELDATE:
00101                 case LELDATE:
00102                 case LONG:
00103                 case BELONG:
00104                 case LELONG:
00105                         v = (int32_t) v;
00106                         break;
00107                 case STRING:
00108                 case PSTRING:
00109                         break;
00110                 case REGEX:
00111                         break;
00112                 default:
00113                         magwarn("can't happen: m->type=%d\n", m->type);
00114                         return -1;
00115                 }
00116         return v;
00117 }
00118 
00119 /*
00120  * eatsize(): Eat the size spec from a number [eg. 10UL]
00121  */
00122 /*@-bounds@*/
00123 static void
00124 eatsize(/*@out@*/ char **p)
00125         /*@modifies *p @*/
00126 {
00127         char *l = *p;
00128 
00129         if (LOWCASE(*l) == 'u') 
00130                 l++;
00131 
00132         switch (LOWCASE(*l)) {
00133         case 'l':    /* long */
00134         case 's':    /* short */
00135         case 'h':    /* short */
00136         case 'b':    /* char/byte */
00137         case 'c':    /* char/byte */
00138                 l++;
00139                 /*@fallthrough@*/
00140         default:
00141                 break;
00142         }
00143 
00144         *p = l;
00145 }
00146 /*@=bounds@*/
00147 
00148 /* Single hex char to int; -1 if not a hex char. */
00149 static int
00150 hextoint(int c)
00151         /*@*/
00152 {
00153         if (!isascii((unsigned char) c))
00154                 return -1;
00155         if (isdigit((unsigned char) c))
00156                 return c - '0';
00157         if ((c >= 'a')&&(c <= 'f'))
00158                 return c + 10 - 'a';
00159         if (( c>= 'A')&&(c <= 'F'))
00160                 return c + 10 - 'A';
00161         return -1;
00162 }
00163 
00164 /*
00165  * Convert a string containing C character escapes.  Stop at an unescaped
00166  * space or tab.
00167  * Copy the converted version to "p", returning its length in *slen.
00168  * Return updated scan pointer as function result.
00169  */
00170 /*@-shiftimplementation@*/
00171 /*@-bounds@*/
00172 static char *
00173 getstr(/*@returned@*/ char *s, char *p, int plen, /*@out@*/ int *slen)
00174         /*@globals fileSystem @*/
00175         /*@modifies *p, *slen, fileSystem @*/
00176 {
00177         char    *origs = s, *origp = p;
00178         char    *pmax = p + plen - 1;
00179         int     c;
00180         int     val;
00181 
00182         while ((c = *s++) != '\0') {
00183                 if (isspace((unsigned char) c))
00184                         break;
00185                 if (p >= pmax) {
00186                         fprintf(stderr, "String too long: %s\n", origs);
00187                         break;
00188                 }
00189                 if(c == '\\') {
00190                         switch(c = *s++) {
00191 
00192                         case '\0':
00193                                 goto out;
00194 
00195                         default:
00196                                 *p++ = (char) c;
00197                                 /*@switchbreak@*/ break;
00198 
00199                         case 'n':
00200                                 *p++ = '\n';
00201                                 /*@switchbreak@*/ break;
00202 
00203                         case 'r':
00204                                 *p++ = '\r';
00205                                 /*@switchbreak@*/ break;
00206 
00207                         case 'b':
00208                                 *p++ = '\b';
00209                                 /*@switchbreak@*/ break;
00210 
00211                         case 't':
00212                                 *p++ = '\t';
00213                                 /*@switchbreak@*/ break;
00214 
00215                         case 'f':
00216                                 *p++ = '\f';
00217                                 /*@switchbreak@*/ break;
00218 
00219                         case 'v':
00220                                 *p++ = '\v';
00221                                 /*@switchbreak@*/ break;
00222 
00223                         /* \ and up to 3 octal digits */
00224                         case '0':
00225                         case '1':
00226                         case '2':
00227                         case '3':
00228                         case '4':
00229                         case '5':
00230                         case '6':
00231                         case '7':
00232                                 val = c - '0';
00233                                 c = *s++;  /* try for 2 */
00234                                 if(c >= '0' && c <= '7') {
00235                                         val = (val<<3) | (c - '0');
00236                                         c = *s++;  /* try for 3 */
00237                                         if(c >= '0' && c <= '7')
00238                                                 val = (val<<3) | (c-'0');
00239                                         else
00240                                                 --s;
00241                                 }
00242                                 else
00243                                         --s;
00244                                 *p++ = (char)val;
00245                                 /*@switchbreak@*/ break;
00246 
00247                         /* \x and up to 2 hex digits */
00248                         case 'x':
00249                                 val = 'x';      /* Default if no digits */
00250                                 c = hextoint(*s++);     /* Get next char */
00251                                 if (c >= 0) {
00252                                         val = c;
00253                                         c = hextoint(*s++);
00254                                         if (c >= 0)
00255                                                 val = (val << 4) + c;
00256                                         else
00257                                                 --s;
00258                                 } else
00259                                         --s;
00260                                 *p++ = (char)val;
00261                                 /*@switchbreak@*/ break;
00262                         }
00263                 } else
00264                         *p++ = (char)c;
00265         }
00266 out:
00267         *p = '\0';
00268         *slen = p - origp;
00269         return s;
00270 }
00271 /*@=bounds@*/
00272 /*@=shiftimplementation@*/
00273 
00274 /* 
00275  * Read a numeric value from a pointer, into the value union of a magic 
00276  * pointer, according to the magic type.  Update the string pointer to point 
00277  * just after the number read.  Return 0 for success, non-zero for failure.
00278  */
00279 /*@-bounds@*/
00280 static int
00281 getvalue(struct magic *m, /*@out@*/ char **p)
00282         /*@globals fileSystem @*/
00283         /*@modifies m, *p, fileSystem @*/
00284 {
00285         int slen;
00286 
00287         if (m->type == STRING || m->type == PSTRING || m->type == REGEX) {
00288                 *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
00289                 m->vallen = slen;
00290         } else
00291                 if (m->reln != 'x') {
00292                         m->value.l = signextend(m, strtoul(*p, p, 0));
00293                         eatsize(p);
00294                 }
00295         return 0;
00296 }
00297 /*@=bounds@*/
00298 
00299 /*
00300  * parse one line from magic file, put into magic[index++] if valid
00301  */
00302 /*@-bounds@*/
00303 static int
00304 parse(/*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
00305                 char *l, int action)
00306         /*@globals maxmagic, fileSystem @*/
00307         /*@modifies *magicp, *nmagicp, maxmagic, fileSystem @*/
00308 {
00309         int i = 0;
00310         struct magic *m;
00311         char *t;
00312 
00313 #define ALLOC_INCR      200
00314         if (*nmagicp + 1 >= maxmagic){
00315                 maxmagic += ALLOC_INCR;
00316 /*@-unqualifiedtrans @*/
00317                 *magicp = xrealloc(*magicp, sizeof(**magicp) * maxmagic);
00318 /*@=unqualifiedtrans @*/
00319                 m = &(*magicp)[*nmagicp];
00320                 memset(m, 0, sizeof(**magicp) * ALLOC_INCR);
00321         } else
00322                 m = &(*magicp)[*nmagicp];
00323         m->flag = 0;
00324         m->cont_level = 0;
00325 
00326         while (*l == '>') {
00327                 ++l;            /* step over */
00328                 m->cont_level++; 
00329         }
00330 
00331         if (m->cont_level != 0 && *l == '(') {
00332                 ++l;            /* step over */
00333                 m->flag |= INDIR;
00334         }
00335         if (m->cont_level != 0 && *l == '&') {
00336                 ++l;            /* step over */
00337                 m->flag |= OFFADD;
00338         }
00339 
00340         /* get offset, then skip over it */
00341         m->offset = (int) strtoul(l,&t,0);
00342         if (l == t)
00343                 magwarn("offset %s invalid", l);
00344         l = t;
00345 
00346         if (m->flag & INDIR) {
00347                 m->in_type = LONG;
00348                 m->in_offset = 0;
00349                 /*
00350                  * read [.lbs][+-]nnnnn)
00351                  */
00352                 if (*l == '.') {
00353                         l++;
00354                         switch (*l) {
00355                         case 'l':
00356                                 m->in_type = LELONG;
00357                                 break;
00358                         case 'L':
00359                                 m->in_type = BELONG;
00360                                 break;
00361                         case 'h':
00362                         case 's':
00363                                 m->in_type = LESHORT;
00364                                 break;
00365                         case 'H':
00366                         case 'S':
00367                                 m->in_type = BESHORT;
00368                                 break;
00369                         case 'c':
00370                         case 'b':
00371                         case 'C':
00372                         case 'B':
00373                                 m->in_type = BYTE;
00374                                 break;
00375                         default:
00376                                 magwarn("indirect offset type %c invalid", *l);
00377                                 break;
00378                         }
00379                         l++;
00380                 }
00381                 if (*l == '~') {
00382                         m->in_op = OPINVERSE;
00383                         l++;
00384                 }
00385                 switch (*l) {
00386                 case '&':
00387                         m->in_op |= OPAND;
00388                         l++;
00389                         break;
00390                 case '|':
00391                         m->in_op |= OPOR;
00392                         l++;
00393                         break;
00394                 case '^':
00395                         m->in_op |= OPXOR;
00396                         l++;
00397                         break;
00398                 case '+':
00399                         m->in_op |= OPADD;
00400                         l++;
00401                         break;
00402                 case '-':
00403                         m->in_op |= OPMINUS;
00404                         l++;
00405                         break;
00406                 case '*':
00407                         m->in_op |= OPMULTIPLY;
00408                         l++;
00409                         break;
00410                 case '/':
00411                         m->in_op |= OPDIVIDE;
00412                         l++;
00413                         break;
00414                 case '%':
00415                         m->in_op |= OPMODULO;
00416                         l++;
00417                         break;
00418                 }
00419                 if (isdigit((unsigned char)*l)) 
00420                         m->in_offset = strtoul(l, &t, 0);
00421                 else
00422                         t = l;
00423                 if (*t++ != ')') 
00424                         magwarn("missing ')' in indirect offset");
00425                 l = t;
00426         }
00427 
00428 
00429         while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
00430                 ++l;
00431         EATAB;
00432 
00433 #define NBYTE           4
00434 #define NSHORT          5
00435 #define NLONG           4
00436 #define NSTRING         6
00437 #define NDATE           4
00438 #define NBESHORT        7
00439 #define NBELONG         6
00440 #define NBEDATE         6
00441 #define NLESHORT        7
00442 #define NLELONG         6
00443 #define NLEDATE         6
00444 #define NPSTRING        7
00445 #define NLDATE          5
00446 #define NBELDATE        7
00447 #define NLELDATE        7
00448 #define NREGEX          5
00449 
00450         if (*l == 'u') {
00451                 ++l;
00452                 m->flag |= UNSIGNED;
00453         }
00454 
00455         /* get type, skip it */
00456         if (strncmp(l, "char", NBYTE)==0) {     /* HP/UX compat */
00457                 m->type = BYTE;
00458                 l += NBYTE;
00459         } else if (strncmp(l, "byte", NBYTE)==0) {
00460                 m->type = BYTE;
00461                 l += NBYTE;
00462         } else if (strncmp(l, "short", NSHORT)==0) {
00463                 m->type = SHORT;
00464                 l += NSHORT;
00465         } else if (strncmp(l, "long", NLONG)==0) {
00466                 m->type = LONG;
00467                 l += NLONG;
00468         } else if (strncmp(l, "string", NSTRING)==0) {
00469                 m->type = STRING;
00470                 l += NSTRING;
00471         } else if (strncmp(l, "date", NDATE)==0) {
00472                 m->type = DATE;
00473                 l += NDATE;
00474         } else if (strncmp(l, "beshort", NBESHORT)==0) {
00475                 m->type = BESHORT;
00476                 l += NBESHORT;
00477         } else if (strncmp(l, "belong", NBELONG)==0) {
00478                 m->type = BELONG;
00479                 l += NBELONG;
00480         } else if (strncmp(l, "bedate", NBEDATE)==0) {
00481                 m->type = BEDATE;
00482                 l += NBEDATE;
00483         } else if (strncmp(l, "leshort", NLESHORT)==0) {
00484                 m->type = LESHORT;
00485                 l += NLESHORT;
00486         } else if (strncmp(l, "lelong", NLELONG)==0) {
00487                 m->type = LELONG;
00488                 l += NLELONG;
00489         } else if (strncmp(l, "ledate", NLEDATE)==0) {
00490                 m->type = LEDATE;
00491                 l += NLEDATE;
00492         } else if (strncmp(l, "pstring", NPSTRING)==0) {
00493                 m->type = PSTRING;
00494                 l += NPSTRING;
00495         } else if (strncmp(l, "ldate", NLDATE)==0) {
00496                 m->type = LDATE;
00497                 l += NLDATE;
00498         } else if (strncmp(l, "beldate", NBELDATE)==0) {
00499                 m->type = BELDATE;
00500                 l += NBELDATE;
00501         } else if (strncmp(l, "leldate", NLELDATE)==0) {
00502                 m->type = LELDATE;
00503                 l += NLELDATE;
00504         } else if (strncmp(l, "regex", NREGEX)==0) {
00505                 m->type = REGEX;
00506                 l += sizeof("regex");
00507         } else {
00508                 magwarn("type %s invalid", l);
00509                 return -1;
00510         }
00511         /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
00512         /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
00513         if (*l == '~') {
00514                 if (STRING != m->type && PSTRING != m->type)
00515                         m->mask_op = OPINVERSE;
00516                 ++l;
00517         }
00518         switch (*l) {
00519         case '&':
00520                 m->mask_op |= OPAND;
00521                 ++l;
00522                 m->mask = signextend(m, strtoul(l, &l, 0));
00523                 eatsize(&l);
00524                 break;
00525         case '|':
00526                 m->mask_op |= OPOR;
00527                 ++l;
00528                 m->mask = signextend(m, strtoul(l, &l, 0));
00529                 eatsize(&l);
00530                 break;
00531         case '^':
00532                 m->mask_op |= OPXOR;
00533                 ++l;
00534                 m->mask = signextend(m, strtoul(l, &l, 0));
00535                 eatsize(&l);
00536                 break;
00537         case '+':
00538                 m->mask_op |= OPADD;
00539                 ++l;
00540                 m->mask = signextend(m, strtoul(l, &l, 0));
00541                 eatsize(&l);
00542                 break;
00543         case '-':
00544                 m->mask_op |= OPMINUS;
00545                 ++l;
00546                 m->mask = signextend(m, strtoul(l, &l, 0));
00547                 eatsize(&l);
00548                 break;
00549         case '*':
00550                 m->mask_op |= OPMULTIPLY;
00551                 ++l;
00552                 m->mask = signextend(m, strtoul(l, &l, 0));
00553                 eatsize(&l);
00554                 break;
00555         case '%':
00556                 m->mask_op |= OPMODULO;
00557                 ++l;
00558                 m->mask = signextend(m, strtoul(l, &l, 0));
00559                 eatsize(&l);
00560                 break;
00561         case '/':
00562                 if (STRING != m->type && PSTRING != m->type) {
00563                         m->mask_op |= OPDIVIDE;
00564                         ++l;
00565                         m->mask = signextend(m, strtoul(l, &l, 0));
00566                         eatsize(&l);
00567                 } else {
00568                         m->mask = 0L;
00569                         while (!isspace(*++l)) {
00570                                 switch (*l) {
00571                                 case CHAR_IGNORE_LOWERCASE:
00572                                         m->mask |= STRING_IGNORE_LOWERCASE;
00573                                         /*@switchbreak@*/ break;
00574                                 case CHAR_COMPACT_BLANK:
00575                                         m->mask |= STRING_COMPACT_BLANK;
00576                                         /*@switchbreak@*/ break;
00577                                 case CHAR_COMPACT_OPTIONAL_BLANK:
00578                                         m->mask |=
00579                                             STRING_COMPACT_OPTIONAL_BLANK;
00580                                         /*@switchbreak@*/ break;
00581                                 default:
00582                                         magwarn("string extension %c invalid",
00583                                             *l);
00584                                         return -1;
00585                                 }
00586                         }
00587                 }
00588                 break;
00589         }
00590         /* We used to set mask to all 1's here, instead let's just not do anything 
00591            if mask = 0 (unless you have a better idea) */
00592         EATAB;
00593   
00594         switch (*l) {
00595         case '>':
00596         case '<':
00597         /* Old-style anding: "0 byte &0x80 dynamically linked" */
00598         case '&':
00599         case '^':
00600         case '=':
00601                 m->reln = *l;
00602                 ++l;
00603                 if (*l == '=') {
00604                    /* HP compat: ignore &= etc. */
00605                    ++l;
00606                 }
00607                 break;
00608         case '!':
00609                 if (m->type != STRING && m->type != PSTRING) {
00610                         m->reln = *l;
00611                         ++l;
00612                         break;
00613                 }
00614                 /*@fallthrough@*/
00615         default:
00616                 if (*l == 'x' && isascii((unsigned char)l[1]) && 
00617                     isspace((unsigned char)l[1])) {
00618                         m->reln = *l;
00619                         ++l;
00620                         goto GetDesc;   /* Bill The Cat */
00621                 }
00622                 m->reln = '=';
00623                 break;
00624         }
00625         EATAB;
00626   
00627         if (getvalue(m, &l))
00628                 return -1;
00629         /*
00630          * TODO finish this macro and start using it!
00631          * #define offsetcheck {if (offset > HOWMANY-1) 
00632          *      magwarn("offset too big"); }
00633          */
00634 
00635         /*
00636          * now get last part - the description
00637          */
00638 GetDesc:
00639         EATAB;
00640         if (l[0] == '\b') {
00641                 ++l;
00642                 m->nospflag = 1;
00643         } else if ((l[0] == '\\') && (l[1] == 'b')) {
00644                 ++l;
00645                 ++l;
00646                 m->nospflag = 1;
00647         } else
00648                 m->nospflag = 0;
00649         while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
00650                 {};
00651 
00652 #ifndef COMPILE_ONLY
00653         if (action == CHECK) {
00654                 mdump(m);
00655         }
00656 #endif
00657         ++(*nmagicp);           /* make room for next */
00658         return 0;
00659 }
00660 /*@=bounds@*/
00661 
00662 /*
00663  * Print a string containing C character escapes.
00664  */
00665 void
00666 showstr(FILE *fp, const char *s, int len)
00667 {
00668         char    c;
00669 
00670         for (;;) {
00671                 c = *s++;
00672                 if (len == -1) {
00673                         if (c == '\0')
00674                                 break;
00675                 }
00676                 else  {
00677                         if (len-- == 0)
00678                                 break;
00679                 }
00680                 if(c >= 040 && c <= 0176)       /* TODO isprint && !iscntrl */
00681                         (void) fputc(c, fp);
00682                 else {
00683                         (void) fputc('\\', fp);
00684                         switch (c) {
00685                         
00686                         case '\n':
00687                                 (void) fputc('n', fp);
00688                                 /*@switchbreak@*/ break;
00689 
00690                         case '\r':
00691                                 (void) fputc('r', fp);
00692                                 /*@switchbreak@*/ break;
00693 
00694                         case '\b':
00695                                 (void) fputc('b', fp);
00696                                 /*@switchbreak@*/ break;
00697 
00698                         case '\t':
00699                                 (void) fputc('t', fp);
00700                                 /*@switchbreak@*/ break;
00701 
00702                         case '\f':
00703                                 (void) fputc('f', fp);
00704                                 /*@switchbreak@*/ break;
00705 
00706                         case '\v':
00707                                 (void) fputc('v', fp);
00708                                 /*@switchbreak@*/ break;
00709 
00710                         default:
00711                                 (void) fprintf(fp, "%.3o", c & 0377);
00712                                 /*@switchbreak@*/ break;
00713                         }
00714                 }
00715         }
00716 }
00717 
00718 /*
00719  * swap a short
00720  */
00721 /*@-bounds@*/
00722 static uint16_t
00723 swap2(uint16_t sv)
00724         /*@*/
00725 {
00726         uint16_t rv;
00727         uint8_t *s = (uint8_t *) &sv; 
00728         uint8_t *d = (uint8_t *) &rv; 
00729         d[0] = s[1];
00730         d[1] = s[0];
00731         return rv;
00732 }
00733 /*@=bounds@*/
00734 
00735 /*
00736  * swap an int
00737  */
00738 /*@-bounds@*/
00739 static uint32_t
00740 swap4(uint32_t sv)
00741         /*@*/
00742 {
00743         uint32_t rv;
00744         uint8_t *s = (uint8_t *) &sv; 
00745         uint8_t *d = (uint8_t *) &rv; 
00746         d[0] = s[3];
00747         d[1] = s[2];
00748         d[2] = s[1];
00749         d[3] = s[0];
00750         return rv;
00751 }
00752 /*@=bounds@*/
00753 
00754 /*
00755  * byteswap a single magic entry
00756  */
00757 static
00758 void bs1(struct magic *m)
00759         /*@modifies m @*/
00760 {
00761         m->cont_level = swap2(m->cont_level);
00762         m->offset = swap4(m->offset);
00763         m->in_offset = swap4(m->in_offset);
00764         if (m->type != STRING)
00765                 m->value.l = swap4(m->value.l);
00766         m->mask = swap4(m->mask);
00767 }
00768 
00769 /*
00770  * Byteswap an mmap'ed file if needed
00771  */
00772 /*@-bounds@*/
00773 static void
00774 byteswap(/*@null@*/ struct magic *m, uint32_t nmagic)
00775         /*@modifies m @*/
00776 {
00777         uint32_t i;
00778         if (m != NULL)
00779         for (i = 0; i < nmagic; i++)
00780                 bs1(&m[i]);
00781 }
00782 /*@=bounds@*/
00783 
00784 /*
00785  * make a dbname
00786  */
00787 static char *
00788 mkdbname(const char *fn)
00789         /*@*/
00790 {
00791         static const char ext[] = ".mgc";
00792         /*@only@*/
00793         static char *buf = NULL;
00794 
00795         buf = xrealloc(buf, strlen(fn) + sizeof(ext) + 1);
00796         (void)strcpy(buf, fn);
00797         (void)strcat(buf, ext);
00798         return buf;
00799 }
00800 
00801 /*
00802  * parse from a file
00803  * const char *fn: name of magic file
00804  */
00805 /*@-bounds@*/
00806 static int
00807 apprentice_file(fmagic fm, /*@out@*/ struct magic **magicp,
00808                 /*@out@*/ uint32_t *nmagicp, const char *fn, int action)
00809         /*@globals maxmagic, fileSystem @*/
00810         /*@modifies fm, *magicp, *nmagicp, maxmagic, fileSystem @*/
00811 {
00812         /*@observer@*/
00813         static const char hdr[] =
00814                 "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
00815         FILE *f;
00816         char line[BUFSIZ+1];
00817         int errs = 0;
00818 
00819         f = fopen(fn, "r");
00820         if (f == NULL) {
00821                 if (errno != ENOENT)
00822                         (void) fprintf(stderr,
00823                             "%s: can't read magic file %s (%s)\n", 
00824                             __progname, fn, strerror(errno));
00825                 return -1;
00826         }
00827 
00828         maxmagic = MAXMAGIS;
00829         *magicp = (struct magic *) xcalloc(sizeof(**magicp), maxmagic);
00830 
00831         /* parse it */
00832         if (action == CHECK)    /* print silly verbose header for USG compat. */
00833                 (void) printf("%s\n", hdr);
00834 
00835         for (fm->lineno = 1; fgets(line, BUFSIZ, f) != NULL; fm->lineno++) {
00836                 if (line[0]=='#')       /* comment, do not parse */
00837                         continue;
00838                 if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
00839                         continue;
00840                 line[strlen(line)-1] = '\0'; /* delete newline */
00841                 if (parse(magicp, nmagicp, line, action) != 0)
00842                         errs = 1;
00843         }
00844 
00845         (void) fclose(f);
00846         if (errs) {
00847                 free(*magicp);
00848                 *magicp = NULL;
00849                 *nmagicp = 0;
00850         }
00851         return errs;
00852 }
00853 /*@=bounds@*/
00854 
00855 /*
00856  * handle an mmaped file.
00857  */
00858 /*@-bounds@*/
00859 static int
00860 apprentice_compile(/*@unused@*/ const fmagic fm,
00861                 /*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
00862                 const char *fn, /*@unused@*/ int action)
00863         /*@globals fileSystem, internalState @*/
00864         /*@modifies fileSystem, internalState @*/
00865 {
00866         int fd;
00867         char *dbname = mkdbname(fn);
00868         /*@observer@*/
00869         static const uint32_t ar[] = {
00870             MAGICNO, VERSIONNO
00871         };
00872 
00873         if (dbname == NULL) 
00874                 return -1;
00875 
00876         if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
00877                 (void)fprintf(stderr, "%s: Cannot open `%s' (%s)\n",
00878                     __progname, dbname, strerror(errno));
00879                 return -1;
00880         }
00881 
00882         if (write(fd, ar, sizeof(ar)) != sizeof(ar)) {
00883                 (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
00884                     __progname, dbname, strerror(errno));
00885                 return -1;
00886         }
00887 
00888         if (lseek(fd, sizeof(**magicp), SEEK_SET) != sizeof(**magicp)) {
00889                 (void)fprintf(stderr, "%s: error seeking `%s' (%s)\n",
00890                     __progname, dbname, strerror(errno));
00891                 return -1;
00892         }
00893 
00894         if (write(fd, *magicp,  sizeof(**magicp) * *nmagicp) 
00895             != sizeof(**magicp) * *nmagicp) {
00896                 (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
00897                     __progname, dbname, strerror(errno));
00898                 return -1;
00899         }
00900 
00901         (void)close(fd);
00902         return 0;
00903 }
00904 /*@=bounds@*/
00905 
00906 /*
00907  * handle a compiled file.
00908  */
00909 /*@-bounds@*/
00910 static int
00911 apprentice_map(/*@unused@*/ const fmagic fm,
00912                 /*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
00913                 const char *fn, /*@unused@*/ int action)
00914         /*@globals fileSystem, internalState @*/
00915         /*@modifies *magicp, *nmagicp, fileSystem, internalState @*/
00916 {
00917         int fd;
00918         struct stat st;
00919         uint32_t *ptr;
00920         uint32_t version;
00921         int needsbyteswap;
00922         char *dbname = mkdbname(fn);
00923         void *mm = NULL;
00924 
00925         if (dbname == NULL)
00926                 return -1;
00927 
00928         if ((fd = open(dbname, O_RDONLY)) == -1)
00929                 return -1;
00930 
00931         if (fstat(fd, &st) == -1) {
00932                 (void)fprintf(stderr, "%s: Cannot stat `%s' (%s)\n",
00933                     __progname, dbname, strerror(errno));
00934                 goto errxit;
00935         }
00936 
00937 #ifdef HAVE_MMAP
00938         if ((mm = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
00939             MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
00940                 (void)fprintf(stderr, "%s: Cannot map `%s' (%s)\n",
00941                     __progname, dbname, strerror(errno));
00942                 goto errxit;
00943         }
00944 #else
00945         mm = xmalloc((size_t)st.st_size);
00946         if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
00947                 (void) fprintf(stderr, "%s: Read failed (%s).\n", __progname,
00948                     strerror(errno));
00949                 goto errxit;
00950         }
00951 #endif
00952         *magicp = mm;
00953         (void)close(fd);
00954         fd = -1;
00955         ptr = (uint32_t *) *magicp;
00956         if (ptr == NULL)        /* XXX can't happen */
00957                 goto errxit;
00958         if (*ptr != MAGICNO) {
00959                 if (swap4(*ptr) != MAGICNO) {
00960                         (void)fprintf(stderr, "%s: Bad magic in `%s'\n",
00961                             __progname, dbname);
00962                         goto errxit;
00963                 }
00964                 needsbyteswap = 1;
00965         } else
00966                 needsbyteswap = 0;
00967         if (needsbyteswap)
00968                 version = swap4(ptr[1]);
00969         else
00970                 version = ptr[1];
00971         if (version != VERSIONNO) {
00972                 (void)fprintf(stderr, 
00973                     "%s: version mismatch (%d != %d) in `%s'\n",
00974                     __progname, version, VERSIONNO, dbname);
00975                 goto errxit;
00976         }
00977         *nmagicp = (st.st_size / sizeof(**magicp)) - 1;
00978         (*magicp)++;
00979         if (needsbyteswap)
00980                 byteswap(*magicp, *nmagicp);
00981         return 0;
00982 
00983 errxit:
00984         if (fd != -1)
00985                 (void)close(fd);
00986 /*@-branchstate@*/
00987         if (mm != NULL) {
00988 #ifdef HAVE_MMAP
00989                 (void)munmap(mm, (size_t)st.st_size);
00990 #else
00991                 free(mm);
00992 #endif
00993         } else {
00994                 *magicp = NULL;
00995                 *nmagicp = 0;
00996         }
00997 /*@=branchstate@*/
00998         return -1;
00999 }
01000 /*@=bounds@*/
01001 
01002 /*
01003  * Handle one file.
01004  */
01005 static int
01006 apprentice_1(fmagic fm, const char *fn, int action)
01007         /*@globals fileSystem, internalState @*/
01008         /*@modifies fm, fileSystem, internalState @*/
01009 {
01010 /*@-shadow@*/
01011         struct magic *magic = NULL;
01012         uint32_t nmagic = 0;
01013 /*@=shadow@*/
01014         struct mlist *ml;
01015         int rv = -1;
01016 
01017         if (action == COMPILE) {
01018                 rv = apprentice_file(fm, &magic, &nmagic, fn, action);
01019                 if (rv)
01020                         return rv;
01021                 return apprentice_compile(fm, &magic, &nmagic, fn, action);
01022         }
01023 #ifndef COMPILE_ONLY
01024         if ((rv = apprentice_map(fm, &magic, &nmagic, fn, action)) != 0)
01025                 (void)fprintf(stderr, "%s: Using regular magic file `%s'\n",
01026                     __progname, fn);
01027                 
01028         if (rv != 0)
01029                 rv = apprentice_file(fm, &magic, &nmagic, fn, action);
01030 
01031         if (rv != 0)
01032                 return rv;
01033              
01034         if (magic == NULL || nmagic == 0)
01035                 return rv;
01036 
01037         ml = xmalloc(sizeof(*ml));
01038 
01039         ml->magic = magic;
01040         ml->nmagic = nmagic;
01041 
01042         fm->mlist->prev->next = ml;
01043         ml->prev = fm->mlist->prev;
01044 /*@-immediatetrans@*/
01045         ml->next = fm->mlist;
01046 /*@=immediatetrans@*/
01047 /*@-kepttrans@*/
01048         fm->mlist->prev = ml;
01049 /*@=kepttrans@*/
01050 
01051 /*@-compdef -compmempass @*/
01052         return rv;
01053 /*@=compdef =compmempass @*/
01054 #endif /* COMPILE_ONLY */
01055 }
01056 
01057 /* const char *fn: list of magic files */
01058 int
01059 fmagicSetup(fmagic fm, const char *fn, int action)
01060 {
01061         char *p, *mfn;
01062         int file_err, errs = -1;
01063 
01064         if (fm->mlist == NULL) {
01065                 static struct mlist mlist;
01066 /*@-immediatetrans@*/
01067                 mlist.next = &mlist;
01068                 mlist.prev = &mlist;
01069                 fm->mlist = &mlist;
01070 /*@=immediatetrans@*/
01071         }
01072 
01073         mfn = xstrdup(fn);
01074         fn = mfn;
01075   
01076 /*@-branchstate@*/
01077         while (fn != NULL) {
01078                 p = strchr(fn, PATHSEP);
01079                 if (p != NULL)
01080                         *p++ = '\0';
01081                 file_err = apprentice_1(fm, fn, action);
01082                 if (file_err > errs)
01083                         errs = file_err;
01084                 fn = p;
01085         }
01086 /*@=branchstate@*/
01087         if (errs == -1)
01088                 (void) fprintf(stderr, "%s: couldn't find any magic files!\n",
01089                     __progname);
01090         if (action == CHECK && errs)
01091                 exit(EXIT_FAILURE);
01092 
01093         free(mfn);
01094 /*@-compdef -compmempass@*/
01095         return errs;
01096 /*@=compdef =compmempass@*/
01097 }
01098 
01099 #ifdef COMPILE_ONLY
01100 int
01101 main(int argc, char *argv[])
01102         /*@*/
01103 {
01104         static struct fmagic_s myfmagic;
01105         fmagic fm = &myfmagic;
01106         int ret;
01107 
01108         setprogname(argv[0]);       /* Retrofit glibc __progname */
01109 
01110         if (argc != 2) {
01111                 (void)fprintf(stderr, "usage: %s file\n", __progname);
01112                 exit(1);
01113         }
01114         fm->magicfile = argv[1];
01115 
01116         exit(apprentice(fm, fm->magicfile, COMPILE));
01117 }
01118 #endif /* COMPILE_ONLY */

Generated on Sun Oct 26 13:01:58 2003 for rpm by doxygen1.2.18