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

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

Generated on Tue Sep 7 17:14:27 2010 for rpm by  doxygen 1.3.9.1