12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145 |
- /*
- * apprentice - make one pass through /etc/magic, learning its secrets.
- *
- * Copyright (c) Ian F. Darwin, 1987.
- * Written by Ian F. Darwin.
- *
- * This software is not subject to any license of the American Telephone
- * and Telegraph Company or of the Regents of the University of California.
- *
- * Permission is granted to anyone to use this software for any purpose on
- * any computer system, and to alter it and redistribute it freely, subject
- * to the following restrictions:
- *
- * 1. The author is not responsible for the consequences of use of this
- * software, no matter how awful, even if they arise from flaws in it.
- *
- * 2. The origin of this software must not be misrepresented, either by
- * explicit claim or by omission. Since few users ever read sources,
- * credits must appear in the documentation.
- *
- * 3. Altered versions must be plainly marked as such, and must not be
- * misrepresented as being the original software. Since few users
- * ever read sources, credits must appear in the documentation.
- *
- * 4. This notice may not be removed or altered.
- */
- #include "file.h"
- #include <stdio.h>
- #include <stdlib.h>
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <string.h>
- #include <ctype.h>
- #include <errno.h>
- #ifdef QUICK
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #endif
- #ifndef lint
- FILE_RCSID("@(#)$Id: apprentice.c,v 1.44 2001/08/01 14:03:19 christos Exp $")
- #endif /* lint */
- #define EATAB {while (isascii((unsigned char) *l) && \
- isspace((unsigned char) *l)) ++l;}
- #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
- tolower((unsigned char) (l)) : (l))
- /*
- * Work around a bug in headers on Digital Unix.
- * At least confirmed for: OSF1 V4.0 878
- */
- #if defined(__osf__) && defined(__DECC)
- #ifdef MAP_FAILED
- #undef MAP_FAILED
- #endif
- #endif
- #ifndef MAP_FAILED
- #define MAP_FAILED (void *) -1
- #endif
- #ifndef MAP_FILE
- #define MAP_FILE 0
- #endif
- #ifdef __EMX__
- char PATHSEP=';';
- #else
- char PATHSEP=':';
- #endif
- static int getvalue __P((struct magic *, char **));
- static int hextoint __P((int));
- static char *getstr __P((char *, char *, int, int *));
- static int parse __P((struct magic **, uint32 *, char *, int));
- static void eatsize __P((char **));
- static int apprentice_1 __P((const char *, int));
- static int apprentice_file __P((struct magic **, uint32 *,
- const char *, int));
- static void byteswap __P((struct magic *, uint32));
- static void bs1 __P((struct magic *));
- static uint16 swap2 __P((uint16));
- static uint32 swap4 __P((uint32));
- static char *mkdbname __P((const char *));
- static int apprentice_map __P((struct magic **, uint32 *,
- const char *, int));
- static int apprentice_compile __P((struct magic **, uint32 *,
- const char *, int));
- static int maxmagic = 0;
- struct mlist mlist;
- #ifdef COMPILE_ONLY
- const char *magicfile;
- char *progname;
- int lineno;
- int main __P((int, char *[]));
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int ret;
- if ((progname = strrchr(argv[0], '/')) != NULL)
- progname++;
- else
- progname = argv[0];
- if (argc != 2) {
- (void)fprintf(stderr, "usage: %s file\n", progname);
- exit(1);
- }
- magicfile = argv[1];
- exit(apprentice(magicfile, COMPILE));
- }
- #endif /* COMPILE_ONLY */
- /*
- * Handle one file.
- */
- static int
- apprentice_1(fn, action)
- const char *fn;
- int action;
- {
- struct magic *magic = NULL;
- uint32 nmagic = 0;
- struct mlist *ml;
- int rv = -1;
- if (action == COMPILE) {
- rv = apprentice_file(&magic, &nmagic, fn, action);
- if (rv == 0)
- return apprentice_compile(&magic, &nmagic, fn, action);
- else
- return rv;
- }
- #ifndef COMPILE_ONLY
- if ((rv = apprentice_map(&magic, &nmagic, fn, action)) != 0 && strcmp(fn,"/etc/magic"))
- (void)fprintf(stderr, "%s: Using regular magic file `%s'\n",
- progname, fn);
-
- if (rv != 0)
- rv = apprentice_file(&magic, &nmagic, fn, action);
- if (rv != 0)
- return rv;
-
- if ((ml = malloc(sizeof(*ml))) == NULL) {
- (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
- strerror(errno));
- if (action == CHECK)
- return -1;
- }
- if (magic == NULL || nmagic == 0)
- return rv;
- ml->magic = magic;
- ml->nmagic = nmagic;
- mlist.prev->next = ml;
- ml->prev = mlist.prev;
- ml->next = &mlist;
- mlist.prev = ml;
- return rv;
- #endif /* COMPILE_ONLY */
- }
- int
- apprentice(fn, action)
- const char *fn; /* list of magic files */
- int action;
- {
- char *p, *mfn;
- int file_err, errs = -1;
- mlist.next = mlist.prev = &mlist;
- mfn = malloc(strlen(fn)+1);
- if (mfn == NULL) {
- (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
- strerror(errno));
- if (action == CHECK)
- return -1;
- else
- exit(1);
- }
- fn = strcpy(mfn, fn);
-
- while (fn) {
- p = strchr(fn, PATHSEP);
- if (p)
- *p++ = '\0';
- file_err = apprentice_1(fn, action);
- if (file_err > errs)
- errs = file_err;
- fn = p;
- }
- if (errs == -1)
- (void) fprintf(stderr, "%s: couldn't find any magic files!\n",
- progname);
- if (action == CHECK && errs)
- exit(1);
- free(mfn);
- return errs;
- }
- /*
- * parse from a file
- */
- static int
- apprentice_file(magicp, nmagicp, fn, action)
- struct magic **magicp;
- uint32 *nmagicp;
- const char *fn; /* name of magic file */
- int action;
- {
- static const char hdr[] =
- "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
- FILE *f;
- char line[BUFSIZ+1];
- int errs = 0;
- f = fopen(fn, "r");
- if (f == NULL) {
- if (errno != ENOENT)
- (void) fprintf(stderr,
- "%s: can't read magic file %s (%s)\n",
- progname, fn, strerror(errno));
- return -1;
- }
- maxmagic = MAXMAGIS;
- *magicp = (struct magic *) calloc(sizeof(struct magic), maxmagic);
- if (*magicp == NULL) {
- (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
- strerror(errno));
- if (action == CHECK)
- return -1;
- }
- /* parse it */
- if (action == CHECK) /* print silly verbose header for USG compat. */
- (void) printf("%s\n", hdr);
- for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
- if (line[0]=='#') /* comment, do not parse */
- continue;
- if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
- continue;
- line[strlen(line)-1] = '\0'; /* delete newline */
- if (parse(magicp, nmagicp, line, action) != 0)
- errs = 1;
- }
- (void) fclose(f);
- if (errs) {
- free(*magicp);
- *magicp = NULL;
- *nmagicp = 0;
- }
- return errs;
- }
- /*
- * extend the sign bit if the comparison is to be signed
- */
- uint32
- signextend(m, v)
- struct magic *m;
- uint32 v;
- {
- if (!(m->flag & UNSIGNED))
- switch(m->type) {
- /*
- * Do not remove the casts below. They are
- * vital. When later compared with the data,
- * the sign extension must have happened.
- */
- case BYTE:
- v = (char) v;
- break;
- case SHORT:
- case BESHORT:
- case LESHORT:
- v = (short) v;
- break;
- case DATE:
- case BEDATE:
- case LEDATE:
- case LDATE:
- case BELDATE:
- case LELDATE:
- case LONG:
- case BELONG:
- case LELONG:
- v = (int32) v;
- break;
- case STRING:
- case PSTRING:
- break;
- default:
- magwarn("can't happen: m->type=%d\n",
- m->type);
- return -1;
- }
- return v;
- }
- /*
- * parse one line from magic file, put into magic[index++] if valid
- */
- static int
- parse(magicp, nmagicp, l, action)
- struct magic **magicp;
- uint32 *nmagicp;
- char *l;
- int action;
- {
- int i = 0;
- struct magic *m;
- char *t;
- #define ALLOC_INCR 200
- if (*nmagicp + 1 >= maxmagic){
- maxmagic += ALLOC_INCR;
- if ((m = (struct magic *) realloc(*magicp,
- sizeof(struct magic) * maxmagic)) == NULL) {
- (void) fprintf(stderr, "%s: Out of memory (%s).\n",
- progname, strerror(errno));
- if (*magicp)
- free(*magicp);
- if (action == CHECK)
- return -1;
- else
- exit(1);
- }
- *magicp = m;
- memset(&(*magicp)[*nmagicp], 0, sizeof(struct magic)
- * ALLOC_INCR);
- }
- m = &(*magicp)[*nmagicp];
- m->flag = 0;
- m->cont_level = 0;
- while (*l == '>') {
- ++l; /* step over */
- m->cont_level++;
- }
- if (m->cont_level != 0 && *l == '(') {
- ++l; /* step over */
- m->flag |= INDIR;
- }
- if (m->cont_level != 0 && *l == '&') {
- ++l; /* step over */
- m->flag |= OFFADD;
- }
- /* get offset, then skip over it */
- m->offset = (int) strtoul(l,&t,0);
- if (l == t)
- magwarn("offset %s invalid", l);
- l = t;
- if (m->flag & INDIR) {
- m->in_type = LONG;
- m->in_offset = 0;
- /*
- * read [.lbs][+-]nnnnn)
- */
- if (*l == '.') {
- l++;
- switch (*l) {
- case 'l':
- m->in_type = LELONG;
- break;
- case 'L':
- m->in_type = BELONG;
- break;
- case 'h':
- case 's':
- m->in_type = LESHORT;
- break;
- case 'H':
- case 'S':
- m->in_type = BESHORT;
- break;
- case 'c':
- case 'b':
- case 'C':
- case 'B':
- m->in_type = BYTE;
- break;
- default:
- magwarn("indirect offset type %c invalid", *l);
- break;
- }
- l++;
- }
- if (*l == '~') {
- m->in_op = OPINVERSE;
- l++;
- }
- switch (*l) {
- case '&':
- m->in_op |= OPAND;
- l++;
- break;
- case '|':
- m->in_op |= OPOR;
- l++;
- break;
- case '^':
- m->in_op |= OPXOR;
- l++;
- break;
- case '+':
- m->in_op |= OPADD;
- l++;
- break;
- case '-':
- m->in_op |= OPMINUS;
- l++;
- break;
- case '*':
- m->in_op |= OPMULTIPLY;
- l++;
- break;
- case '/':
- m->in_op |= OPDIVIDE;
- l++;
- break;
- case '%':
- m->in_op |= OPMODULO;
- l++;
- break;
- }
- if (isdigit((unsigned char)*l))
- m->in_offset = strtoul(l, &t, 0);
- else
- t = l;
- if (*t++ != ')')
- magwarn("missing ')' in indirect offset");
- l = t;
- }
- while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
- ++l;
- EATAB;
- #define NBYTE 4
- #define NSHORT 5
- #define NLONG 4
- #define NSTRING 6
- #define NDATE 4
- #define NBESHORT 7
- #define NBELONG 6
- #define NBEDATE 6
- #define NLESHORT 7
- #define NLELONG 6
- #define NLEDATE 6
- #define NPSTRING 7
- #define NLDATE 5
- #define NBELDATE 7
- #define NLELDATE 7
- if (*l == 'u') {
- ++l;
- m->flag |= UNSIGNED;
- }
- /* get type, skip it */
- if (strncmp(l, "char", NBYTE)==0) { /* HP/UX compat */
- m->type = BYTE;
- l += NBYTE;
- } else if (strncmp(l, "byte", NBYTE)==0) {
- m->type = BYTE;
- l += NBYTE;
- } else if (strncmp(l, "short", NSHORT)==0) {
- m->type = SHORT;
- l += NSHORT;
- } else if (strncmp(l, "long", NLONG)==0) {
- m->type = LONG;
- l += NLONG;
- } else if (strncmp(l, "string", NSTRING)==0) {
- m->type = STRING;
- l += NSTRING;
- } else if (strncmp(l, "date", NDATE)==0) {
- m->type = DATE;
- l += NDATE;
- } else if (strncmp(l, "beshort", NBESHORT)==0) {
- m->type = BESHORT;
- l += NBESHORT;
- } else if (strncmp(l, "belong", NBELONG)==0) {
- m->type = BELONG;
- l += NBELONG;
- } else if (strncmp(l, "bedate", NBEDATE)==0) {
- m->type = BEDATE;
- l += NBEDATE;
- } else if (strncmp(l, "leshort", NLESHORT)==0) {
- m->type = LESHORT;
- l += NLESHORT;
- } else if (strncmp(l, "lelong", NLELONG)==0) {
- m->type = LELONG;
- l += NLELONG;
- } else if (strncmp(l, "ledate", NLEDATE)==0) {
- m->type = LEDATE;
- l += NLEDATE;
- } else if (strncmp(l, "pstring", NPSTRING)==0) {
- m->type = PSTRING;
- l += NPSTRING;
- } else if (strncmp(l, "ldate", NLDATE)==0) {
- m->type = LDATE;
- l += NLDATE;
- } else if (strncmp(l, "beldate", NBELDATE)==0) {
- m->type = BELDATE;
- l += NBELDATE;
- } else if (strncmp(l, "leldate", NLELDATE)==0) {
- m->type = LELDATE;
- l += NLELDATE;
- } else {
- magwarn("type %s invalid", l);
- return -1;
- }
- /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
- /* New and improved: ~ & | ^ + - * / % -- exciting, isn't it? */
- if (*l == '~') {
- if (STRING != m->type && PSTRING != m->type)
- m->mask_op = OPINVERSE;
- ++l;
- }
- switch (*l) {
- case '&':
- m->mask_op |= OPAND;
- ++l;
- m->mask = signextend(m, strtoul(l, &l, 0));
- eatsize(&l);
- break;
- case '|':
- m->mask_op |= OPOR;
- ++l;
- m->mask = signextend(m, strtoul(l, &l, 0));
- eatsize(&l);
- break;
- case '^':
- m->mask_op |= OPXOR;
- ++l;
- m->mask = signextend(m, strtoul(l, &l, 0));
- eatsize(&l);
- break;
- case '+':
- m->mask_op |= OPADD;
- ++l;
- m->mask = signextend(m, strtoul(l, &l, 0));
- eatsize(&l);
- break;
- case '-':
- m->mask_op |= OPMINUS;
- ++l;
- m->mask = signextend(m, strtoul(l, &l, 0));
- eatsize(&l);
- break;
- case '*':
- m->mask_op |= OPMULTIPLY;
- ++l;
- m->mask = signextend(m, strtoul(l, &l, 0));
- eatsize(&l);
- break;
- case '%':
- m->mask_op |= OPMODULO;
- ++l;
- m->mask = signextend(m, strtoul(l, &l, 0));
- eatsize(&l);
- break;
- case '/':
- if (STRING != m->type && PSTRING != m->type) {
- m->mask_op |= OPDIVIDE;
- ++l;
- m->mask = signextend(m, strtoul(l, &l, 0));
- eatsize(&l);
- } else {
- m->mask = 0L;
- while (!isspace(*++l)) {
- switch (*l) {
- case CHAR_IGNORE_LOWERCASE:
- m->mask |= STRING_IGNORE_LOWERCASE;
- break;
- case CHAR_COMPACT_BLANK:
- m->mask |= STRING_COMPACT_BLANK;
- break;
- case CHAR_COMPACT_OPTIONAL_BLANK:
- m->mask |=
- STRING_COMPACT_OPTIONAL_BLANK;
- break;
- default:
- magwarn("string extension %c invalid",
- *l);
- return -1;
- }
- }
- }
- break;
- }
- /* We used to set mask to all 1's here, instead let's just not do anything
- if mask = 0 (unless you have a better idea) */
- EATAB;
-
- switch (*l) {
- case '>':
- case '<':
- /* Old-style anding: "0 byte &0x80 dynamically linked" */
- case '&':
- case '^':
- case '=':
- m->reln = *l;
- ++l;
- if (*l == '=') {
- /* HP compat: ignore &= etc. */
- ++l;
- }
- break;
- case '!':
- if (m->type != STRING && m->type != PSTRING) {
- m->reln = *l;
- ++l;
- break;
- }
- /* FALL THROUGH */
- default:
- if (*l == 'x' && isascii((unsigned char)l[1]) &&
- isspace((unsigned char)l[1])) {
- m->reln = *l;
- ++l;
- goto GetDesc; /* Bill The Cat */
- }
- m->reln = '=';
- break;
- }
- EATAB;
-
- if (getvalue(m, &l))
- return -1;
- /*
- * TODO finish this macro and start using it!
- * #define offsetcheck {if (offset > HOWMANY-1)
- * magwarn("offset too big"); }
- */
- /*
- * now get last part - the description
- */
- GetDesc:
- EATAB;
- if (l[0] == '\b') {
- ++l;
- m->nospflag = 1;
- } else if ((l[0] == '\\') && (l[1] == 'b')) {
- ++l;
- ++l;
- m->nospflag = 1;
- } else
- m->nospflag = 0;
- while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
- /* NULLBODY */;
- if (action == CHECK) {
- mdump(m);
- }
- ++(*nmagicp); /* make room for next */
- return 0;
- }
- /*
- * Read a numeric value from a pointer, into the value union of a magic
- * pointer, according to the magic type. Update the string pointer to point
- * just after the number read. Return 0 for success, non-zero for failure.
- */
- static int
- getvalue(m, p)
- struct magic *m;
- char **p;
- {
- int slen;
- if (m->type == STRING || m->type == PSTRING) {
- *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
- m->vallen = slen;
- } else
- if (m->reln != 'x') {
- m->value.l = signextend(m, strtoul(*p, p, 0));
- eatsize(p);
- }
- return 0;
- }
- /*
- * Convert a string containing C character escapes. Stop at an unescaped
- * space or tab.
- * Copy the converted version to "p", returning its length in *slen.
- * Return updated scan pointer as function result.
- */
- static char *
- getstr(s, p, plen, slen)
- char *s;
- char *p;
- int plen, *slen;
- {
- char *origs = s, *origp = p;
- char *pmax = p + plen - 1;
- int c;
- int val;
- while ((c = *s++) != '\0') {
- if (isspace((unsigned char) c))
- break;
- if (p >= pmax) {
- fprintf(stderr, "String too long: %s\n", origs);
- break;
- }
- if(c == '\\') {
- switch(c = *s++) {
- case '\0':
- goto out;
- default:
- *p++ = (char) c;
- break;
- case 'n':
- *p++ = '\n';
- break;
- case 'r':
- *p++ = '\r';
- break;
- case 'b':
- *p++ = '\b';
- break;
- case 't':
- *p++ = '\t';
- break;
- case 'f':
- *p++ = '\f';
- break;
- case 'v':
- *p++ = '\v';
- break;
- /* \ and up to 3 octal digits */
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- val = c - '0';
- c = *s++; /* try for 2 */
- if(c >= '0' && c <= '7') {
- val = (val<<3) | (c - '0');
- c = *s++; /* try for 3 */
- if(c >= '0' && c <= '7')
- val = (val<<3) | (c-'0');
- else
- --s;
- }
- else
- --s;
- *p++ = (char)val;
- break;
- /* \x and up to 2 hex digits */
- case 'x':
- val = 'x'; /* Default if no digits */
- c = hextoint(*s++); /* Get next char */
- if (c >= 0) {
- val = c;
- c = hextoint(*s++);
- if (c >= 0)
- val = (val << 4) + c;
- else
- --s;
- } else
- --s;
- *p++ = (char)val;
- break;
- }
- } else
- *p++ = (char)c;
- }
- out:
- *p = '\0';
- *slen = p - origp;
- return s;
- }
- /* Single hex char to int; -1 if not a hex char. */
- static int
- hextoint(c)
- int c;
- {
- if (!isascii((unsigned char) c))
- return -1;
- if (isdigit((unsigned char) c))
- return c - '0';
- if ((c >= 'a')&&(c <= 'f'))
- return c + 10 - 'a';
- if (( c>= 'A')&&(c <= 'F'))
- return c + 10 - 'A';
- return -1;
- }
- /*
- * Print a string containing C character escapes.
- */
- void
- showstr(fp, s, len)
- FILE *fp;
- const char *s;
- int len;
- {
- char c;
- for (;;) {
- c = *s++;
- if (len == -1) {
- if (c == '\0')
- break;
- }
- else {
- if (len-- == 0)
- break;
- }
- if(c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
- (void) fputc(c, fp);
- else {
- (void) fputc('\\', fp);
- switch (c) {
-
- case '\n':
- (void) fputc('n', fp);
- break;
- case '\r':
- (void) fputc('r', fp);
- break;
- case '\b':
- (void) fputc('b', fp);
- break;
- case '\t':
- (void) fputc('t', fp);
- break;
- case '\f':
- (void) fputc('f', fp);
- break;
- case '\v':
- (void) fputc('v', fp);
- break;
- default:
- (void) fprintf(fp, "%.3o", c & 0377);
- break;
- }
- }
- }
- }
- /*
- * eatsize(): Eat the size spec from a number [eg. 10UL]
- */
- static void
- eatsize(p)
- char **p;
- {
- char *l = *p;
- if (LOWCASE(*l) == 'u')
- l++;
- switch (LOWCASE(*l)) {
- case 'l': /* long */
- case 's': /* short */
- case 'h': /* short */
- case 'b': /* char/byte */
- case 'c': /* char/byte */
- l++;
- /*FALLTHROUGH*/
- default:
- break;
- }
- *p = l;
- }
- /*
- * handle an mmaped file.
- */
- static int
- apprentice_map(magicp, nmagicp, fn, action)
- struct magic **magicp;
- uint32 *nmagicp;
- const char *fn;
- int action;
- {
- int fd;
- struct stat st;
- uint32 *ptr;
- uint32 version;
- int needsbyteswap;
- char *dbname = mkdbname(fn);
- if (dbname == NULL)
- return -1;
- if ((fd = open(dbname, O_RDONLY)) == -1)
- return -1;
- if (fstat(fd, &st) == -1) {
- (void)fprintf(stderr, "%s: Cannot stat `%s' (%s)\n",
- progname, dbname, strerror(errno));
- goto error;
- }
- #ifdef QUICK
- if ((*magicp = mmap(0, (size_t)st.st_size, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_FILE, fd, (off_t)0)) == MAP_FAILED) {
- (void)fprintf(stderr, "%s: Cannot map `%s' (%s)\n",
- progname, dbname, strerror(errno));
- goto error;
- }
- #else
- if ((*magicp = malloc((size_t)st.st_size)) == NULL) {
- (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
- strerror(errno));
- goto error;
- }
- if (read(fd, *magicp, (size_t)st.st_size) != (size_t)st.st_size) {
- (void) fprintf(stderr, "%s: Read failed (%s).\n", progname,
- strerror(errno));
- goto error;
- }
- #endif
- (void)close(fd);
- fd = -1;
- ptr = (uint32 *) *magicp;
- if (*ptr != MAGICNO) {
- if (swap4(*ptr) != MAGICNO) {
- (void)fprintf(stderr, "%s: Bad magic in `%s'\n",
- progname, dbname);
- goto error;
- }
- needsbyteswap = 1;
- } else
- needsbyteswap = 0;
- if (needsbyteswap)
- version = swap4(ptr[1]);
- else
- version = ptr[1];
- if (version != VERSIONNO) {
- (void)fprintf(stderr,
- "%s: version mismatch (%d != %d) in `%s'\n",
- progname, version, VERSIONNO, dbname);
- goto error;
- }
- *nmagicp = (st.st_size / sizeof(struct magic)) - 1;
- (*magicp)++;
- if (needsbyteswap)
- byteswap(*magicp, *nmagicp);
- return 0;
- error:
- if (fd != -1)
- (void)close(fd);
- if (*magicp) {
- #ifdef QUICK
- (void)munmap(*magicp, (size_t)st.st_size);
- #else
- free(*magicp);
- #endif
- } else {
- *magicp = NULL;
- *nmagicp = 0;
- }
- return -1;
- }
- /*
- * handle an mmaped file.
- */
- static int
- apprentice_compile(magicp, nmagicp, fn, action)
- struct magic **magicp;
- uint32 *nmagicp;
- const char *fn;
- int action;
- {
- int fd;
- char *dbname = mkdbname(fn);
- static const uint32 ar[] = {
- MAGICNO, VERSIONNO
- };
- if (dbname == NULL)
- return -1;
- if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) {
- (void)fprintf(stderr, "%s: Cannot open `%s' (%s)\n",
- progname, dbname, strerror(errno));
- return -1;
- }
- if (write(fd, ar, sizeof(ar)) != sizeof(ar)) {
- (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
- progname, dbname, strerror(errno));
- return -1;
- }
- if (lseek(fd, sizeof(struct magic), SEEK_SET) != sizeof(struct magic)) {
- (void)fprintf(stderr, "%s: error seeking `%s' (%s)\n",
- progname, dbname, strerror(errno));
- return -1;
- }
- if (write(fd, *magicp, sizeof(struct magic) * *nmagicp)
- != sizeof(struct magic) * *nmagicp) {
- (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
- progname, dbname, strerror(errno));
- return -1;
- }
- (void)close(fd);
- return 0;
- }
- /*
- * make a dbname
- */
- char *
- mkdbname(fn)
- const char *fn;
- {
- static const char ext[] = ".mgc";
- static char *buf = NULL;
- size_t len = strlen(fn) + sizeof(ext) + 1;
- if (buf == NULL)
- buf = malloc(len);
- else
- buf = realloc(buf, len);
- if (buf == NULL) {
- (void) fprintf(stderr, "%s: Out of memory (%s).\n", progname,
- strerror(errno));
- return NULL;
- }
- (void)strcpy(buf, fn);
- (void)strcat(buf, ext);
- return buf;
- }
- /*
- * Byteswap an mmap'ed file if needed
- */
- static void
- byteswap(magic, nmagic)
- struct magic *magic;
- uint32 nmagic;
- {
- uint32 i;
- for (i = 0; i < nmagic; i++)
- bs1(&magic[i]);
- }
- /*
- * swap a short
- */
- static uint16
- swap2(sv)
- uint16 sv;
- {
- uint16 rv;
- uint8 *s = (uint8 *) &sv;
- uint8 *d = (uint8 *) &rv;
- d[0] = s[1];
- d[1] = s[0];
- return rv;
- }
- /*
- * swap an int
- */
- static uint32
- swap4(sv)
- uint32 sv;
- {
- uint32 rv;
- uint8 *s = (uint8 *) &sv;
- uint8 *d = (uint8 *) &rv;
- d[0] = s[3];
- d[1] = s[2];
- d[2] = s[1];
- d[3] = s[0];
- return rv;
- }
- /*
- * byteswap a single magic entry
- */
- static
- void bs1(m)
- struct magic *m;
- {
- m->cont_level = swap2(m->cont_level);
- m->offset = swap4(m->offset);
- m->in_offset = swap4(m->in_offset);
- if (m->type != STRING)
- m->value.l = swap4(m->value.l);
- m->mask = swap4(m->mask);
- }
|