| 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	lintFILE_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=':';#endifstatic 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_ONLYconst char *magicfile;char *progname;int lineno;int main __P((int, char *[]));intmain(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 intapprentice_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)		(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 */}intapprentice(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 intapprentice_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 */uint32signextend(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 intparse(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 intgetvalue(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 inthextoint(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. */voidshowstr(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 voideatsize(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 intapprentice_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 intapprentice_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 voidbyteswap(magic, nmagic)	struct magic *magic;	uint32 nmagic;{	uint32 i;	for (i = 0; i < nmagic; i++)		bs1(&magic[i]);}/* * swap a short */static uint16swap2(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 uint32swap4(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 */staticvoid 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);}
 |