--- /dev/null
+/*
+ * 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 "system.h"
+#include "file.h"
+#include "debug.h"
+
+FILE_RCSID("@(#)Id: apprentice.c,v 1.49 2002/07/03 19:00:41 christos Exp ")
+
+/*@access fmagic @*/
+
+#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
+
+/*@unchecked@*/
+#ifdef __EMX__
+ static char PATHSEP=';';
+#else
+ static char PATHSEP=':';
+#endif
+
+/*@unchecked@*/
+static int maxmagic = 0;
+
+#ifndef MAGIC
+# define MAGIC "/etc/magic"
+#endif
+
+/*@unchecked@*/ /*@observer@*/
+const char *default_magicfile = MAGIC;
+
+/*
+ * extend the sign bit if the comparison is to be signed
+ */
+uint32_t
+signextend(struct magic *m, uint32_t 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_t) v;
+ break;
+ case STRING:
+ case PSTRING:
+ break;
+ case REGEX:
+ break;
+ default:
+ magwarn("can't happen: m->type=%d\n", m->type);
+ return -1;
+ }
+ return v;
+}
+
+/*
+ * eatsize(): Eat the size spec from a number [eg. 10UL]
+ */
+/*@-bounds@*/
+static void
+eatsize(/*@out@*/ char **p)
+ /*@modifies *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;
+}
+/*@=bounds@*/
+
+/* Single hex char to int; -1 if not a hex char. */
+static int
+hextoint(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;
+}
+
+/*
+ * 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.
+ */
+/*@-shiftimplementation@*/
+/*@-bounds@*/
+static char *
+getstr(/*@returned@*/ char *s, char *p, int plen, /*@out@*/ int *slen)
+ /*@globals fileSystem @*/
+ /*@modifies *p, *slen, fileSystem @*/
+{
+ 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;
+ /*@switchbreak@*/ break;
+
+ case 'n':
+ *p++ = '\n';
+ /*@switchbreak@*/ break;
+
+ case 'r':
+ *p++ = '\r';
+ /*@switchbreak@*/ break;
+
+ case 'b':
+ *p++ = '\b';
+ /*@switchbreak@*/ break;
+
+ case 't':
+ *p++ = '\t';
+ /*@switchbreak@*/ break;
+
+ case 'f':
+ *p++ = '\f';
+ /*@switchbreak@*/ break;
+
+ case 'v':
+ *p++ = '\v';
+ /*@switchbreak@*/ 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;
+ /*@switchbreak@*/ 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;
+ /*@switchbreak@*/ break;
+ }
+ } else
+ *p++ = (char)c;
+ }
+out:
+ *p = '\0';
+ *slen = p - origp;
+ return s;
+}
+/*@=bounds@*/
+/*@=shiftimplementation@*/
+
+/*
+ * 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.
+ */
+/*@-bounds@*/
+static int
+getvalue(struct magic *m, /*@out@*/ char **p)
+ /*@globals fileSystem @*/
+ /*@modifies m, *p, fileSystem @*/
+{
+ int slen;
+
+ if (m->type == STRING || m->type == PSTRING || m->type == REGEX) {
+ *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;
+}
+/*@=bounds@*/
+
+/*
+ * parse one line from magic file, put into magic[index++] if valid
+ */
+/*@-bounds@*/
+static int
+parse(/*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
+ char *l, int action)
+ /*@globals maxmagic, fileSystem @*/
+ /*@modifies *magicp, *nmagicp, maxmagic, fileSystem @*/
+{
+ int i = 0;
+ struct magic *m;
+ char *t;
+
+#define ALLOC_INCR 200
+ if (*nmagicp + 1 >= maxmagic){
+ maxmagic += ALLOC_INCR;
+/*@-unqualifiedtrans @*/
+ *magicp = xrealloc(*magicp, sizeof(**magicp) * maxmagic);
+/*@=unqualifiedtrans @*/
+ m = &(*magicp)[*nmagicp];
+ memset(m, 0, sizeof(**magicp) * ALLOC_INCR);
+ } else
+ 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
+#define NREGEX 5
+
+ 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 if (strncmp(l, "regex", NREGEX)==0) {
+ m->type = REGEX;
+ l += sizeof("regex");
+ } 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;
+ /*@switchbreak@*/ break;
+ case CHAR_COMPACT_BLANK:
+ m->mask |= STRING_COMPACT_BLANK;
+ /*@switchbreak@*/ break;
+ case CHAR_COMPACT_OPTIONAL_BLANK:
+ m->mask |=
+ STRING_COMPACT_OPTIONAL_BLANK;
+ /*@switchbreak@*/ 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;
+ }
+ /*@fallthrough@*/
+ 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)
+ {};
+
+#ifndef COMPILE_ONLY
+ if (action == CHECK) {
+ mdump(m);
+ }
+#endif
+ ++(*nmagicp); /* make room for next */
+ return 0;
+}
+/*@=bounds@*/
+
+/*
+ * Print a string containing C character escapes.
+ */
+void
+showstr(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);
+ /*@switchbreak@*/ break;
+
+ case '\r':
+ (void) fputc('r', fp);
+ /*@switchbreak@*/ break;
+
+ case '\b':
+ (void) fputc('b', fp);
+ /*@switchbreak@*/ break;
+
+ case '\t':
+ (void) fputc('t', fp);
+ /*@switchbreak@*/ break;
+
+ case '\f':
+ (void) fputc('f', fp);
+ /*@switchbreak@*/ break;
+
+ case '\v':
+ (void) fputc('v', fp);
+ /*@switchbreak@*/ break;
+
+ default:
+ (void) fprintf(fp, "%.3o", c & 0377);
+ /*@switchbreak@*/ break;
+ }
+ }
+ }
+}
+
+/*
+ * swap a short
+ */
+/*@-bounds@*/
+static uint16_t
+swap2(uint16_t sv)
+ /*@*/
+{
+ uint16_t rv;
+ uint8_t *s = (uint8_t *) &sv;
+ uint8_t *d = (uint8_t *) &rv;
+ d[0] = s[1];
+ d[1] = s[0];
+ return rv;
+}
+/*@=bounds@*/
+
+/*
+ * swap an int
+ */
+/*@-bounds@*/
+static uint32_t
+swap4(uint32_t sv)
+ /*@*/
+{
+ uint32_t rv;
+ uint8_t *s = (uint8_t *) &sv;
+ uint8_t *d = (uint8_t *) &rv;
+ d[0] = s[3];
+ d[1] = s[2];
+ d[2] = s[1];
+ d[3] = s[0];
+ return rv;
+}
+/*@=bounds@*/
+
+/*
+ * byteswap a single magic entry
+ */
+static
+void bs1(struct magic *m)
+ /*@modifies 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);
+}
+
+/*
+ * Byteswap an mmap'ed file if needed
+ */
+/*@-bounds@*/
+static void
+byteswap(/*@null@*/ struct magic *m, uint32_t nmagic)
+ /*@modifies m @*/
+{
+ uint32_t i;
+ if (m != NULL)
+ for (i = 0; i < nmagic; i++)
+ bs1(&m[i]);
+}
+/*@=bounds@*/
+
+/*
+ * make a dbname
+ */
+static char *
+mkdbname(const char *fn)
+ /*@*/
+{
+ static const char ext[] = ".mgc";
+ /*@only@*/
+ static char *buf = NULL;
+
+ buf = xrealloc(buf, strlen(fn) + sizeof(ext) + 1);
+ (void)strcpy(buf, fn);
+ (void)strcat(buf, ext);
+ return buf;
+}
+
+/*
+ * parse from a file
+ * const char *fn: name of magic file
+ */
+/*@-bounds@*/
+static int
+apprentice_file(fmagic fm, /*@out@*/ struct magic **magicp,
+ /*@out@*/ uint32_t *nmagicp, const char *fn, int action)
+ /*@globals maxmagic, fileSystem @*/
+ /*@modifies fm, *magicp, *nmagicp, maxmagic, fileSystem @*/
+{
+ /*@observer@*/
+ 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 *) xcalloc(sizeof(**magicp), maxmagic);
+
+ /* parse it */
+ if (action == CHECK) /* print silly verbose header for USG compat. */
+ (void) printf("%s\n", hdr);
+
+ for (fm->lineno = 1; fgets(line, BUFSIZ, f) != NULL; fm->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;
+}
+/*@=bounds@*/
+
+/*
+ * handle an mmaped file.
+ */
+/*@-bounds@*/
+static int
+apprentice_compile(/*@unused@*/ const fmagic fm,
+ /*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
+ const char *fn, /*@unused@*/ int action)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fileSystem, internalState @*/
+{
+ int fd;
+ char *dbname = mkdbname(fn);
+ /*@observer@*/
+ static const uint32_t 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(**magicp), SEEK_SET) != sizeof(**magicp)) {
+ (void)fprintf(stderr, "%s: error seeking `%s' (%s)\n",
+ __progname, dbname, strerror(errno));
+ return -1;
+ }
+
+ if (write(fd, *magicp, sizeof(**magicp) * *nmagicp)
+ != sizeof(**magicp) * *nmagicp) {
+ (void)fprintf(stderr, "%s: error writing `%s' (%s)\n",
+ __progname, dbname, strerror(errno));
+ return -1;
+ }
+
+ (void)close(fd);
+ return 0;
+}
+/*@=bounds@*/
+
+/*
+ * handle a compiled file.
+ */
+/*@-bounds@*/
+static int
+apprentice_map(/*@unused@*/ const fmagic fm,
+ /*@out@*/ struct magic **magicp, /*@out@*/ uint32_t *nmagicp,
+ const char *fn, /*@unused@*/ int action)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies *magicp, *nmagicp, fileSystem, internalState @*/
+{
+ int fd;
+ struct stat st;
+ uint32_t *ptr;
+ uint32_t version;
+ int needsbyteswap;
+ char *dbname = mkdbname(fn);
+ void *mm = NULL;
+
+ 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 errxit;
+ }
+
+#ifdef HAVE_MMAP
+ if ((mm = 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 errxit;
+ }
+#else
+ mm = xmalloc((size_t)st.st_size);
+ if (read(fd, mm, (size_t)st.st_size) != (size_t)st.st_size) {
+ (void) fprintf(stderr, "%s: Read failed (%s).\n", __progname,
+ strerror(errno));
+ goto errxit;
+ }
+#endif
+ *magicp = mm;
+ (void)close(fd);
+ fd = -1;
+ ptr = (uint32_t *) *magicp;
+ if (ptr == NULL) /* XXX can't happen */
+ goto errxit;
+ if (*ptr != MAGICNO) {
+ if (swap4(*ptr) != MAGICNO) {
+ (void)fprintf(stderr, "%s: Bad magic in `%s'\n",
+ __progname, dbname);
+ goto errxit;
+ }
+ 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 errxit;
+ }
+ *nmagicp = (st.st_size / sizeof(**magicp)) - 1;
+ (*magicp)++;
+ if (needsbyteswap)
+ byteswap(*magicp, *nmagicp);
+ return 0;
+
+errxit:
+ if (fd != -1)
+ (void)close(fd);
+/*@-branchstate@*/
+ if (mm != NULL) {
+#ifdef HAVE_MMAP
+ (void)munmap(mm, (size_t)st.st_size);
+#else
+ free(mm);
+#endif
+ } else {
+ *magicp = NULL;
+ *nmagicp = 0;
+ }
+/*@=branchstate@*/
+ return -1;
+}
+/*@=bounds@*/
+
+/*
+ * Handle one file.
+ */
+static int
+apprentice_1(fmagic fm, const char *fn, int action)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fm, fileSystem, internalState @*/
+{
+/*@-shadow@*/
+ struct magic *magic = NULL;
+ uint32_t nmagic = 0;
+/*@=shadow@*/
+ struct mlist *ml;
+ int rv = -1;
+
+ if (action == COMPILE) {
+ rv = apprentice_file(fm, &magic, &nmagic, fn, action);
+ if (rv)
+ return rv;
+ return apprentice_compile(fm, &magic, &nmagic, fn, action);
+ }
+#ifndef COMPILE_ONLY
+ if ((rv = apprentice_map(fm, &magic, &nmagic, fn, action)) != 0)
+ (void)fprintf(stderr, "%s: Using regular magic file `%s'\n",
+ __progname, fn);
+
+ if (rv != 0)
+ rv = apprentice_file(fm, &magic, &nmagic, fn, action);
+
+ if (rv != 0)
+ return rv;
+
+ if (magic == NULL || nmagic == 0)
+ return rv;
+
+ ml = xmalloc(sizeof(*ml));
+
+ ml->magic = magic;
+ ml->nmagic = nmagic;
+
+ fm->mlist->prev->next = ml;
+ ml->prev = fm->mlist->prev;
+/*@-immediatetrans@*/
+ ml->next = fm->mlist;
+/*@=immediatetrans@*/
+/*@-kepttrans@*/
+ fm->mlist->prev = ml;
+/*@=kepttrans@*/
+
+/*@-compdef -compmempass @*/
+ return rv;
+/*@=compdef =compmempass @*/
+#endif /* COMPILE_ONLY */
+}
+
+/* const char *fn: list of magic files */
+int
+fmagicSetup(fmagic fm, const char *fn, int action)
+{
+ char *p, *mfn;
+ int file_err, errs = -1;
+
+ if (fm->mlist == NULL) {
+ static struct mlist mlist;
+/*@-immediatetrans@*/
+ mlist.next = &mlist;
+ mlist.prev = &mlist;
+ fm->mlist = &mlist;
+/*@=immediatetrans@*/
+ }
+
+ mfn = xstrdup(fn);
+ fn = mfn;
+
+/*@-branchstate@*/
+ while (fn != NULL) {
+ p = strchr(fn, PATHSEP);
+ if (p != NULL)
+ *p++ = '\0';
+ file_err = apprentice_1(fm, fn, action);
+ if (file_err > errs)
+ errs = file_err;
+ fn = p;
+ }
+/*@=branchstate@*/
+ if (errs == -1)
+ (void) fprintf(stderr, "%s: couldn't find any magic files!\n",
+ __progname);
+ if (action == CHECK && errs)
+ exit(EXIT_FAILURE);
+
+ free(mfn);
+/*@-compdef -compmempass@*/
+ return errs;
+/*@=compdef =compmempass@*/
+}
+
+#ifdef COMPILE_ONLY
+int
+main(int argc, char *argv[])
+ /*@*/
+{
+ static struct fmagic_s myfmagic;
+ fmagic fm = &myfmagic;
+ int ret;
+
+ setprogname(argv[0]); /* Retrofit glibc __progname */
+
+ if (argc != 2) {
+ (void)fprintf(stderr, "usage: %s file\n", __progname);
+ exit(1);
+ }
+ fm->magicfile = argv[1];
+
+ exit(apprentice(fm, fm->magicfile, COMPILE));
+}
+#endif /* COMPILE_ONLY */
--- /dev/null
+/*
+ * ASCII magic -- file types that we know based on keywords
+ * that can appear anywhere in the file.
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * Extensively modified by Eric Fischer <enf@pobox.com> in July, 2000,
+ * to handle character codes other than ASCII on a unified basis.
+ *
+ * Joerg Wunsch <joerg@freebsd.org> wrote the original support for 8-bit
+ * international characters, now subsumed into this file.
+ */
+
+/*
+ * 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 "system.h"
+#include "file.h"
+#include "names.h"
+#include "tar.h"
+#include "debug.h"
+
+FILE_RCSID("@(#)Id: ascmagic.c,v 1.32 2002/07/03 18:26:37 christos Exp ")
+
+/*@access fmagic @*/
+
+/*
+ * Stolen (by the author!) from the public domain tar program:
+ * Public Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
+ */
+#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
+
+/*
+ * Quick and dirty octal conversion.
+ *
+ * Result is -1 if the field is invalid (all blank, or nonoctal).
+ */
+/*@-bounds@*/
+static int
+from_oct(int digs, char *where)
+ /*@*/
+{
+ int value;
+
+ while (isspace((unsigned char)*where)) { /* Skip spaces */
+ where++;
+ if (--digs <= 0)
+ return -1; /* All blank field */
+ }
+ value = 0;
+/*@-shiftimplementation@*/
+ while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
+ value = (value << 3) | (*where++ - '0');
+ --digs;
+ }
+/*@=shiftimplementation@*/
+
+ if (digs > 0 && *where && !isspace((unsigned char)*where))
+ return -1; /* Ended on non-space/nul */
+
+ return value;
+}
+/*@=bounds@*/
+
+/*
+ * Return
+ * 0 if the checksum is bad (i.e., probably not a tar archive),
+ * 1 for old UNIX tar file,
+ * 2 for Unix Std (POSIX) tar file.
+ */
+static int
+is_tar(const fmagic fm)
+ /*@*/
+{
+ int nb = fm->nb;
+ union record *header = (union record *)fm->buf;
+ int i;
+ int sum, recsum;
+ char *p;
+
+ if (nb < sizeof(*header))
+ return 0;
+
+ recsum = from_oct(8, header->header.chksum);
+
+ sum = 0;
+ p = header->charptr;
+/*@-sizeoftype@*/
+ for (i = sizeof(union record); --i >= 0;)
+/*@=sizeoftype@*/
+ {
+ /*
+ * We can't use unsigned char here because of old compilers,
+ * e.g. V7.
+ */
+ sum += 0xFF & *p++;
+ }
+
+ /* Adjust checksum to count the "chksum" field as blanks. */
+ for (i = sizeof(header->header.chksum); --i >= 0;)
+ sum -= 0xFF & header->header.chksum[i];
+ sum += ' ' * sizeof header->header.chksum;
+
+ if (sum != recsum)
+ return 0; /* Not a tar archive */
+
+ if (!strcmp(header->header.magic, TARMAGIC))
+ return 2; /* Unix Standard tar archive */
+
+ return 1; /* Old fashioned tar archive */
+}
+typedef unsigned long unichar;
+
+#define MAXLINELEN 300 /* longest sane line length */
+#define ISSPC(x) ((x) == ' ' || (x) == '\t' || (x) == '\r' || (x) == '\n' \
+ || (x) == 0x85 || (x) == '\f')
+
+/*
+ * This table reflects a particular philosophy about what constitutes
+ * "text," and there is room for disagreement about it.
+ *
+ * Version 3.31 of the file command considered a file to be ASCII if
+ * each of its characters was approved by either the isascii() or
+ * isalpha() function. On most systems, this would mean that any
+ * file consisting only of characters in the range 0x00 ... 0x7F
+ * would be called ASCII text, but many systems might reasonably
+ * consider some characters outside this range to be alphabetic,
+ * so the file command would call such characters ASCII. It might
+ * have been more accurate to call this "considered textual on the
+ * local system" than "ASCII."
+ *
+ * It considered a file to be "International language text" if each
+ * of its characters was either an ASCII printing character (according
+ * to the real ASCII standard, not the above test), a character in
+ * the range 0x80 ... 0xFF, or one of the following control characters:
+ * backspace, tab, line feed, vertical tab, form feed, carriage return,
+ * escape. No attempt was made to determine the language in which files
+ * of this type were written.
+ *
+ *
+ * The table below considers a file to be ASCII if all of its characters
+ * are either ASCII printing characters (again, according to the X3.4
+ * standard, not isascii()) or any of the following controls: bell,
+ * backspace, tab, line feed, form feed, carriage return, esc, nextline.
+ *
+ * I include bell because some programs (particularly shell scripts)
+ * use it literally, even though it is rare in normal text. I exclude
+ * vertical tab because it never seems to be used in real text. I also
+ * include, with hesitation, the X3.64/ECMA-43 control nextline (0x85),
+ * because that's what the dd EBCDIC->ASCII table maps the EBCDIC newline
+ * character to. It might be more appropriate to include it in the 8859
+ * set instead of the ASCII set, but it's got to be included in *something*
+ * we recognize or EBCDIC files aren't going to be considered textual.
+ * Some old Unix source files use SO/SI (^N/^O) to shift between Greek
+ * and Latin characters, so these should possibly be allowed. But they
+ * make a real mess on VT100-style displays if they're not paired properly,
+ * so we are probably better off not calling them text.
+ *
+ * A file is considered to be ISO-8859 text if its characters are all
+ * either ASCII, according to the above definition, or printing characters
+ * from the ISO-8859 8-bit extension, characters 0xA0 ... 0xFF.
+ *
+ * Finally, a file is considered to be international text from some other
+ * character code if its characters are all either ISO-8859 (according to
+ * the above definition) or characters in the range 0x80 ... 0x9F, which
+ * ISO-8859 considers to be control characters but the IBM PC and Macintosh
+ * consider to be printing characters.
+ */
+
+#define F 0 /* character never appears in text */
+#define T 1 /* character appears in plain ASCII text */
+#define I 2 /* character appears in ISO-8859 text */
+#define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */
+
+/*@unchecked@*/ /*@observer@*/
+static char text_chars[256] = {
+ /* BEL BS HT LF FF CR */
+ F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */
+ /* ESC */
+ F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */
+ T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */
+ /* NEL */
+ X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */
+ X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */
+ I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */
+};
+
+/*@-bounds@*/
+static int
+looks_ascii(const unsigned char *buf, int nb,
+ /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+ /*@modifies *ubuf, *ulen @*/
+{
+ int i;
+
+ *ulen = 0;
+
+ for (i = 0; i < nb; i++) {
+ int t = text_chars[buf[i]];
+
+ if (t != T)
+ return 0;
+
+ ubuf[(*ulen)++] = buf[i];
+ }
+
+ return 1;
+}
+/*@=bounds@*/
+
+/*@-bounds@*/
+static int
+looks_latin1(const unsigned char *buf, int nb,
+ /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+ /*@modifies *ubuf, *ulen @*/
+{
+ int i;
+
+ *ulen = 0;
+
+ for (i = 0; i < nb; i++) {
+ int t = text_chars[buf[i]];
+
+ if (t != T && t != I)
+ return 0;
+
+ ubuf[(*ulen)++] = buf[i];
+ }
+
+ return 1;
+}
+/*@=bounds@*/
+
+/*@-bounds@*/
+static int
+looks_extended(const unsigned char *buf, int nb,
+ /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+ /*@modifies *ubuf, *ulen @*/
+{
+ int i;
+
+ *ulen = 0;
+
+ for (i = 0; i < nb; i++) {
+ int t = text_chars[buf[i]];
+
+ if (t != T && t != I && t != X)
+ return 0;
+
+ ubuf[(*ulen)++] = buf[i];
+ }
+
+ return 1;
+}
+/*@=bounds@*/
+
+/*@-bounds@*/
+static int
+looks_utf8(const unsigned char *buf, int nb,
+ /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+ /*@modifies *ubuf, *ulen @*/
+{
+ int i, n;
+ unichar c;
+ int gotone = 0;
+
+ *ulen = 0;
+
+ for (i = 0; i < nb; i++) {
+ if ((buf[i] & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */
+ /*
+ * Even if the whole file is valid UTF-8 sequences,
+ * still reject it if it uses weird control characters.
+ */
+
+ if (text_chars[buf[i]] != T)
+ return 0;
+
+ ubuf[(*ulen)++] = buf[i];
+ } else if ((buf[i] & 0x40) == 0) { /* 10xxxxxx never 1st byte */
+ return 0;
+ } else { /* 11xxxxxx begins UTF-8 */
+ int following;
+
+ if ((buf[i] & 0x20) == 0) { /* 110xxxxx */
+ c = buf[i] & 0x1f;
+ following = 1;
+ } else if ((buf[i] & 0x10) == 0) { /* 1110xxxx */
+ c = buf[i] & 0x0f;
+ following = 2;
+ } else if ((buf[i] & 0x08) == 0) { /* 11110xxx */
+ c = buf[i] & 0x07;
+ following = 3;
+ } else if ((buf[i] & 0x04) == 0) { /* 111110xx */
+ c = buf[i] & 0x03;
+ following = 4;
+ } else if ((buf[i] & 0x02) == 0) { /* 1111110x */
+ c = buf[i] & 0x01;
+ following = 5;
+ } else
+ return 0;
+
+ for (n = 0; n < following; n++) {
+ i++;
+ if (i >= nb)
+ goto done;
+
+ if ((buf[i] & 0x80) == 0 || (buf[i] & 0x40))
+ return 0;
+
+ c = (c << 6) + (buf[i] & 0x3f);
+ }
+
+ ubuf[(*ulen)++] = c;
+ gotone = 1;
+ }
+ }
+done:
+ return gotone; /* don't claim it's UTF-8 if it's all 7-bit */
+}
+/*@=bounds@*/
+
+/*@-bounds@*/
+static int
+looks_unicode(const unsigned char *buf, int nb,
+ /*@out@*/ unichar *ubuf, /*@out@*/ int *ulen)
+ /*@modifies *ubuf, *ulen @*/
+{
+ int bigend;
+ int i;
+
+ if (nb < 2)
+ return 0;
+
+ if (buf[0] == 0xff && buf[1] == 0xfe)
+ bigend = 0;
+ else if (buf[0] == 0xfe && buf[1] == 0xff)
+ bigend = 1;
+ else
+ return 0;
+
+ *ulen = 0;
+
+ for (i = 2; i + 1 < nb; i += 2) {
+ /* XXX fix to properly handle chars > 65536 */
+
+ if (bigend)
+ ubuf[(*ulen)++] = buf[i + 1] + 256 * buf[i];
+ else
+ ubuf[(*ulen)++] = buf[i] + 256 * buf[i + 1];
+
+ if (ubuf[*ulen - 1] == 0xfffe)
+ return 0;
+ if (ubuf[*ulen - 1] < 128 && text_chars[ubuf[*ulen - 1]] != T)
+ return 0;
+ }
+
+ return 1;
+}
+/*@=bounds@*/
+
+#undef F
+#undef T
+#undef I
+#undef X
+
+/*
+ * This table maps each EBCDIC character to an (8-bit extended) ASCII
+ * character, as specified in the rationale for the dd(1) command in
+ * draft 11.2 (September, 1991) of the POSIX P1003.2 standard.
+ *
+ * Unfortunately it does not seem to correspond exactly to any of the
+ * five variants of EBCDIC documented in IBM's _Enterprise Systems
+ * Architecture/390: Principles of Operation_, SA22-7201-06, Seventh
+ * Edition, July, 1999, pp. I-1 - I-4.
+ *
+ * Fortunately, though, all versions of EBCDIC, including this one, agree
+ * on most of the printing characters that also appear in (7-bit) ASCII.
+ * Of these, only '|', '!', '~', '^', '[', and ']' are in question at all.
+ *
+ * Fortunately too, there is general agreement that codes 0x00 through
+ * 0x3F represent control characters, 0x41 a nonbreaking space, and the
+ * remainder printing characters.
+ *
+ * This is sufficient to allow us to identify EBCDIC text and to distinguish
+ * between old-style and internationalized examples of text.
+ */
+
+/*@unchecked@*/ /*@observer@*/
+static unsigned char ebcdic_to_ascii[] = {
+ 0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
+128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
+144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
+' ', 160, 161, 162, 163, 164, 165, 166, 167, 168, 213, '.', '<', '(', '+', '|',
+'&', 169, 170, 171, 172, 173, 174, 175, 176, 177, '!', '$', '*', ')', ';', '~',
+'-', '/', 178, 179, 180, 181, 182, 183, 184, 185, 203, ',', '%', '_', '>', '?',
+186, 187, 188, 189, 190, 191, 192, 193, 194, '`', ':', '#', '@', '\'','=', '"',
+195, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 196, 197, 198, 199, 200, 201,
+202, 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', '^', 204, 205, 206, 207, 208,
+209, 229, 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 210, 211, 212, '[', 214, 215,
+216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, ']', 230, 231,
+'{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 232, 233, 234, 235, 236, 237,
+'}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 238, 239, 240, 241, 242, 243,
+'\\',159, 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 244, 245, 246, 247, 248, 249,
+'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 250, 251, 252, 253, 254, 255
+};
+
+/*
+ * The following EBCDIC-to-ASCII table may relate more closely to reality,
+ * or at least to modern reality. It comes from
+ *
+ * http://ftp.s390.ibm.com/products/oe/bpxqp9.html
+ *
+ * and maps the characters of EBCDIC code page 1047 (the code used for
+ * Unix-derived software on IBM's 390 systems) to the corresponding
+ * characters from ISO 8859-1.
+ *
+ * If this table is used instead of the above one, some of the special
+ * cases for the NEL character can be taken out of the code.
+ */
+
+/*@unchecked@*/ /*@unused@*/ /*@observer@*/
+static unsigned char ebcdic_1047_to_8859[] = {
+0x00,0x01,0x02,0x03,0x9C,0x09,0x86,0x7F,0x97,0x8D,0x8E,0x0B,0x0C,0x0D,0x0E,0x0F,
+0x10,0x11,0x12,0x13,0x9D,0x0A,0x08,0x87,0x18,0x19,0x92,0x8F,0x1C,0x1D,0x1E,0x1F,
+0x80,0x81,0x82,0x83,0x84,0x85,0x17,0x1B,0x88,0x89,0x8A,0x8B,0x8C,0x05,0x06,0x07,
+0x90,0x91,0x16,0x93,0x94,0x95,0x96,0x04,0x98,0x99,0x9A,0x9B,0x14,0x15,0x9E,0x1A,
+0x20,0xA0,0xE2,0xE4,0xE0,0xE1,0xE3,0xE5,0xE7,0xF1,0xA2,0x2E,0x3C,0x28,0x2B,0x7C,
+0x26,0xE9,0xEA,0xEB,0xE8,0xED,0xEE,0xEF,0xEC,0xDF,0x21,0x24,0x2A,0x29,0x3B,0x5E,
+0x2D,0x2F,0xC2,0xC4,0xC0,0xC1,0xC3,0xC5,0xC7,0xD1,0xA6,0x2C,0x25,0x5F,0x3E,0x3F,
+0xF8,0xC9,0xCA,0xCB,0xC8,0xCD,0xCE,0xCF,0xCC,0x60,0x3A,0x23,0x40,0x27,0x3D,0x22,
+0xD8,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0xAB,0xBB,0xF0,0xFD,0xFE,0xB1,
+0xB0,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0xAA,0xBA,0xE6,0xB8,0xC6,0xA4,
+0xB5,0x7E,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0xA1,0xBF,0xD0,0x5B,0xDE,0xAE,
+0xAC,0xA3,0xA5,0xB7,0xA9,0xA7,0xB6,0xBC,0xBD,0xBE,0xDD,0xA8,0xAF,0x5D,0xB4,0xD7,
+0x7B,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0xAD,0xF4,0xF6,0xF2,0xF3,0xF5,
+0x7D,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0xB9,0xFB,0xFC,0xF9,0xFA,0xFF,
+0x5C,0xF7,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0xB2,0xD4,0xD6,0xD2,0xD3,0xD5,
+0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0xB3,0xDB,0xDC,0xD9,0xDA,0x9F
+};
+
+/*
+ * Copy buf[0 ... nb-1] into out[], translating EBCDIC to ASCII.
+ */
+/*@-bounds@*/
+static void
+from_ebcdic(const unsigned char *buf, int nb, /*@out@*/ unsigned char *otp)
+ /*@modifies *otp @*/
+{
+ int i;
+
+ for (i = 0; i < nb; i++) {
+ otp[i] = ebcdic_to_ascii[buf[i]];
+ }
+}
+/*@=bounds@*/
+
+/*@-bounds@*/
+static int
+fmagicAMatch(const unsigned char *s, const unichar *us, int ulen)
+ /*@*/
+{
+ size_t i;
+
+ for (i = 0; i < ulen; i++) {
+ if (s[i] != us[i])
+ return 0;
+ }
+
+ if (s[i])
+ return 0;
+ else
+ return 1;
+}
+/*@=bounds@*/
+
+/* int nb: size actually read */
+/*@-bounds@*/
+int
+fmagicA(fmagic fm)
+{
+ unsigned char * buf = fm->buf;
+ int nb = fm->nb;
+
+ char nbuf[HOWMANY+1]; /* one extra for terminating '\0' */
+ unichar ubuf[HOWMANY+1]; /* one extra for terminating '\0' */
+ int ulen;
+ struct names *p;
+ int i;
+
+ char *code = NULL;
+ char *code_mime = NULL;
+ char *type = NULL;
+ char *subtype = NULL;
+ char *subtype_mime = NULL;
+
+ int has_escapes = 0;
+ int has_backspace = 0;
+
+ int n_crlf = 0;
+ int n_lf = 0;
+ int n_cr = 0;
+ int n_nel = 0;
+
+ int last_line_end = -1;
+ int has_long_lines = 0;
+
+ /*
+ * Do the tar test first, because if the first file in the tar
+ * archive starts with a dot, we can confuse it with an nroff file.
+ */
+ switch (is_tar(fm)) {
+ case 1:
+ fmagicPrintf(fm, ((fm->flags & FMAGIC_FLAGS_MIME)
+ ? "application/x-tar" : "tar archive"));
+ return 1;
+ case 2:
+ fmagicPrintf(fm, ((fm->flags & FMAGIC_FLAGS_MIME)
+ ? "application/x-tar, POSIX" : "POSIX tar archive"));
+ return 1;
+ }
+
+ /*
+ * Undo the NUL-termination kindly provided by fmagicProcess()
+ * but leave at least one byte to look at
+ */
+
+ while (nb > 1 && buf[nb - 1] == '\0')
+ nb--;
+
+ /*
+ * Then try to determine whether it's any character code we can
+ * identify. Each of these tests, if it succeeds, will leave
+ * the text converted into one-unichar-per-character Unicode in
+ * ubuf, and the number of characters converted in ulen.
+ */
+ if (looks_ascii(buf, nb, ubuf, &ulen)) {
+ code = "ASCII";
+ code_mime = "us-ascii";
+ type = "text";
+ } else if (looks_utf8(buf, nb, ubuf, &ulen)) {
+ code = "UTF-8 Unicode";
+ code_mime = "utf-8";
+ type = "text";
+ } else if ((i = looks_unicode(buf, nb, ubuf, &ulen))) {
+ if (i == 1)
+ code = "Little-endian UTF-16 Unicode";
+ else
+ code = "Big-endian UTF-16 Unicode";
+
+ type = "character data";
+ code_mime = "utf-16"; /* is this defined? */
+ } else if (looks_latin1(buf, nb, ubuf, &ulen)) {
+ code = "ISO-8859";
+ type = "text";
+ code_mime = "iso-8859-1";
+ } else if (looks_extended(buf, nb, ubuf, &ulen)) {
+ code = "Non-ISO extended-ASCII";
+ type = "text";
+ code_mime = "unknown";
+ } else {
+ from_ebcdic(buf, nb, nbuf);
+
+ if (looks_ascii(nbuf, nb, ubuf, &ulen)) {
+ code = "EBCDIC";
+ type = "character data";
+ code_mime = "ebcdic";
+ } else if (looks_latin1(nbuf, nb, ubuf, &ulen)) {
+ code = "International EBCDIC";
+ type = "character data";
+ code_mime = "ebcdic";
+ } else {
+ return 0; /* doesn't look like text at all */
+ }
+ }
+
+ /*
+ * for troff, look for . + letter + letter or .\";
+ * this must be done to disambiguate tar archives' ./file
+ * and other trash from real troff input.
+ *
+ * I believe Plan 9 troff allows non-ASCII characters in the names
+ * of macros, so this test might possibly fail on such a file.
+ */
+ if (*ubuf == '.') {
+ unichar *tp = ubuf + 1;
+
+ while (ISSPC(*tp))
+ ++tp; /* skip leading whitespace */
+ if ((tp[0] == '\\' && tp[1] == '\"') ||
+ (isascii(tp[0]) && isalnum(tp[0]) &&
+ isascii(tp[1]) && isalnum(tp[1]) &&
+ ISSPC(tp[2]))) {
+ subtype_mime = "text/troff";
+ subtype = "troff or preprocessor input";
+ goto subtype_identified;
+ }
+ }
+
+ if ((*buf == 'c' || *buf == 'C') && ISSPC(buf[1])) {
+ subtype_mime = "text/fortran";
+ subtype = "fortran program";
+ goto subtype_identified;
+ }
+
+ /* look for tokens from names.h - this is expensive! */
+
+ i = 0;
+ while (i < ulen) {
+ int end;
+
+ /*
+ * skip past any leading space
+ */
+ while (i < ulen && ISSPC(ubuf[i]))
+ i++;
+ if (i >= ulen)
+ break;
+
+ /*
+ * find the next whitespace
+ */
+ for (end = i + 1; end < nb; end++)
+ if (ISSPC(ubuf[end]))
+ /*@innerbreak@*/ break;
+
+ /*
+ * compare the word thus isolated against the token list
+ */
+/*@-sizeoftype@*/
+ for (p = names; p < names + NNAMES; p++)
+/*@=sizeoftype@*/
+ {
+ if (p->name == NULL)
+ /*@innerbreak@*/ break;
+ if (fmagicAMatch(p->name, ubuf + i, end - i)) {
+ subtype = types[p->type].human;
+ subtype_mime = types[p->type].mime;
+ goto subtype_identified;
+ }
+ }
+
+ i = end;
+ }
+
+subtype_identified:
+
+ /*
+ * Now try to discover other details about the file.
+ */
+ for (i = 0; i < ulen; i++) {
+ if (i > last_line_end + MAXLINELEN)
+ has_long_lines = 1;
+
+ if (ubuf[i] == '\033')
+ has_escapes = 1;
+ if (ubuf[i] == '\b')
+ has_backspace = 1;
+
+ if (ubuf[i] == '\r' && (i + 1 < ulen && ubuf[i + 1] == '\n')) {
+ n_crlf++;
+ last_line_end = i;
+ }
+ if (ubuf[i] == '\r' && (i + 1 >= ulen || ubuf[i + 1] != '\n')) {
+ n_cr++;
+ last_line_end = i;
+ }
+ if (ubuf[i] == '\n' && (i - 1 < 0 || ubuf[i - 1] != '\r')) {
+ n_lf++;
+ last_line_end = i;
+ }
+ if (ubuf[i] == 0x85) { /* X3.64/ECMA-43 "next line" character */
+ n_nel++;
+ last_line_end = i;
+ }
+ }
+
+ if ((fm->flags & FMAGIC_FLAGS_MIME)) {
+ if (subtype_mime != NULL)
+ fmagicPrintf(fm, subtype_mime);
+ else
+ fmagicPrintf(fm, "text/plain");
+
+ if (code_mime != NULL) {
+ fmagicPrintf(fm, "; charset=");
+ fmagicPrintf(fm, code_mime);
+ }
+ } else {
+ fmagicPrintf(fm, code);
+
+ if (subtype != NULL) {
+ fmagicPrintf(fm, " ");
+ fmagicPrintf(fm, subtype);
+ }
+ fmagicPrintf(fm, " ");
+ fmagicPrintf(fm, type);
+
+ if (has_long_lines)
+ fmagicPrintf(fm, ", with very long lines");
+
+ /*
+ * Only report line terminators if we find one other than LF,
+ * or if we find none at all.
+ */
+ if ((n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0) ||
+ (n_crlf != 0 || n_cr != 0 || n_nel != 0)) {
+ fmagicPrintf(fm, ", with");
+
+ if (n_crlf == 0 && n_cr == 0 && n_nel == 0 && n_lf == 0)
+ fmagicPrintf(fm, " no");
+ else {
+ if (n_crlf) {
+ fmagicPrintf(fm, " CRLF");
+ if (n_cr || n_lf || n_nel)
+ fmagicPrintf(fm, ",");
+ }
+ if (n_cr) {
+ fmagicPrintf(fm, " CR");
+ if (n_lf || n_nel)
+ fmagicPrintf(fm, ",");
+ }
+ if (n_lf) {
+ fmagicPrintf(fm, " LF");
+ if (n_nel)
+ fmagicPrintf(fm, ",");
+ }
+ if (n_nel)
+ fmagicPrintf(fm, " NEL");
+ }
+
+ fmagicPrintf(fm, " line terminators");
+ }
+
+ if (has_escapes)
+ fmagicPrintf(fm, ", with escape sequences");
+ if (has_backspace)
+ fmagicPrintf(fm, ", with overstriking");
+ }
+
+ return 1;
+}
+/*@=bounds@*/
--- /dev/null
+
+#include "system.h"
+#include "file.h"
+#include "debug.h"
+
+FILE_RCSID("@(#)Id: compress.c,v 1.25 2002/07/03 18:26:37 christos Exp ")
+
+/*@access fmagic @*/
+
+/*@-nullassign@*/
+/*@unchecked@*/
+static struct {
+/*@observer@*/
+ const char *magic;
+ int maglen;
+/*@observer@*/
+ const char *const argv[3];
+ int silent;
+} compr[] = {
+ { "\037\235", 2, { "gzip", "-cdq", NULL }, 1 }, /* compressed */
+ /* Uncompress can get stuck; so use gzip first if we have it
+ * Idea from Damien Clark, thanks! */
+ { "\037\235", 2, { "uncompress", "-c", NULL }, 1 }, /* compressed */
+ { "\037\213", 2, { "gzip", "-cdq", NULL }, 1 }, /* gzipped */
+ { "\037\236", 2, { "gzip", "-cdq", NULL }, 1 }, /* frozen */
+ { "\037\240", 2, { "gzip", "-cdq", NULL }, 1 }, /* SCO LZH */
+ /* the standard pack utilities do not accept standard input */
+ { "\037\036", 2, { "gzip", "-cdq", NULL }, 0 }, /* packed */
+ { "BZh", 3, { "bzip2", "-cd", NULL }, 1 }, /* bzip2-ed */
+};
+/*@=nullassign@*/
+
+/*@unchecked@*/
+static int ncompr = sizeof(compr) / sizeof(compr[0]);
+
+/*
+ * `safe' write for sockets and pipes.
+ */
+static int
+swrite(int fd, const void *buf, size_t n)
+ /*@*/
+{
+ int rv;
+ size_t rn = n;
+
+ do {
+ switch (rv = write(fd, buf, n)) {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ return -1;
+ default:
+ n -= rv;
+ buf = ((const char *)buf) + rv;
+ /*@switchbreak@*/ break;
+ }
+ } while (n > 0);
+ return rn;
+}
+
+
+/*
+ * `safe' read for sockets and pipes.
+ */
+static int
+sread(int fd, /*@out@*/ void *buf, size_t n)
+ /*@modifies *buf @*/
+{
+ int rv;
+ size_t rn = n;
+
+ do {
+ switch (rv = read(fd, buf, n)) {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ return -1;
+ case 0:
+ return rn - n;
+ default:
+ n -= rv;
+ buf = ((char *)buf) + rv;
+ /*@switchbreak@*/ break;
+ }
+ } while (n > 0);
+ return rn;
+}
+
+int
+pipe2file(int fd, void *startbuf, size_t nbytes)
+{
+ char buf[4096];
+ int r, tfd;
+
+ (void)strcpy(buf, "/tmp/file.XXXXXX");
+#ifndef HAVE_MKSTEMP
+ {
+ char *ptr = mktemp(buf);
+ tfd = open(ptr, O_RDWR|O_TRUNC|O_EXCL|O_CREAT, 0600);
+ r = errno;
+ (void)unlink(ptr);
+ errno = r;
+ }
+#else
+ tfd = mkstemp(buf);
+ r = errno;
+ (void)unlink(buf);
+ errno = r;
+#endif
+ if (tfd == -1) {
+ error(EXIT_FAILURE, 0, "Can't create temporary file for pipe copy (%s)\n",
+ strerror(errno));
+ /*@notreached@*/
+ }
+
+ if (swrite(tfd, startbuf, nbytes) != nbytes)
+ r = 1;
+ else {
+ while ((r = sread(fd, buf, sizeof(buf))) > 0)
+ if (swrite(tfd, buf, r) != r)
+ break;
+ }
+
+ switch (r) {
+ case -1:
+ error(EXIT_FAILURE, 0, "Error copying from pipe to temp file (%s)\n",
+ strerror(errno));
+ /*@notreached@*/break;
+ case 0:
+ break;
+ default:
+ error(EXIT_FAILURE, 0, "Error while writing to temp file (%s)\n",
+ strerror(errno));
+ /*@notreached@*/
+ }
+
+ /*
+ * We duplicate the file descriptor, because fclose on a
+ * tmpfile will delete the file, but any open descriptors
+ * can still access the phantom inode.
+ */
+ if ((fd = dup2(tfd, fd)) == -1) {
+ error(EXIT_FAILURE, 0, "Couldn't dup destcriptor for temp file(%s)\n",
+ strerror(errno));
+ /*@notreached@*/
+ }
+ (void)close(tfd);
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+ error(EXIT_FAILURE, 0, "Couldn't seek on temp file (%s)\n", strerror(errno));
+ /*@notreached@*/
+ }
+ return fd;
+}
+
+#ifdef HAVE_LIBZ
+
+#define FHCRC (1 << 1)
+#define FEXTRA (1 << 2)
+#define FNAME (1 << 3)
+#define FCOMMENT (1 << 4)
+
+/*@-bounds@*/
+static int
+uncompressgzipped(const unsigned char *old,
+ /*@out@*/ unsigned char **newch, int n)
+ /*@globals fileSystem @*/
+ /*@modifies *newch, fileSystem @*/
+{
+ unsigned char flg = old[3];
+ int data_start = 10;
+ z_stream z;
+ int rc;
+
+ if (flg & FEXTRA)
+ data_start += 2 + old[data_start] + old[data_start + 1] * 256;
+ if (flg & FNAME) {
+ while(old[data_start])
+ data_start++;
+ data_start++;
+ }
+ if(flg & FCOMMENT) {
+ while(old[data_start])
+ data_start++;
+ data_start++;
+ }
+ if(flg & FHCRC)
+ data_start += 2;
+
+ *newch = (unsigned char *) xmalloc(HOWMANY + 1);
+
+ z.next_in = (Bytef *)(old + data_start);
+ z.avail_in = n - data_start;
+ z.next_out = *newch;
+ z.avail_out = HOWMANY;
+ z.zalloc = NULL;
+ z.zfree = NULL;
+ z.opaque = NULL;
+
+/*@-sizeoftype@*/
+/*@-type@*/
+ rc = inflateInit2(&z, -15);
+/*@=type@*/
+/*@=sizeoftype@*/
+ if (rc != Z_OK) {
+ fprintf(stderr,"%s: zlib: %s\n", __progname,
+ (z.msg != NULL ? z.msg : ""));
+ return 0;
+ }
+
+/*@-type@*/
+ rc = inflate(&z, Z_SYNC_FLUSH);
+/*@=type@*/
+ if (rc != Z_OK && rc != Z_STREAM_END) {
+ fprintf(stderr,"%s: zlib: %s\n", __progname,
+ (z.msg != NULL ? z.msg : ""));
+ return 0;
+ }
+
+ n = z.total_out;
+/*@-type@*/
+ (void) inflateEnd(&z);
+/*@=type@*/
+
+ /* let's keep the nul-terminate tradition */
+ (*newch)[n++] = '\0';
+
+ return n;
+}
+/*@=bounds@*/
+#endif
+
+/*@-bounds@*/
+static int
+uncompressbuf(int method, const unsigned char *old,
+ /*@out@*/ unsigned char **newch, int n)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies *newch, fileSystem, internalState @*/
+{
+ int fdin[2], fdout[2];
+ pid_t pid;
+
+#ifdef HAVE_LIBZ
+ if (method == 2)
+ return uncompressgzipped(old,newch,n);
+#endif
+
+ if (pipe(fdin) == -1 || pipe(fdout) == -1) {
+ error(EXIT_FAILURE, 0, "cannot create pipe (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+
+ switch ((pid = fork())) {
+ case 0: /* child */
+ (void) close(0);
+ (void) dup(fdin[0]);
+ (void) close(fdin[0]);
+ (void) close(fdin[1]);
+
+ (void) close(1);
+ (void) dup(fdout[1]);
+ (void) close(fdout[0]);
+ (void) close(fdout[1]);
+ if (compr[method].silent)
+ (void) close(2);
+
+ (void) execvp(compr[method].argv[0],
+ (char *const *)compr[method].argv);
+ exit(EXIT_FAILURE);
+ /*@notreached@*/ break;
+ case -1:
+ error(EXIT_FAILURE, 0, "could not fork (%s).\n", strerror(errno));
+ /*@notreached@*/break;
+
+ default: /* parent */
+ (void) close(fdin[0]);
+ (void) close(fdout[1]);
+
+ n--; /* The buffer is NUL terminated, and we don't need that. */
+ if (swrite(fdin[1], old, n) != n) {
+ n = 0;
+ goto errxit;
+ }
+ (void) close(fdin[1]);
+ fdin[1] = -1;
+ *newch = (unsigned char *) xmalloc(HOWMANY + 1);
+ if ((n = sread(fdout[0], *newch, HOWMANY)) <= 0) {
+ free(*newch);
+ n = 0;
+ goto errxit;
+ }
+ /* NUL terminate, as every buffer is handled here. */
+ (*newch)[n++] = '\0';
+errxit:
+ if (fdin[1] != -1)
+ (void) close(fdin[1]);
+ (void) close(fdout[0]);
+ pid = waitpid(pid, NULL, 0);
+ return n;
+ }
+ /*@notreached@*/
+ return 0;
+}
+/*@=bounds@*/
+
+/*
+ * compress routines:
+ * fmagicZ() - returns 0 if not recognized, uncompresses and prints
+ * information if recognized
+ */
+int
+fmagicZ(fmagic fm)
+{
+ unsigned char * buf = fm->buf;
+ int nb = fm->nb;
+ unsigned char * newbuf;
+ int newsize;
+ int i;
+
+ for (i = 0; i < ncompr; i++) {
+/*@-boundsread@*/
+ if (nb < compr[i].maglen)
+ continue;
+/*@=boundsread@*/
+ if (memcmp(buf, compr[i].magic, compr[i].maglen) == 0 &&
+ (newsize = uncompressbuf(i, buf, &newbuf, nb)) != 0) {
+ fm->buf = newbuf;
+ fm->nb = newsize;
+ (void) fmagicF(fm, 1);
+ fm->buf = buf;
+ fm->nb = nb;
+/*@-kepttrans@*/
+ free(newbuf);
+/*@=kepttrans@*/
+ printf(" (");
+ (void) fmagicF(fm, 0);
+ printf(")");
+ return 1;
+ }
+ }
+
+ if (i == ncompr)
+ return 0;
+
+ return 1;
+}
--- /dev/null
+/*
+ * file - find type of a file or files - main program.
+ *
+ * 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 "system.h"
+#include "file.h"
+#include "patchlevel.h"
+#include "debug.h"
+
+FILE_RCSID("@(#)Id: file.c,v 1.66 2002/07/03 19:00:41 christos Exp ")
+
+/*@access fmagic @*/
+
+#ifdef S_IFLNK
+# define USAGE "Usage: %s [-bciknsvzL] [-f namefile] [-m magicfiles] file...\n"
+#else
+# define USAGE "Usage: %s [-bciknsvz] [-f namefile] [-m magicfiles] file...\n"
+#endif
+
+#ifdef __EMX__
+static char *apptypeName = NULL;
+int os2_apptype (const char *fn, char *buf, int nb);
+#endif /* __EMX__ */
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 512
+#endif
+
+ /* Global command-line options */
+/*@unchecked@*/
+static int nobuffer = 0; /* Do not buffer stdout */
+
+/*
+ * unwrap -- read a file of filenames, do each one.
+ */
+/*@-bounds@*/
+static void
+unwrap(fmagic fm, char *fn)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fm, fileSystem, internalState @*/
+{
+ char buf[MAXPATHLEN];
+ FILE *f;
+ int wid = 0, cwid;
+ int xx;
+
+ if (strcmp("-", fn) == 0) {
+ f = stdin;
+ wid = 1;
+ } else {
+ if ((f = fopen(fn, "r")) == NULL) {
+ error(EXIT_FAILURE, 0, "Cannot open `%s' (%s).\n", fn, strerror(errno));
+ /*@notreached@*/
+ }
+
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ cwid = strlen(buf) - 1;
+ if (cwid > wid)
+ wid = cwid;
+ }
+
+ rewind(f);
+ }
+
+/*@-nullpass@*/ /* LCL: buf is null??? */
+ while (fgets(buf, sizeof(buf), f) != NULL)
+/*@=nullpass@*/
+ {
+ buf[strlen(buf)-1] = '\0';
+ fm->obp = fm->obuf;
+ *fm->obp = '\0';
+ fm->nob = sizeof(fm->obuf);
+ xx = fmagicProcess(fm, buf, wid);
+ fprintf(stdout, "%s\n", fm->obuf);
+ if (nobuffer)
+ (void) fflush(stdout);
+ }
+
+ (void) fclose(f);
+}
+/*@=bounds@*/
+
+/*@exits@*/
+static void
+usage(void)
+ /*@globals fileSystem @*/
+ /*@modifies fileSystem @*/
+{
+ (void)fprintf(stderr, USAGE, __progname);
+ (void)fprintf(stderr, "Usage: %s -C [-m magic]\n", __progname);
+#ifdef HAVE_GETOPT_H
+ (void)fputs("Try `file --help' for more information.\n", stderr);
+#endif
+ exit(EXIT_FAILURE);
+}
+
+#ifdef HAVE_GETOPT_H
+/*@exits@*/
+static void
+help(void)
+ /*@globals fileSystem @*/
+ /*@modifies fileSystem @*/
+{
+ (void) puts(
+"Usage: file [OPTION]... [FILE]...\n"
+"Determine file type of FILEs.\n"
+"\n"
+" -m, --magic-file LIST use LIST as a colon-separated list of magic\n"
+" number files\n"
+" -z, --uncompress try to look inside compressed files\n"
+" -b, --brief do not prepend filenames to output lines\n"
+" -c, --checking-printout print the parsed form of the magic file, use in\n"
+" conjunction with -m to debug a new magic file\n"
+" before installing it\n"
+" -f, --files-from FILE read the filenames to be examined from FILE\n"
+" -i, --mime output mime type strings\n"
+" -k, --keep-going don't stop at the first match\n"
+" -L, --dereference causes symlinks to be followed\n"
+" -n, --no-buffer do not buffer output\n"
+" -s, --special-files treat special (block/char devices) files as\n"
+" ordinary ones\n"
+" --help display this help and exit\n"
+" --version output version information and exit\n"
+);
+ exit(0);
+}
+#endif
+
+/*
+ * main - parse arguments and handle options
+ */
+/*@-bounds@*/
+int
+main(int argc, char **argv)
+ /*@globals global_fmagic, nobuffer,
+ default_magicfile, optind,
+ fileSystem, internalState @*/
+ /*@modifies global_fmagic, nobuffer,
+ default_magicfile, optind,
+ fileSystem, internalState @*/
+{
+ int xx;
+ int c;
+ int action = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
+ char *mime, *home, *usermagic;
+ fmagic fm = global_fmagic;
+ struct stat sb;
+#define OPTSTRING "bcdf:ikm:nsvzCL"
+#ifdef HAVE_GETOPT_H
+ int longindex = 0;
+/*@-nullassign -readonlytrans@*/
+ static struct option long_options[] =
+ {
+ {"version", 0, 0, 'v'},
+ {"help", 0, 0, 0},
+ {"brief", 0, 0, 'b'},
+ {"checking-printout", 0, 0, 'c'},
+ {"debug", 0, 0, 'd'},
+ {"files-from", 1, 0, 'f'},
+ {"mime", 0, 0, 'i'},
+ {"keep-going", 0, 0, 'k'},
+#ifdef S_IFLNK
+ {"dereference", 0, 0, 'L'},
+#endif
+ {"magic-file", 1, 0, 'm'},
+ {"uncompress", 0, 0, 'z'},
+ {"no-buffer", 0, 0, 'n'},
+ {"special-files", 0, 0, 's'},
+ {"compile", 0, 0, 'C'},
+ {0, 0, 0, 0},
+ };
+/*@=nullassign =readonlytrans@*/
+#endif
+
+#if HAVE_MCHECK_H && HAVE_MTRACE
+ /*@-noeffect@*/
+ mtrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
+ /*@=noeffect@*/
+#endif
+
+#ifdef LC_CTYPE
+ setlocale(LC_CTYPE, ""); /* makes islower etc work for other langs */
+#endif
+
+#ifdef __EMX__
+ /* sh-like wildcard expansion! Shouldn't hurt at least ... */
+ _wildcard(&argc, &argv);
+#endif
+
+/*@-assignexpose@*/
+ fm->magicfile = default_magicfile;
+/*@=assignexpose@*/
+ if ((usermagic = getenv("MAGIC")) != NULL)
+ fm->magicfile = usermagic;
+ else {
+ if ((home = getenv("HOME")) != NULL) {
+ size_t nb = strlen(home) + 8;
+ usermagic = xmalloc(nb);
+ (void)strcpy(usermagic, home);
+ (void)strcat(usermagic, "/.magic");
+ if (stat(usermagic, &sb)<0)
+ free(usermagic);
+ else
+ fm->magicfile = usermagic;
+ }
+ }
+
+#ifndef HAVE_GETOPT_H
+ while ((c = getopt(argc, argv, OPTSTRING)) != -1)
+#else
+ while ((c = getopt_long(argc, argv, OPTSTRING, long_options,
+ &longindex)) != -1)
+#endif
+ {
+ switch (c) {
+#ifdef HAVE_GETOPT_H
+ case 0 :
+ if (longindex == 1)
+ help();
+ /*@switchbreak@*/ break;
+#endif
+ case 'b':
+ fm->flags |= FMAGIC_FLAGS_BRIEF;
+ /*@switchbreak@*/ break;
+ case 'c':
+ action = CHECK;
+ /*@switchbreak@*/ break;
+ case 'C':
+ action = COMPILE;
+ /*@switchbreak@*/ break;
+ case 'd':
+ fm->flags |= FMAGIC_FLAGS_DEBUG;
+ /*@switchbreak@*/ break;
+ case 'f':
+ if (!app) {
+ ret = fmagicSetup(fm, fm->magicfile, action);
+ if (action)
+ exit(ret);
+ app = 1;
+ }
+ unwrap(fm, optarg);
+ ++didsomefiles;
+ /*@switchbreak@*/ break;
+ case 'i':
+ fm->flags |= FMAGIC_FLAGS_MIME;
+ mime = malloc(strlen(fm->magicfile) + sizeof(".mime"));
+ if (mime != NULL) {
+ (void)strcpy(mime, fm->magicfile);
+ (void)strcat(mime, ".mime");
+ }
+ fm->magicfile = mime;
+ /*@switchbreak@*/ break;
+ case 'k':
+ fm->flags |= FMAGIC_FLAGS_CONTINUE;
+ /*@switchbreak@*/ break;
+ case 'm':
+/*@-assignexpose@*/
+ fm->magicfile = optarg;
+/*@=assignexpose@*/
+ /*@switchbreak@*/ break;
+ case 'n':
+ ++nobuffer;
+ /*@switchbreak@*/ break;
+ case 's':
+ fm->flags |= FMAGIC_FLAGS_SPECIAL;
+ /*@switchbreak@*/ break;
+ case 'v':
+ (void) fprintf(stdout, "%s-%d.%d\n", __progname,
+ FILE_VERSION_MAJOR, patchlevel);
+ (void) fprintf(stdout, "magic file from %s\n",
+ fm->magicfile);
+ return 1;
+ case 'z':
+ fm->flags |= FMAGIC_FLAGS_UNCOMPRESS;
+ /*@switchbreak@*/ break;
+#ifdef S_IFLNK
+ case 'L':
+ fm->flags |= FMAGIC_FLAGS_FOLLOW;
+ /*@switchbreak@*/ break;
+#endif
+ case '?':
+ default:
+ errflg++;
+ /*@switchbreak@*/ break;
+ }
+ }
+
+ if (errflg)
+ usage();
+
+ if (!app) {
+/*@-nullpass@*/ /* FIX: fm->magicfile may be null */
+ ret = fmagicSetup(fm, fm->magicfile, action);
+/*@=nullpass@*/
+ if (action)
+ exit(ret);
+ app = 1;
+ }
+
+ if (optind == argc) {
+ if (!didsomefiles)
+ usage();
+ } else {
+ int i, wid, nw;
+ for (wid = 0, i = optind; i < argc; i++) {
+ nw = strlen(argv[i]);
+ if (nw > wid)
+ wid = nw;
+ }
+ for (; optind < argc; optind++) {
+ fm->obp = fm->obuf;
+ *fm->obp = '\0';
+ fm->nob = sizeof(fm->obuf);
+ xx = fmagicProcess(fm, argv[optind], wid);
+ fprintf(stdout, "%s\n", fm->obuf);
+ if (nobuffer)
+ (void) fflush(stdout);
+ }
+ }
+
+#if HAVE_MCHECK_H && HAVE_MTRACE
+ /*@-noeffect@*/
+ muntrace(); /* Trace malloc only if MALLOC_TRACE=mtrace-output-file. */
+ /*@=noeffect@*/
+#endif
+
+ return 0;
+}
+/*@=bounds@*/
--- /dev/null
+/*
+ * file.h - definitions for file(1) program
+ * @(#)Id: file.h,v 1.43 2002/07/03 18:57:52 christos Exp
+ *
+ * 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.
+ */
+
+#ifndef __file_h__
+#define __file_h__
+
+/*@-redef@*/
+
+#ifndef HOWMANY
+# define HOWMANY 65536 /* how much of the file to look at */
+#endif
+#define MAXMAGIS 4096 /* max entries in /etc/magic */
+#define MAXDESC 50 /* max leng of text description */
+#define MAXstring 32 /* max leng of "string" types */
+
+#define MAGICNO 0xF11E041C
+#define VERSIONNO 1
+
+#define CHECK 1
+#define COMPILE 2
+
+struct magic {
+ uint16_t cont_level; /* level of ">" */
+ uint8_t nospflag; /* supress space character */
+ uint8_t flag;
+#define INDIR 1 /* if '>(...)' appears, */
+#define UNSIGNED 2 /* comparison is unsigned */
+#define OFFADD 4 /* if '>&' appears, */
+ uint8_t reln; /* relation (0=eq, '>'=gt, etc) */
+ uint8_t vallen; /* length of string value, if any */
+ uint8_t type; /* int, short, long or string. */
+ uint8_t in_type; /* type of indirrection */
+#define BYTE 1
+#define SHORT 2
+#define LONG 4
+#define STRING 5
+#define DATE 6
+#define BESHORT 7
+#define BELONG 8
+#define BEDATE 9
+#define LESHORT 10
+#define LELONG 11
+#define LEDATE 12
+#define PSTRING 13
+#define LDATE 14
+#define BELDATE 15
+#define LELDATE 16
+#define REGEX 17
+ uint8_t in_op; /* operator for indirection */
+ uint8_t mask_op; /* operator for mask */
+#define OPAND 1
+#define OPOR 2
+#define OPXOR 3
+#define OPADD 4
+#define OPMINUS 5
+#define OPMULTIPLY 6
+#define OPDIVIDE 7
+#define OPMODULO 8
+#define OPINVERSE 0x80
+ int32_t offset; /* offset to magic number */
+ int32_t in_offset; /* offset from indirection */
+ union VALUETYPE {
+ uint8_t b;
+ uint16_t h;
+ uint32_t l;
+ char s[MAXstring];
+ const char * buf;
+ uint8_t hs[2]; /* 2 bytes of a fixed-endian "short" */
+ uint8_t hl[4]; /* 4 bytes of a fixed-endian "long" */
+ } value; /* either number or string */
+ uint32_t mask; /* mask before comparison with value */
+ char desc[MAXDESC]; /* description */
+} __attribute__((__packed__));
+
+#define BIT(A) (1 << (A))
+#define STRING_IGNORE_LOWERCASE BIT(0)
+#define STRING_COMPACT_BLANK BIT(1)
+#define STRING_COMPACT_OPTIONAL_BLANK BIT(2)
+#define CHAR_IGNORE_LOWERCASE 'c'
+#define CHAR_COMPACT_BLANK 'B'
+#define CHAR_COMPACT_OPTIONAL_BLANK 'b'
+
+
+/* list of magic entries */
+struct mlist {
+ struct magic *magic; /* array of magic entries */
+ uint32_t nmagic; /* number of entries in array */
+/*@relnull@*/
+ struct mlist *next;
+/*@relnull@*/
+ struct mlist *prev;
+};
+
+enum fmagicFlags_e {
+/*@-enummemuse@*/
+ FMAGIC_FLAGS_NONE = 0,
+/*@=enummemuse@*/
+ FMAGIC_FLAGS_DEBUG = (1 << 0),
+ FMAGIC_FLAGS_BRIEF = (1 << 1), /*!< brief output format */
+ FMAGIC_FLAGS_MIME = (1 << 2), /*!< output as mime-types */
+ FMAGIC_FLAGS_CONTINUE = (1 << 3), /*!< continue after 1st match */
+ FMAGIC_FLAGS_FOLLOW = (1 << 4), /*!< follow symlinks? */
+ FMAGIC_FLAGS_SPECIAL = (1 << 5), /*!< analyze block devices? */
+ FMAGIC_FLAGS_UNCOMPRESS = (1 << 6) /*!< uncompress files? */
+};
+
+struct fmagic_s {
+ int flags; /*!< bit(s) to control fmagic behavior. */
+/*@dependent@*/ /*@observer@*/ /*@relnull@*/
+ const char *magicfile; /*!< name of the magic file */
+ int lineno; /*!< current line number in magic file */
+/*@relnull@*/
+ struct mlist * mlist; /*!< list of arrays of magic entries */
+/*@relnull@*/
+ struct mlist * ml; /*!< current magic array item */
+/*@observer@*/
+ const char * fn; /*!< current file name */
+ int fd; /*!< current file descriptor */
+ struct stat sb; /*!< current file stat(2) buffer */
+/*@relnull@*/
+ unsigned char * buf; /*!< current file buffer */
+ int nb; /*!< current no. bytes in file buffer */
+ union VALUETYPE val; /*!< current magic expression value */
+ int cls; /*!< Elf class */
+ int swap; /*!< Elf swap bytes? */
+/*@dependent@*/
+ char * obp; /*!< current output buffer pointer */
+ size_t nob; /*!< bytes remaining in output buffer */
+ char obuf[512]; /*!< output buffer */
+};
+
+typedef /*@abstract@*/ struct fmagic_s * fmagic;
+
+/*@unchecked@*/
+extern fmagic global_fmagic;
+
+/*@unchecked@*//*@observer@*/
+extern const char * default_magicfile;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*@mayexit@*/
+extern int fmagicSetup(fmagic fm, const char *fn, int action)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fm, fileSystem, internalState @*/;
+extern int fmagicProcess(fmagic fm, const char *fn, int wid)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fm, fileSystem, internalState @*/;
+
+extern int fmagicA(fmagic fm)
+ /*@modifies fm @*/;
+extern int fmagicD(fmagic fm)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fm, fileSystem, internalState @*/;
+extern void fmagicE(fmagic fm)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fm, fileSystem, internalState @*/;
+extern int fmagicF(fmagic fm, int zfl)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fm, fileSystem, internalState @*/;
+extern int fmagicS(fmagic fm)
+ /*@globals fileSystem @*/
+ /*@modifies fm, fileSystem @*/;
+extern int fmagicZ(fmagic fm)
+ /*@globals fileSystem, internalState @*/
+ /*@modifies fm, fileSystem, internalState @*/;
+
+extern void fmagicPrintf(const fmagic fm, const char *f, ...)
+ /*@modifies fm @*/;
+
+/*@observer@*/
+extern char *fmttime(long v, int local)
+ /*@*/;
+
+extern void magwarn(const char *f, ...)
+ /*@globals fileSystem @*/
+ /*@modifies fileSystem @*/;
+extern void mdump(struct magic *m)
+ /*@globals fileSystem @*/
+ /*@modifies fileSystem @*/;
+extern void showstr(FILE *fp, const char *s, int len)
+ /*@globals fileSystem @*/
+ /*@modifies fp, fileSystem @*/;
+
+extern uint32_t signextend(struct magic *m, uint32_t v)
+ /*@globals fileSystem @*/
+ /*@modifies fileSystem @*/;
+extern int pipe2file(int fd, void *startbuf, size_t nbytes)
+ /*@globals errno, fileSystem, internalState @*/
+ /*@modifies errno, fileSystem, internalState @*/;
+
+#ifdef __cplusplus
+}
+#endif
+
+/*@=redef@*/
+#endif /* __file_h__ */
--- /dev/null
+/*
+ * fsmagic - magic based on filesystem info - directory, special files, etc.
+ *
+ * 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 "system.h"
+#include "file.h"
+#include "debug.h"
+
+FILE_RCSID("@(#)Id: fsmagic.c,v 1.36 2002/07/03 19:00:41 christos Exp ")
+
+/*@access fmagic @*/
+
+/*@-bounds@*/
+int
+fmagicD(fmagic fm)
+{
+ const char * fn = fm->fn;
+ struct stat * st = &fm->sb;
+ int ret = 0;
+ int xx;
+
+ /*
+ * Fstat is cheaper but fails for files you don't have read perms on.
+ * On 4.2BSD and similar systems, use lstat() to identify symlinks.
+ */
+#if defined(S_IFLNK) || defined(__LCLINT__)
+ if (!(fm->flags & FMAGIC_FLAGS_FOLLOW))
+ ret = lstat(fn, st);
+ else
+#endif
+ ret = stat(fn, st); /* don't merge into if; see "ret =" above */
+
+ if (ret) {
+ /* Yes, I do mean stdout. */
+ /* No \n, caller will provide. */
+ fmagicPrintf(fm, "can't stat `%s' (%s).", fn, strerror(errno));
+ return 1;
+ }
+
+ if ((fm->flags & FMAGIC_FLAGS_MIME)) {
+ if ((st->st_mode & S_IFMT) != S_IFREG) {
+ fmagicPrintf(fm, "application/x-not-regular-file");
+ return 1;
+ }
+ }
+ else {
+#if defined(S_ISUID) || defined(__LCLINT__)
+ if (st->st_mode & S_ISUID) fmagicPrintf(fm, "setuid ");
+#endif
+#if defined(S_ISGID) || defined(__LCLINT__)
+ if (st->st_mode & S_ISGID) fmagicPrintf(fm, "setgid ");
+#endif
+#if defined(S_ISVTX) || defined(__LCLINT__)
+ if (st->st_mode & S_ISVTX) fmagicPrintf(fm, "sticky ");
+#endif
+ }
+
+ switch (st->st_mode & S_IFMT) {
+ case S_IFDIR:
+ fmagicPrintf(fm, "directory");
+ return 1;
+#if defined(S_IFCHR) || defined(__LCLINT__)
+ case S_IFCHR:
+ /*
+ * If -s has been specified, treat character special files
+ * like ordinary files. Otherwise, just report that they
+ * are block special files and go on to the next file.
+ */
+ if ((fm->flags & FMAGIC_FLAGS_SPECIAL))
+ break;
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+# ifdef dv_unit
+ fmagicPrintf(fm, "character special (%d/%d/%d)",
+ major(st->st_rdev),
+ dv_unit(st->st_rdev),
+ dv_subunit(st->st_rdev));
+# else
+/*@-shiftimplementation@*/
+ fmagicPrintf(fm, "character special (%ld/%ld)",
+ (long) major(st->st_rdev), (long) minor(st->st_rdev));
+/*@=shiftimplementation@*/
+# endif
+#else
+ fmagicPrintf(fm, "character special");
+#endif
+ return 1;
+#endif
+#if defined(S_IFBLK) || defined(__LCLINT__)
+ case S_IFBLK:
+ /*
+ * If -s has been specified, treat block special files
+ * like ordinary files. Otherwise, just report that they
+ * are block special files and go on to the next file.
+ */
+ if ((fm->flags & FMAGIC_FLAGS_SPECIAL))
+ break;
+#ifdef HAVE_STRUCT_STAT_ST_RDEV
+# ifdef dv_unit
+ fmagicPrintf(fm, "block special (%d/%d/%d)",
+ major(st->st_rdev),
+ dv_unit(st->st_rdev),
+ dv_subunit(st->st_rdev));
+# else
+/*@-shiftimplementation@*/
+ fmagicPrintf(fm, "block special (%ld/%ld)",
+ (long) major(st->st_rdev), (long) minor(st->st_rdev));
+/*@=shiftimplementation@*/
+# endif
+#else
+ fmagicPrintf(fm, "block special");
+#endif
+ return 1;
+#endif
+ /* TODO add code to handle V7 MUX and Blit MUX files */
+#if defined(S_IFIFO) || defined(__LCLINT__)
+ case S_IFIFO:
+ fmagicPrintf(fm, "fifo (named pipe)");
+ return 1;
+#endif
+#if defined(S_IFDOOR)
+ case S_IFDOOR:
+ fmagicPrintf(fm, "door");
+ return 1;
+#endif
+#if defined(S_IFLNK) || defined(__LCLINT__)
+ case S_IFLNK:
+ {
+ char buf[BUFSIZ+4];
+ int nch;
+ struct stat tstatbuf;
+
+ buf[0] = '\0';
+ if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
+ fmagicPrintf(fm, "unreadable symlink (%s).", strerror(errno));
+ return 1;
+ }
+ buf[nch] = '\0'; /* readlink(2) needs this */
+
+ /* If broken symlink, say so and quit early. */
+/*@-branchstate@*/
+ if (*buf == '/') {
+ if (stat(buf, &tstatbuf) < 0) {
+ fmagicPrintf(fm, "broken symbolic link to %s", buf);
+ return 1;
+ }
+ }
+ else {
+ char *tmp;
+ char buf2[BUFSIZ+BUFSIZ+4];
+
+ if ((tmp = strrchr(fn, '/')) == NULL) {
+ tmp = buf; /* in current directory anyway */
+ }
+ else {
+ strcpy (buf2, fn); /* take directory part */
+ buf2[tmp-fn+1] = '\0';
+ strcat (buf2, buf); /* plus (relative) symlink */
+ tmp = buf2;
+ }
+ if (stat(tmp, &tstatbuf) < 0) {
+ fmagicPrintf(fm, "broken symbolic link to %s", buf);
+ return 1;
+ }
+ }
+/*@=branchstate@*/
+
+ /* Otherwise, handle it. */
+ if ((fm->flags & FMAGIC_FLAGS_FOLLOW)) {
+ fmagicPrintf(fm, "\n");
+ xx = fmagicProcess(fm, buf, strlen(buf));
+ return 1;
+ } else { /* just print what it points to */
+ fmagicPrintf(fm, "symbolic link to %s", buf);
+ }
+ }
+ return 1;
+#endif
+#if defined(S_IFSOCK)
+#ifndef __COHERENT__
+ case S_IFSOCK:
+ fmagicPrintf(fm, "socket");
+ return 1;
+#endif
+#endif
+ case S_IFREG:
+ break;
+ default:
+ error(EXIT_FAILURE, 0, "invalid mode 0%o.\n", st->st_mode);
+ /*@notreached@*/
+ }
+
+ /*
+ * regular file, check next possibility
+ *
+ * If stat() tells us the file has zero length, report here that
+ * the file is empty, so we can skip all the work of opening and
+ * reading the file.
+ * But if the -s option has been given, we skip this optimization,
+ * since on some systems, stat() reports zero size for raw disk
+ * partitions. (If the block special device really has zero length,
+ * the fact that it is empty will be detected and reported correctly
+ * when we read the file.)
+ */
+ if (!(fm->flags & FMAGIC_FLAGS_SPECIAL) && st->st_size == 0) {
+ fmagicPrintf(fm, ((fm->flags & FMAGIC_FLAGS_MIME)
+ ? "application/x-empty" : "empty"));
+ return 1;
+ }
+ return 0;
+}
+/*@=bounds@*/
+
+int
+fmagicF(fmagic fm, int zfl)
+{
+ /*
+ * The main work is done here!
+ * We have the file name and/or the data buffer to be identified.
+ */
+
+#ifdef __EMX__
+ /*
+ * Ok, here's the right place to add a call to some os-specific
+ * routine, e.g.
+ */
+ if (os2_apptype(fn, buf, nb) == 1)
+ return 'o';
+#endif
+ /* try compression stuff */
+ if (zfl && fmagicZ(fm))
+ return 'z';
+
+ /* try tests in /etc/magic (or surrogate magic file) */
+ if (fmagicS(fm))
+ return 's';
+
+ /* try known keywords, check whether it is ASCII */
+ if (fmagicA(fm))
+ return 'a';
+
+ /* abandon hope, all ye who remain here */
+ fmagicPrintf(fm, ((fm->flags & FMAGIC_FLAGS_MIME)
+ ? "application/octet-stream" : "data"));
+ return '\0';
+}
+
+/*
+ * fmagicProcess - process input file
+ */
+/*@-bounds@*/
+int
+fmagicProcess(fmagic fm, const char *fn, int wid)
+{
+ static const char stdname[] = "standard input";
+ char match = '\0';
+ int ret = 0;
+
+/*@-assignexpose -temptrans @*/
+ fm->fn = fn;
+/*@=assignexpose =temptrans @*/
+ fm->buf = xmalloc(HOWMANY+1);
+ fm->buf[0] = '\0';
+ fm->nb = 0;
+
+/*@-branchstate@*/
+ if (strcmp("-", fn) == 0) {
+ if (fstat(0, &fm->sb)<0) {
+ error(EXIT_FAILURE, 0, "cannot fstat `%s' (%s).\n", stdname,
+ strerror(errno));
+ /*@notreached@*/
+ }
+ fm->fn = stdname;
+ }
+/*@=branchstate@*/
+
+ if (wid > 0 && !(fm->flags & FMAGIC_FLAGS_BRIEF))
+ fmagicPrintf(fm, "%s:%*s ", fm->fn,
+ (int) (wid - strlen(fm->fn)), "");
+
+ if (fm->fn != stdname) {
+ /*
+ * first try judging the file based on its filesystem status
+ */
+ if (fmagicD(fm) != 0)
+ goto exit;
+
+ if ((fm->fd = open(fm->fn, O_RDONLY)) < 0) {
+ /* We can't open it, but we were able to stat it. */
+ if (fm->sb.st_mode & 0002)
+ fmagicPrintf(fm, "writeable, ");
+ if (fm->sb.st_mode & 0111)
+ fmagicPrintf(fm, "executable, ");
+ fmagicPrintf(fm, "can't read `%s' (%s).", fm->fn, strerror(errno));
+ goto exit;
+ }
+ }
+
+
+ /*
+ * try looking at the first HOWMANY bytes
+ */
+ if ((fm->nb = read(fm->fd, (char *)fm->buf, HOWMANY)) == -1) {
+ error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+
+ if (fm->nb == 0)
+ fmagicPrintf(fm, ((fm->flags & FMAGIC_FLAGS_MIME)
+ ? "application/x-empty" : "empty"), fm);
+ else {
+ fm->buf[fm->nb++] = '\0'; /* null-terminate data buffer */
+ match = fmagicF(fm, (fm->flags & FMAGIC_FLAGS_UNCOMPRESS));
+ }
+
+#ifdef BUILTIN_ELF
+ if (match == 's' && fm->nb > 5) {
+ /*
+ * We matched something in the file, so this *might*
+ * be an ELF file, and the file is at least 5 bytes long,
+ * so if it's an ELF file it has at least one byte
+ * past the ELF magic number - try extracting information
+ * from the ELF headers that can't easily be extracted
+ * with rules in the magic file.
+ */
+ fmagicE(fm);
+ }
+#endif
+
+ if (fm->fn != stdname) {
+#ifdef RESTORE_TIME
+ /*
+ * Try to restore access, modification times if read it.
+ * This is really *bad* because it will modify the status
+ * time of the file... And of course this will affect
+ * backup programs
+ */
+# ifdef USE_UTIMES
+ struct timeval utsbuf[2];
+ utsbuf[0].tv_sec = fm->sb.st_atime;
+ utsbuf[1].tv_sec = fm->sb.st_mtime;
+
+ (void) utimes(fm->fn, utsbuf); /* don't care if loses */
+# else
+ struct utimbuf utbuf;
+
+ utbuf.actime = fm->sb.st_atime;
+ utbuf.modtime = fm->sb.st_mtime;
+ (void) utime(fm->fn, &utbuf); /* don't care if loses */
+# endif
+#endif
+ (void) close(fm->fd);
+ fm->fd = -1;
+ }
+
+exit:
+ if (fm->buf != NULL)
+ free(fm->buf);
+ fm->buf = NULL;
+ fm->nb = 0;
+ return ret;
+}
+/*@=bounds@*/
--- /dev/null
+/*
+ * Names.h - names and types used by ascmagic in file(1).
+ * These tokens are here because they can appear anywhere in
+ * the first HOWMANY bytes, while tokens in MAGIC must
+ * appear at fixed offsets into the file. Don't make HOWMANY
+ * too high unless you have a very fast CPU.
+ *
+ * Copyright (c) Ian F. Darwin, 1987.
+ * Written by Ian F. Darwin.
+ *
+ * See LEGAL.NOTICE
+ *
+ * Id: names.h,v 1.19 2002/05/16 15:01:41 christos Exp
+ */
+
+/*
+ modified by Chris Lowth - 9 April 2000
+ to add mime type strings to the types table.
+*/
+
+/* these types are used to index the table 'types': keep em in sync! */
+#define L_C 0 /* first and foremost on UNIX */
+#define L_CC 1 /* Bjarne's postincrement */
+#define L_FORT 2 /* the oldest one */
+#define L_MAKE 3 /* Makefiles */
+#define L_PLI 4 /* PL/1 */
+#define L_MACH 5 /* some kinda assembler */
+#define L_ENG 6 /* English */
+#define L_PAS 7 /* Pascal */
+#define L_MAIL 8 /* Electronic mail */
+#define L_NEWS 9 /* Usenet Netnews */
+#define L_JAVA 10 /* Java code */
+#define L_HTML 11 /* HTML */
+#define L_BCPL 12 /* BCPL */
+#define L_M4 13 /* M4 */
+
+/*@unchecked@*/ /*@unused@*/ /*@observer@*/
+static const struct {
+/*@observer@*/ /*@null@*/
+ char *human;
+/*@observer@*/ /*@null@*/
+ char *mime;
+} types[] = {
+ { "C program", "text/x-c", },
+ { "C++ program", "text/x-c++" },
+ { "FORTRAN program", "text/x-fortran" },
+ { "make commands", "text/x-makefile" },
+ { "PL/1 program", "text/x-pl1" },
+ { "assembler program", "text/x-asm" },
+ { "English", "text/plain, English" },
+ { "Pascal program", "text/x-pascal" },
+ { "mail", "text/x-mail" },
+ { "news", "text/x-news" },
+ { "Java program", "text/x-java" },
+ { "HTML document", "text/html", },
+ { "BCPL program", "text/x-bcpl" },
+ { "M4 macro language pre-processor", "text/x-m4" },
+ { "can't happen error on names.h/types", "error/x-error" },
+ { 0, 0}
+};
+
+/*
+ * XXX - how should we distinguish Java from C++?
+ * The trick used in a Debian snapshot, of having "extends" or "implements"
+ * as tags for Java, doesn't work very well, given that those keywords
+ * are often preceded by "class", which flags it as C++.
+ *
+ * Perhaps we need to be able to say
+ *
+ * If "class" then
+ *
+ * if "extends" or "implements" then
+ * Java
+ * else
+ * C++
+ * endif
+ *
+ * Or should we use other keywords, such as "package" or "import"?
+ * Unfortunately, Ada95 uses "package", and Modula-3 uses "import",
+ * although I infer from the language spec at
+ *
+ * http://www.research.digital.com/SRC/m3defn/html/m3.html
+ *
+ * that Modula-3 uses "IMPORT" rather than "import", i.e. it must be
+ * in all caps.
+ *
+ * So, for now, we go with "import". We must put it before the C++
+ * stuff, so that we don't misidentify Java as C++. Not using "package"
+ * means we won't identify stuff that defines a package but imports
+ * nothing; hopefully, very little Java code imports nothing (one of the
+ * reasons for doing OO programming is to import as much as possible
+ * and write only what you need to, right?).
+ *
+ * Unfortunately, "import" may cause us to misidentify English text
+ * as Java, as it comes after "the" and "The". Perhaps we need a fancier
+ * heuristic to identify Java?
+ */
+/*@unchecked@*/ /*@unused@*/ /*@observer@*/
+static struct names {
+/*@observer@*/ /*@null@*/
+ const char *name;
+ short type;
+} names[] = {
+ /* These must be sorted by eye for optimal hit rate */
+ /* Add to this list only after substantial meditation */
+ {"dnl", L_M4},
+ {"import", L_JAVA},
+ {"\"libhdr\"", L_BCPL},
+ {"\"LIBHDR\"", L_BCPL},
+ {"//", L_CC},
+ {"template", L_CC},
+ {"virtual", L_CC},
+ {"class", L_CC},
+ {"public:", L_CC},
+ {"private:", L_CC},
+ {"/*", L_C}, /* must precede "The", "the", etc. */
+ {"#include", L_C},
+ {"char", L_C},
+ {"The", L_ENG},
+ {"the", L_ENG},
+ {"double", L_C},
+ {"extern", L_C},
+ {"float", L_C},
+ {"struct", L_C},
+ {"union", L_C},
+ {"CFLAGS", L_MAKE},
+ {"LDFLAGS", L_MAKE},
+ {"all:", L_MAKE},
+ {".PRECIOUS", L_MAKE},
+/* Too many files of text have these words in them. Find another way
+ * to recognize Fortrash.
+ */
+#ifdef NOTDEF
+ {"subroutine", L_FORT},
+ {"function", L_FORT},
+ {"block", L_FORT},
+ {"common", L_FORT},
+ {"dimension", L_FORT},
+ {"integer", L_FORT},
+ {"data", L_FORT},
+#endif /*NOTDEF*/
+ {".ascii", L_MACH},
+ {".asciiz", L_MACH},
+ {".byte", L_MACH},
+ {".even", L_MACH},
+ {".globl", L_MACH},
+ {".text", L_MACH},
+ {"clr", L_MACH},
+ {"(input,", L_PAS},
+ {"dcl", L_PLI},
+ {"Received:", L_MAIL},
+ {">From", L_MAIL},
+ {"Return-Path:",L_MAIL},
+ {"Cc:", L_MAIL},
+ {"Newsgroups:", L_NEWS},
+ {"Path:", L_NEWS},
+ {"Organization:",L_NEWS},
+ {"href=", L_HTML},
+ {"HREF=", L_HTML},
+ {"<body", L_HTML},
+ {"<BODY", L_HTML},
+ {NULL, 0}
+};
+#define NNAMES ((sizeof(names)/sizeof(struct names)) - 1)
--- /dev/null
+#define FILE_VERSION_MAJOR 3
+#define patchlevel 39
+
+/*
+ * Patchlevel file for Ian Darwin's MAGIC command.
+ * Id: patchlevel.h,v 1.39 2002/07/03 18:57:52 christos Exp
+ *
+ * Log: patchlevel.h,v
+ * Revision 1.39 2002/07/03 18:57:52 christos
+ * - ansify/c99ize
+ * - more magic
+ * - better COMPILE_ONLY support.
+ * - new magic files.
+ * - fix solaris compilation problems.
+ *
+ * Revision 1.38 2002/05/16 18:45:56 christos
+ * - pt_note elf additions from NetBSD
+ * - EMX os specific changes (Alexander Mai)
+ * - stdint.h detection, acconfig.h fixes (Maciej W. Rozycki, Franz Korntner)
+ * - regex file additions (Kim Cromie)
+ * - getopt_long support and misc cleanups (Michael Piefel)
+ * - many magic fixes and additions
+ *
+ * Revision 1.37 2001/09/03 14:44:22 christos
+ * daylight/tm_isdst detection
+ * magic fixes
+ * don't eat the whole file if it has only nulls
+ *
+ * Revision 1.36 2001/07/22 21:04:15 christos
+ * - magic fixes
+ * - add new operators, pascal strings, UTC date printing, $HOME/.magic
+ * [from "Tom N Harris" <telliamed@mac.com>]
+ *
+ * Revision 1.35 2001/04/24 14:40:25 christos
+ * - rename magic file sgi to mips and fix it
+ * - add support for building magic.mgc
+ * - portability fixes for mmap()
+ * - try gzip before uncompress, because uncompress sometimes hangs
+ * - be more conservative about pipe reads and writes
+ * - many magic fixes
+ *
+ * Revision 1.34 2001/03/12 05:05:57 christos
+ * - new compiled magic format
+ * - lots of magic additions
+ *
+ * Revision 1.33 2000/11/13 00:30:50 christos
+ * - wordperfect magic fix: freebsd pr 9388
+ * - more msdos fixes from freebsd pr's 20131 and 20812
+ * - sas and spss magic [Bruce Foster]
+ * - mkinstalldirs [John Fremlin]
+ * - sgi opengl fixes [Michael Pruett]
+ * - netbsd magic fixes [Ignatios Souvatzis]
+ * - audio additions [Michael Pruett]
+ * - fix problem with non ansi RCSID [Andreas Ley]
+ * - oggs magic [Felix von Leitner]
+ * - gmon magic [Eugen Dedu]
+ * - TNEF magic [Joomy]
+ * - netpbm magic and misc other image stuff [Bryan Henderson]
+ *
+ * Revision 1.32 2000/08/05 18:24:18 christos
+ * Correct indianness detection in elf (Charles Hannum)
+ * FreeBSD elf core support (Guy Harris)
+ * Use gzip in systems that don't have uncompress (Anthon van der Neut)
+ * Internationalization/EBCDIC support (Eric Fisher)
+ * Many many magic changes
+ *
+ * Revision 1.31 2000/05/14 17:58:36 christos
+ * - new magic for claris files
+ * - new magic for mathematica and maple files
+ * - new magic for msvc files
+ * - new -k flag to keep going matching all possible entries
+ * - add the word executable on #! magic files, and fix the usage of
+ * the word script
+ * - lots of other magic fixes
+ * - fix typo test -> text
+ *
+ * Revision 1.30 2000/04/11 02:41:17 christos
+ * - add support for mime output (-i)
+ * - make sure we free memory in case realloc fails
+ * - magic fixes
+ *
+ * Revision 1.29 1999/11/28 20:02:29 christos
+ * new string/[Bcb] magic from anthon, and adjustments to the magic files to
+ * use it.
+ *
+ * Revision 1.28 1999/10/31 22:11:48 christos
+ * - add "char" type for compatibility with HP/UX
+ * - recognize HP/UX syntax &=n etc.
+ * - include errno.h for CYGWIN
+ * - conditionalize the S_IS* macros
+ * - revert the SHT_DYNSYM test that broke the linux stripped binaries test
+ * - lots of Magdir changes
+ *
+ * Revision 1.27 1999/02/14 17:21:41 christos
+ * Automake support and misc cleanups from Rainer Orth
+ * Enable reading character and block special files from Dale R. Worley
+ *
+ * Revision 1.26 1998/09/12 13:19:39 christos
+ * - add support for bi-endian indirect offsets (Richard Verhoeven)
+ * - add recognition for bcpl (Joseph Myers)
+ * - remove non magic files from Magdir to avoid difficulties building
+ * on os2 where files are case independent
+ * - magic fixes.
+ *
+ * Revision 1.25 1998/06/27 14:04:04 christos
+ * OLF patch Guy Harris
+ * Recognize java/html (debian linux)
+ * Const poisoning (debian linux)
+ * More magic!
+ *
+ * Revision 1.24 1998/02/15 23:20:38 christos
+ * Autoconf patch: Felix von Leitner <leitner@math.fu-berlin.de>
+ * More magic fixes
+ * Elf64 fixes
+ *
+ * Revision 1.23 1997/11/05 16:03:37 christos
+ * - correct elf prps offset for SunOS-2.5.1 [guy@netapp.com]
+ * - handle 64 bit time_t's correctly [ewt@redhat.com]
+ * - new mime style magic [clarosse@netvista.net]
+ * - new TI calculator magic [rmcguire@freenet.columbus.oh.us]
+ * - new figlet fonts [obrien@freebsd.org]
+ * - new cisco magic, and elf fixes [jhawk@bbnplanet.com]
+ * - -b flag addition, and x86 filesystem magic [vax@linkhead.paranoia.com]
+ * - s/Mpeg/MPEG, header and elf typo fixes [guy@netapp.com]
+ * - Windows/NT registry files, audio code [guy@netapp.com]
+ * - libGrx graphics lib fonts [guy@netapp.com]
+ * - PNG fixes [guy@netapp.com]
+ * - more m$ document magic [guy@netapp.com]
+ * - PPD files [guy@netapp.com]
+ * - archive magic cleanup [guy@netapp.com]
+ * - linux kernel magic cleanup [guy@netapp.com]
+ * - lecter magic [guy@netapp.com]
+ * - vgetty magic [guy@netapp.com]
+ * - sniffer additions [guy@netapp.com]
+ *
+ * Revision 1.22 1997/01/15 17:23:24 christos
+ * - add support for elf core files: find the program name under SVR4 [Ken Pizzini]
+ * - print strings only up to the first carriage return [various]
+ * - freebsd international ascii support [J Wunsch]
+ * - magic fixes and additions [Guy Harris]
+ * - 64 bit fixes [Larry Schwimmer]
+ * - support for both utime and utimes, but don't restore file access times
+ * by default [various]
+ * - \xXX only takes 2 hex digits, not 3.
+ * - re-implement support for core files [Guy Harris]
+ *
+ * Revision 1.21 1996/10/05 18:15:29 christos
+ * Segregate elf stuff and conditionally enable it with -DBUILTIN_ELF
+ * More magic fixes
+ *
+ * Revision 1.20 1996/06/22 22:15:52 christos
+ * - support relative offsets of the form >&
+ * - fix bug with truncating magic strings that contain \n
+ * - file -f - did not read from stdin as documented
+ * - support elf file parsing using our own elf support.
+ * - as always magdir fixes and additions.
+ *
+ * Revision 1.19 1995/10/27 23:14:46 christos
+ * Ability to parse colon separated list of magic files
+ * New LEGAL.NOTICE
+ * Various magic file changes
+ *
+ * Revision 1.18 1995/05/20 22:09:21 christos
+ * Passed incorrect argument to eatsize().
+ * Use %ld and %lx where appropriate.
+ * Remove unused variables
+ * ELF support for both big and little endian
+ * Fixes for small files again.
+ *
+ * Revision 1.17 1995/04/28 17:29:13 christos
+ * - Incorrect nroff detection fix from der Mouse
+ * - Lost and incorrect magic entries.
+ * - Added ELF stripped binary detection [in C; ugh]
+ * - Look for $MAGIC to find the magic file.
+ * - Eat trailing size specifications from numbers i.e. ignore 10L
+ * - More fixes for very short files
+ *
+ * Revision 1.16 1995/03/25 22:06:45 christos
+ * - use strtoul() where it exists.
+ * - fix sign-extend bug
+ * - try to detect tar archives before nroff files, otherwise
+ * tar files where the first file starts with a . will not work
+ *
+ * Revision 1.15 1995/01/21 21:03:35 christos
+ * Added CSECTION for the file man page
+ * Added version flag -v
+ * Fixed bug with -f input flag (from iorio@violet.berkeley.edu)
+ * Lots of magic fixes and reorganization...
+ *
+ * Revision 1.14 1994/05/03 17:58:23 christos
+ * changes from mycroft@gnu.ai.mit.edu (Charles Hannum) for unsigned
+ *
+ * Revision 1.13 1994/01/21 01:27:01 christos
+ * Fixed null termination bug from Don Seeley at BSDI in ascmagic.c
+ *
+ * Revision 1.12 1993/10/27 20:59:05 christos
+ * Changed -z flag to understand gzip format too.
+ * Moved builtin compression detection to a table, and move
+ * the compress magic entry out of the source.
+ * Made printing of numbers unsigned, and added the mask to it.
+ * Changed the buffer size to 8k, because gzip will refuse to
+ * unzip just a few bytes.
+ *
+ * Revision 1.11 1993/09/24 18:49:06 christos
+ * Fixed small bug in softmagic.c introduced by
+ * copying the data to be examined out of the input
+ * buffer. Changed the Makefile to use sed to create
+ * the correct man pages.
+ *
+ * Revision 1.10 1993/09/23 21:56:23 christos
+ * Passed purify. Fixed indirections. Fixed byte order printing.
+ * Fixed segmentation faults caused by referencing past the end
+ * of the magic buffer. Fixed bus errors caused by referencing
+ * unaligned shorts or longs.
+ *
+ * Revision 1.9 1993/03/24 14:23:40 ian
+ * Batch of minor changes from several contributors.
+ *
+ * Revision 1.8 93/02/19 15:01:26 ian
+ * Numerous changes from Guy Harris too numerous to mention but including
+ * byte-order independance, fixing "old-style masking", etc. etc. A bugfix
+ * for broken symlinks from martin@@d255s004.zfe.siemens.de.
+ *
+ * Revision 1.7 93/01/05 14:57:27 ian
+ * Couple of nits picked by Christos (again, thanks).
+ *
+ * Revision 1.6 93/01/05 13:51:09 ian
+ * Lotsa work on the Magic directory.
+ *
+ * Revision 1.5 92/09/14 14:54:51 ian
+ * Fix a tiny null-pointer bug in previous fix for tar archive + uncompress.
+ *
+ */
+
--- /dev/null
+/*
+ * print.c - debugging printout routines
+ *
+ * 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 "system.h"
+#include "file.h"
+#include "debug.h"
+
+FILE_RCSID("@(#)Id: print.c,v 1.38 2002/07/03 18:37:44 christos Exp ")
+
+/*@access fmagic @*/
+
+/*@-compmempass@*/
+/*@unchecked@*/
+static struct fmagic_s myfmagic;
+/*@unchecked@*/
+fmagic global_fmagic = &myfmagic;
+/*@=compmempass@*/
+
+#define SZOF(a) (sizeof(a) / sizeof(a[0]))
+
+#ifndef COMPILE_ONLY
+void
+mdump(struct magic *m)
+{
+ /*@observer@*/
+ static const char *typ[] = { "invalid", "byte", "short", "invalid",
+ "long", "string", "date", "beshort",
+ "belong", "bedate", "leshort", "lelong",
+ "ledate", "pstring", "ldate", "beldate",
+ "leldate", "regex" };
+ static const char optyp[] = { '@', '&', '|', '^', '+', '-',
+ '*', '/', '%' };
+ (void) fputc('[', stderr);
+/*@-formatconst@*/
+ (void) fprintf(stderr, ">>>>>>>> %d" + 8 - (m->cont_level & 7),
+ m->offset);
+/*@=formatconst@*/
+
+ if (m->flag & INDIR) {
+ (void) fprintf(stderr, "(%s,",
+ /* Note: type is unsigned */
+ (m->in_type < SZOF(typ)) ?
+ typ[m->in_type] : "*bad*");
+ if (m->in_op & OPINVERSE)
+ (void) fputc('~', stderr);
+ (void) fprintf(stderr, "%c%d),",
+ ((m->in_op&0x7F) < SZOF(optyp)) ?
+ optyp[m->in_op&0x7F] : '?',
+ m->in_offset);
+ }
+ (void) fprintf(stderr, " %s%s", (m->flag & UNSIGNED) ? "u" : "",
+ /* Note: type is unsigned */
+ (m->type < SZOF(typ)) ? typ[m->type] : "*bad*");
+ if (m->mask_op & OPINVERSE)
+ (void) fputc('~', stderr);
+ if (m->mask) {
+ ((m->mask_op&0x7F) < SZOF(optyp)) ?
+ (void) fputc(optyp[m->mask_op&0x7F], stderr) :
+ (void) fputc('?', stderr);
+ if(STRING != m->type || PSTRING != m->type)
+ (void) fprintf(stderr, "%.8x", m->mask);
+ else {
+ if (m->mask & STRING_IGNORE_LOWERCASE)
+ (void) fputc(CHAR_IGNORE_LOWERCASE, stderr);
+ if (m->mask & STRING_COMPACT_BLANK)
+ (void) fputc(CHAR_COMPACT_BLANK, stderr);
+ if (m->mask & STRING_COMPACT_OPTIONAL_BLANK)
+ (void) fputc(CHAR_COMPACT_OPTIONAL_BLANK,
+ stderr);
+ }
+ }
+
+ (void) fprintf(stderr, ",%c", m->reln);
+
+ if (m->reln != 'x') {
+ switch (m->type) {
+ case BYTE:
+ case SHORT:
+ case LONG:
+ case LESHORT:
+ case LELONG:
+ case BESHORT:
+ case BELONG:
+ (void) fprintf(stderr, "%d", m->value.l);
+ break;
+ case STRING:
+ case PSTRING:
+ case REGEX:
+ showstr(stderr, m->value.s, -1);
+ break;
+ case DATE:
+ case LEDATE:
+ case BEDATE:
+ (void)fprintf(stderr, "%s,", fmttime(m->value.l, 1));
+ break;
+ case LDATE:
+ case LELDATE:
+ case BELDATE:
+ (void)fprintf(stderr, "%s,", fmttime(m->value.l, 0));
+ break;
+ default:
+ (void) fputs("*bad*", stderr);
+ break;
+ }
+ }
+ (void) fprintf(stderr, ",\"%s\"]\n", m->desc);
+}
+#endif
+
+#if !defined(HAVE_ERROR) || defined(__LCLINT__)
+/*
+ * error - print best error message possible and exit
+ */
+/*VARARGS*/
+void
+error(int status, /*@unused@*/ int errnum, const char * format, ...)
+{
+ va_list va;
+
+ va_start(va, format);
+ /* cuz we use stdout for most, stderr here */
+ (void) fflush(stdout);
+
+ if (__progname != NULL)
+ (void) fprintf(stderr, "%s: ", __progname);
+ (void) vfprintf(stderr, format, va);
+ va_end(va);
+#if NOTYET
+ if (status)
+#endif
+ exit(status);
+}
+#endif
+
+/*VARARGS*/
+void
+magwarn(const char *f, ...)
+{
+ fmagic fm = global_fmagic;
+ va_list va;
+
+ va_start(va, f);
+ /* cuz we use stdout for most, stderr here */
+ (void) fflush(stdout);
+
+ if (__progname != NULL)
+ (void) fprintf(stderr, "%s: %s, %d: ",
+ __progname, fm->magicfile, fm->lineno);
+ (void) vfprintf(stderr, f, va);
+ va_end(va);
+ (void) fputc('\n', stderr);
+/*@-globstate@*/ /* FIX: __progname might be null */
+ return;
+/*@=globstate@*/
+}
+
+void
+fmagicPrintf(const fmagic fm, const char *f, ...)
+{
+ va_list va;
+ size_t nob;
+ int rc;
+
+ va_start(va, f);
+/*@-boundswrite@*/
+ rc = vsnprintf(fm->obp, fm->nob, f, va);
+/*@=boundswrite@*/
+ va_end(va);
+
+ fm->obuf[sizeof(fm->obuf)-1] = '\0';
+ nob = strlen(fm->obp);
+ fm->obp += nob;
+ fm->nob -= nob;
+}
+
+
+#ifndef COMPILE_ONLY
+char *
+fmttime(long v, int local)
+{
+ char *pp = "???";
+ char *rt;
+ time_t t = (time_t)v;
+ struct tm *tm;
+
+ if (local) {
+ pp = ctime(&t);
+ } else {
+#ifndef HAVE_DAYLIGHT
+ static int daylight = 0;
+#ifdef HAVE_TM_ISDST
+ static time_t now = (time_t)0;
+
+ if (now == (time_t)0) {
+ struct tm *tm1;
+ (void)time(&now);
+ tm1 = localtime(&now);
+ daylight = tm1->tm_isdst;
+ }
+#endif /* HAVE_TM_ISDST */
+#endif /* HAVE_DAYLIGHT */
+ if (daylight)
+ t += 3600;
+ tm = gmtime(&t);
+ if (tm != NULL)
+ pp = asctime(tm);
+ }
+
+/*@-modobserver@*/
+ if ((rt = strchr(pp, '\n')) != NULL)
+ *rt = '\0';
+/*@=modobserver@*/
+ return pp;
+}
+#endif
--- /dev/null
+#include "system.h"
+
+#ifdef BUILTIN_ELF
+#include "file.h"
+#include "readelf.h"
+#include "debug.h"
+
+FILE_RCSID("@(#)Id: readelf.c,v 1.22 2002/07/03 18:26:38 christos Exp ")
+
+/*@access fmagic @*/
+
+/*@-bounds@*/
+static uint16_t
+getu16(const fmagic fm, uint16_t value)
+ /*@*/
+{
+ union {
+ uint16_t ui;
+ char c[2];
+ } retval, tmpval;
+
+ if (fm->swap) {
+ tmpval.ui = value;
+
+ retval.c[0] = tmpval.c[1];
+ retval.c[1] = tmpval.c[0];
+
+ return retval.ui;
+ } else
+ return value;
+}
+
+static uint32_t
+getu32(const fmagic fm, uint32_t value)
+ /*@*/
+{
+ union {
+ uint32_t ui;
+ char c[4];
+ } retval, tmpval;
+
+ if (fm->swap) {
+ tmpval.ui = value;
+
+ retval.c[0] = tmpval.c[3];
+ retval.c[1] = tmpval.c[2];
+ retval.c[2] = tmpval.c[1];
+ retval.c[3] = tmpval.c[0];
+
+ return retval.ui;
+ } else
+ return value;
+}
+
+static uint64_t
+getu64(const fmagic fm, uint64_t value)
+ /*@*/
+{
+ union {
+ uint64_t ui;
+ char c[8];
+ } retval, tmpval;
+
+ if (fm->swap) {
+ tmpval.ui = value;
+
+ retval.c[0] = tmpval.c[7];
+ retval.c[1] = tmpval.c[6];
+ retval.c[2] = tmpval.c[5];
+ retval.c[3] = tmpval.c[4];
+ retval.c[4] = tmpval.c[3];
+ retval.c[5] = tmpval.c[2];
+ retval.c[6] = tmpval.c[1];
+ retval.c[7] = tmpval.c[0];
+
+ return retval.ui;
+ } else
+ return value;
+}
+/*@=bounds@*/
+
+#define sh_addr (fm->cls == ELFCLASS32 \
+ ? (void *) &sh32 \
+ : (void *) &sh64)
+#define sh_size (fm->cls == ELFCLASS32 \
+ ? sizeof sh32 \
+ : sizeof sh64)
+#define shs_type (fm->cls == ELFCLASS32 \
+ ? getu32(fm, sh32.sh_type) \
+ : getu32(fm, sh64.sh_type))
+#define ph_addr (fm->cls == ELFCLASS32 \
+ ? (void *) &ph32 \
+ : (void *) &ph64)
+#define ph_size (fm->cls == ELFCLASS32 \
+ ? sizeof ph32 \
+ : sizeof ph64)
+#define ph_type (fm->cls == ELFCLASS32 \
+ ? getu32(fm, ph32.p_type) \
+ : getu32(fm, ph64.p_type))
+#define ph_offset (fm->cls == ELFCLASS32 \
+ ? getu32(fm, ph32.p_offset) \
+ : getu64(fm, ph64.p_offset))
+#define ph_align (fm->cls == ELFCLASS32 \
+ ? (ph32.p_align ? getu32(fm, ph32.p_align) : 4) \
+ : (ph64.p_align ? getu64(fm, ph64.p_align) : 4))
+#define nh_size (fm->cls == ELFCLASS32 \
+ ? sizeof *nh32 \
+ : sizeof *nh64)
+#define nh_type (fm->cls == ELFCLASS32 \
+ ? getu32(fm, nh32->n_type) \
+ : getu32(fm, nh64->n_type))
+#define nh_namesz (fm->cls == ELFCLASS32 \
+ ? getu32(fm, nh32->n_namesz) \
+ : getu32(fm, nh64->n_namesz))
+#define nh_descsz (fm->cls == ELFCLASS32 \
+ ? getu32(fm, nh32->n_descsz) \
+ : getu32(fm, nh64->n_descsz))
+#define prpsoffsets(i) (fm->cls == ELFCLASS32 \
+ ? prpsoffsets32[i] \
+ : prpsoffsets64[i])
+
+/*@-bounds@*/
+static void
+doshn(fmagic fm, off_t off, int num, size_t size)
+ /*@globals fileSystem @*/
+ /*@modifies fm, fileSystem @*/
+{
+ Elf32_Shdr sh32;
+ Elf64_Shdr sh64;
+
+ if (size != sh_size) {
+ error(EXIT_FAILURE, 0, "corrupted program header size.\n");
+ /*@notreached@*/
+ }
+
+ if (lseek(fm->fd, off, SEEK_SET) == -1) {
+ error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+
+ for ( ; num; num--) {
+ if (read(fm->fd, sh_addr, size) == -1) {
+ error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+ if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) {
+ fmagicPrintf(fm, ", not stripped");
+ return;
+ }
+ }
+ fmagicPrintf(fm, ", stripped");
+}
+/*@=bounds@*/
+
+/*
+ * Look through the program headers of an executable image, searching
+ * for a PT_INTERP section; if one is found, it's dynamically linked,
+ * otherwise it's statically linked.
+ */
+/*@-bounds@*/
+static void
+dophn_exec(fmagic fm, off_t off, int num, size_t size)
+ /*@globals fileSystem @*/
+ /*@modifies fm, fileSystem @*/
+{
+ Elf32_Phdr ph32;
+ Elf32_Nhdr *nh32 = NULL;
+ Elf64_Phdr ph64;
+ Elf64_Nhdr *nh64 = NULL;
+ char *linking_style = "statically";
+ char *shared_libraries = "";
+ char nbuf[BUFSIZ];
+ int bufsize;
+ size_t offset, nameoffset;
+
+ if (size != ph_size) {
+ error(EXIT_FAILURE, 0, "corrupted program header size.\n");
+ /*@notreached@*/
+ }
+
+ if (lseek(fm->fd, off, SEEK_SET) == -1) {
+ error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+
+ for ( ; num; num--) {
+ if (read(fm->fd, ph_addr, size) == -1) {
+ error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+
+ switch (ph_type) {
+ case PT_DYNAMIC:
+ linking_style = "dynamically";
+ /*@switchbreak@*/ break;
+ case PT_INTERP:
+ shared_libraries = " (uses shared libs)";
+ /*@switchbreak@*/ break;
+ case PT_NOTE:
+ /*
+ * This is a PT_NOTE section; loop through all the notes
+ * in the section.
+ */
+ if (lseek(fm->fd, (off_t) ph_offset, SEEK_SET) == -1) {
+ error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+ bufsize = read(fm->fd, nbuf, sizeof(nbuf));
+ if (bufsize == -1) {
+ error(EXIT_FAILURE, 0, ": " "read failed (%s).\n",
+ strerror(errno));
+ /*@notreached@*/
+ }
+ offset = 0;
+ for (;;) {
+ if (offset >= bufsize)
+ /*@innerbreak@*/ break;
+ if (fm->cls == ELFCLASS32)
+ nh32 = (Elf32_Nhdr *)&nbuf[offset];
+ else
+ nh64 = (Elf64_Nhdr *)&nbuf[offset];
+ offset += nh_size;
+
+ if (offset + nh_namesz >= bufsize) {
+ /*
+ * We're past the end of the buffer.
+ */
+ /*@innerbreak@*/ break;
+ }
+
+ nameoffset = offset;
+ offset += nh_namesz;
+ offset = ((offset+ph_align-1)/ph_align)*ph_align;
+
+ if ((nh_namesz == 0) && (nh_descsz == 0)) {
+ /*
+ * We're out of note headers.
+ */
+ /*@innerbreak@*/ break;
+ }
+
+ if (offset + nh_descsz >= bufsize)
+ /*@innerbreak@*/ break;
+
+ if (nh_namesz == 4 &&
+ strcmp(&nbuf[nameoffset], "GNU") == 0 &&
+ nh_type == NT_GNU_VERSION &&
+ nh_descsz == 16) {
+ uint32_t *desc =
+ (uint32_t *)&nbuf[offset];
+
+ fmagicPrintf(fm, ", for GNU/");
+ switch (getu32(fm, desc[0])) {
+ case GNU_OS_LINUX:
+ fmagicPrintf(fm, "Linux");
+ /*@switchbreak@*/ break;
+ case GNU_OS_HURD:
+ fmagicPrintf(fm, "Hurd");
+ /*@switchbreak@*/ break;
+ case GNU_OS_SOLARIS:
+ fmagicPrintf(fm, "Solaris");
+ /*@switchbreak@*/ break;
+ default:
+ fmagicPrintf(fm, "<unknown>");
+ /*@switchbreak@*/ break;
+ }
+ fmagicPrintf(fm, " %d.%d.%d",
+ getu32(fm, desc[1]),
+ getu32(fm, desc[2]),
+ getu32(fm, desc[3]));
+ }
+
+ if (nh_namesz == 7 &&
+ strcmp(&nbuf[nameoffset], "NetBSD") == 0 &&
+ nh_type == NT_NETBSD_VERSION &&
+ nh_descsz == 4) {
+ fmagicPrintf(fm, ", for NetBSD");
+ /*
+ * Version number is stuck at 199905,
+ * and hence is basically content-free.
+ */
+ }
+
+ if (nh_namesz == 8 &&
+ strcmp(&nbuf[nameoffset], "FreeBSD") == 0 &&
+ nh_type == NT_FREEBSD_VERSION &&
+ nh_descsz == 4) {
+ uint32_t desc = getu32(fm,
+ *(uint32_t *)&nbuf[offset]);
+ fmagicPrintf(fm, ", for FreeBSD");
+ /*
+ * Contents is __FreeBSD_version,
+ * whose relation to OS versions is
+ * defined by a huge table in the
+ * Porters' Handbook. Happily, the
+ * first three digits are the version
+ * number, at least in versions of
+ * FreeBSD that use this note.
+ */
+
+ fmagicPrintf(fm, " %d.%d", desc / 100000,
+ desc / 10000 % 10);
+ if (desc / 1000 % 10 > 0)
+ fmagicPrintf(fm, ".%d",
+ desc / 1000 % 10);
+ }
+
+ if (nh_namesz == 8 &&
+ strcmp(&nbuf[nameoffset], "OpenBSD") == 0 &&
+ nh_type == NT_OPENBSD_VERSION &&
+ nh_descsz == 4) {
+ fmagicPrintf(fm, ", for OpenBSD");
+ /* Content of note is always 0 */
+ }
+ }
+ if ((lseek(fm->fd, ph_offset + offset, SEEK_SET)) == -1) {
+ error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+ /*@switchbreak@*/ break;
+ }
+ }
+ fmagicPrintf(fm, ", %s linked%s", linking_style, shared_libraries);
+}
+/*@=bounds@*/
+
+#ifdef ELFCORE
+/*@unchecked@*/ /*@observer@*/
+static size_t prpsoffsets32[] = {
+ 8, /* FreeBSD */
+ 28, /* Linux 2.0.36 */
+ 32, /* Linux (I forget which kernel version) */
+ 84 /* SunOS 5.x */
+};
+
+/*@unchecked@*/ /*@observer@*/
+static size_t prpsoffsets64[] = {
+ 120 /* SunOS 5.x, 64-bit */
+};
+
+#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
+#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
+
+#define NOFFSETS (fm->cls == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
+
+/*
+ * Look through the program headers of an executable image, searching
+ * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
+ * "FreeBSD"; if one is found, try looking in various places in its
+ * contents for a 16-character string containing only printable
+ * characters - if found, that string should be the name of the program
+ * that dropped core. Note: right after that 16-character string is,
+ * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
+ * Linux, a longer string (80 characters, in 5.x, probably other
+ * SVR4-flavored systems, and Linux) containing the start of the
+ * command line for that program.
+ *
+ * The signal number probably appears in a section of type NT_PRSTATUS,
+ * but that's also rather OS-dependent, in ways that are harder to
+ * dissect with heuristics, so I'm not bothering with the signal number.
+ * (I suppose the signal number could be of interest in situations where
+ * you don't have the binary of the program that dropped core; if you
+ * *do* have that binary, the debugger will probably tell you what
+ * signal it was.)
+ */
+
+#define OS_STYLE_SVR4 0
+#define OS_STYLE_FREEBSD 1
+#define OS_STYLE_NETBSD 2
+
+/*@unchecked@*/ /*@observer@*/
+static const char *os_style_names[] = {
+ "SVR4",
+ "FreeBSD",
+ "NetBSD",
+};
+
+/*@-bounds@*/
+static void
+dophn_core(fmagic fm, off_t off, int num, size_t size)
+ /*@globals fileSystem @*/
+ /*@modifies fm, fileSystem @*/
+{
+ Elf32_Phdr ph32;
+ Elf32_Nhdr *nh32 = NULL;
+ Elf64_Phdr ph64;
+ Elf64_Nhdr *nh64 = NULL;
+ size_t offset, nameoffset, noffset, reloffset;
+ unsigned char c;
+ int i, j;
+ char nbuf[BUFSIZ];
+ int bufsize;
+ int os_style = -1;
+
+ if (size != ph_size) {
+ error(EXIT_FAILURE, 0, "corrupted program header size.\n");
+ /*@notreached@*/
+ }
+
+ /*
+ * Loop through all the program headers.
+ */
+ for ( ; num; num--) {
+ if (lseek(fm->fd, off, SEEK_SET) == -1) {
+ error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+ if (read(fm->fd, ph_addr, size) == -1) {
+ error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+ off += size;
+ if (ph_type != PT_NOTE)
+ continue;
+
+ /*
+ * This is a PT_NOTE section; loop through all the notes
+ * in the section.
+ */
+ if (lseek(fm->fd, (off_t) ph_offset, SEEK_SET) == -1) {
+ error(EXIT_FAILURE, 0, "lseek failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+ bufsize = read(fm->fd, nbuf, BUFSIZ);
+ if (bufsize == -1) {
+ error(EXIT_FAILURE, 0, ": " "read failed (%s).\n", strerror(errno));
+ /*@notreached@*/
+ }
+ offset = 0;
+ for (;;) {
+ if (offset >= bufsize)
+ /*@innerbreak@*/ break;
+ if (fm->cls == ELFCLASS32)
+ nh32 = (Elf32_Nhdr *)&nbuf[offset];
+ else
+ nh64 = (Elf64_Nhdr *)&nbuf[offset];
+ offset += nh_size;
+
+ /*
+ * Check whether this note has the name "CORE" or
+ * "FreeBSD", or "NetBSD-CORE".
+ */
+ if (offset + nh_namesz >= bufsize) {
+ /*
+ * We're past the end of the buffer.
+ */
+ /*@innerbreak@*/ break;
+ }
+
+ nameoffset = offset;
+ offset += nh_namesz;
+ offset = ((offset + 3)/4)*4;
+
+ /*
+ * Sigh. The 2.0.36 kernel in Debian 2.1, at
+ * least, doesn't correctly implement name
+ * sections, in core dumps, as specified by
+ * the "Program Linking" section of "UNIX(R) System
+ * V Release 4 Programmer's Guide: ANSI C and
+ * Programming Support Tools", because my copy
+ * clearly says "The first 'namesz' bytes in 'name'
+ * contain a *null-terminated* [emphasis mine]
+ * character representation of the entry's owner
+ * or originator", but the 2.0.36 kernel code
+ * doesn't include the terminating null in the
+ * name....
+ */
+ if (os_style == -1) {
+ if ((nh_namesz == 4 &&
+ strncmp(&nbuf[nameoffset],
+ "CORE", 4) == 0) ||
+ (nh_namesz == 5 &&
+ strcmp(&nbuf[nameoffset],
+ "CORE") == 0)) {
+ os_style = OS_STYLE_SVR4;
+ } else
+ if ((nh_namesz == 8 &&
+ strcmp(&nbuf[nameoffset],
+ "FreeBSD") == 0)) {
+ os_style = OS_STYLE_FREEBSD;
+ } else
+ if ((nh_namesz >= 11 &&
+ strncmp(&nbuf[nameoffset],
+ "NetBSD-CORE", 11) == 0)) {
+ os_style = OS_STYLE_NETBSD;
+ } else
+ /*@innercontinue@*/ continue;
+ fmagicPrintf(fm, ", %s-style", os_style_names[os_style]);
+ }
+
+ if (os_style == OS_STYLE_NETBSD &&
+ nh_type == NT_NETBSD_CORE_PROCINFO) {
+ uint32_t signo;
+
+ /*
+ * Extract the program name. It is at
+ * offset 0x7c, and is up to 32-bytes,
+ * including the terminating NUL.
+ */
+ fmagicPrintf(fm, ", from '%.31s'", &nbuf[offset + 0x7c]);
+
+ /*
+ * Extract the signal number. It is at
+ * offset 0x08.
+ */
+ memcpy(&signo, &nbuf[offset + 0x08],
+ sizeof(signo));
+ fmagicPrintf(fm, " (signal %u)", getu32(fm, signo));
+ } else
+ if (os_style != OS_STYLE_NETBSD &&
+ nh_type == NT_PRPSINFO) {
+ /*
+ * Extract the program name. We assume
+ * it to be 16 characters (that's what it
+ * is in SunOS 5.x and Linux).
+ *
+ * Unfortunately, it's at a different offset
+ * in varous OSes, so try multiple offsets.
+ * If the characters aren't all printable,
+ * reject it.
+ */
+ for (i = 0; i < NOFFSETS; i++) {
+ reloffset = prpsoffsets(i);
+ noffset = offset + reloffset;
+ for (j = 0; j < 16;
+ j++, noffset++, reloffset++) {
+ /*
+ * Make sure we're not past
+ * the end of the buffer; if
+ * we are, just give up.
+ */
+ if (noffset >= bufsize)
+ goto tryanother;
+
+ /*
+ * Make sure we're not past
+ * the end of the contents;
+ * if we are, this obviously
+ * isn't the right offset.
+ */
+ if (reloffset >= nh_descsz)
+ goto tryanother;
+
+ c = nbuf[noffset];
+ if (c == '\0') {
+ /*
+ * A '\0' at the
+ * beginning is
+ * obviously wrong.
+ * Any other '\0'
+ * means we're done.
+ */
+ if (j == 0)
+ goto tryanother;
+ else
+ /*@innerbreak@*/ break;
+ } else {
+ /*
+ * A nonprintable
+ * character is also
+ * wrong.
+ */
+#define isquote(c) (strchr("'\"`", (c)) != NULL)
+ if (!isprint(c) ||
+ isquote(c))
+ goto tryanother;
+ }
+ }
+
+ /*
+ * Well, that worked.
+ */
+ fmagicPrintf(fm, ", from '%.16s'",
+ &nbuf[offset + prpsoffsets(i)]);
+ /*@innerbreak@*/ break;
+
+ tryanother:
+ ;
+ }
+ /*@innerbreak@*/ break;
+ }
+ offset += nh_descsz;
+ offset = ((offset + 3)/4)*4;
+ }
+ }
+}
+/*@=bounds@*/
+#endif
+
+/*@-bounds@*/
+void
+fmagicE(fmagic fm)
+{
+/*@-sizeoftype@*/
+ union {
+ int32_t l;
+ char c[sizeof (int32_t)];
+ } u;
+/*@=sizeoftype@*/
+
+ /*
+ * If we can't seek, it must be a pipe, socket or fifo.
+ */
+ if((lseek(fm->fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
+ fm->fd = pipe2file(fm->fd, fm->buf, fm->nb);
+
+ /*
+ * ELF executables have multiple section headers in arbitrary
+ * file locations and thus file(1) cannot determine it from easily.
+ * Instead we traverse thru all section headers until a symbol table
+ * one is found or else the binary is stripped.
+ */
+ if (fm->buf[EI_MAG0] != ELFMAG0
+ || (fm->buf[EI_MAG1] != ELFMAG1 && fm->buf[EI_MAG1] != OLFMAG1)
+ || fm->buf[EI_MAG2] != ELFMAG2 || fm->buf[EI_MAG3] != ELFMAG3)
+ return;
+
+
+ fm->cls = fm->buf[EI_CLASS];
+
+ if (fm->cls == ELFCLASS32) {
+ Elf32_Ehdr elfhdr;
+ if (fm->nb <= sizeof (elfhdr))
+ return;
+
+
+ u.l = 1;
+ (void) memcpy(&elfhdr, fm->buf, sizeof elfhdr);
+/*@-sizeoftype@*/
+ fm->swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
+/*@=sizeoftype@*/
+
+ if (getu16(fm, elfhdr.e_type) == ET_CORE)
+#ifdef ELFCORE
+ dophn_core(fm,
+ getu32(fm, elfhdr.e_phoff),
+ getu16(fm, elfhdr.e_phnum),
+ getu16(fm, elfhdr.e_phentsize));
+#else
+ ;
+#endif
+ else {
+ if (getu16(fm, elfhdr.e_type) == ET_EXEC) {
+ dophn_exec(fm,
+ getu32(fm, elfhdr.e_phoff),
+ getu16(fm, elfhdr.e_phnum),
+ getu16(fm, elfhdr.e_phentsize));
+ }
+ doshn(fm,
+ getu32(fm, elfhdr.e_shoff),
+ getu16(fm, elfhdr.e_shnum),
+ getu16(fm, elfhdr.e_shentsize));
+ }
+ return;
+ }
+
+ if (fm->cls == ELFCLASS64) {
+ Elf64_Ehdr elfhdr;
+ if (fm->nb <= sizeof (elfhdr))
+ return;
+
+ u.l = 1;
+ (void) memcpy(&elfhdr, fm->buf, sizeof elfhdr);
+/*@-sizeoftype@*/
+ fm->swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[EI_DATA];
+/*@=sizeoftype@*/
+
+ if (getu16(fm, elfhdr.e_type) == ET_CORE)
+#ifdef ELFCORE
+ dophn_core(fm,
+#ifdef USE_ARRAY_FOR_64BIT_TYPES
+ getu32(fm, elfhdr.e_phoff[1]),
+#else
+ getu64(fm, elfhdr.e_phoff),
+#endif
+ getu16(fm, elfhdr.e_phnum),
+ getu16(fm, elfhdr.e_phentsize));
+#else
+ ;
+#endif
+ else
+ {
+ if (getu16(fm, elfhdr.e_type) == ET_EXEC) {
+ dophn_exec(fm,
+#ifdef USE_ARRAY_FOR_64BIT_TYPES
+ getu32(fm, elfhdr.e_phoff[1]),
+#else
+ getu64(fm, elfhdr.e_phoff),
+#endif
+ getu16(fm, elfhdr.e_phnum),
+ getu16(fm, elfhdr.e_phentsize));
+ }
+ doshn(fm,
+#ifdef USE_ARRAY_FOR_64BIT_TYPES
+ getu32(fm, elfhdr.e_shoff[1]),
+#else
+ getu64(fm, elfhdr.e_shoff),
+#endif
+ getu16(fm, elfhdr.e_shnum),
+ getu16(fm, elfhdr.e_shentsize));
+ }
+ return;
+ }
+}
+/*@=bounds@*/
+#endif /* BUILTIN_ELF */
--- /dev/null
+/* $NetBSD: readelf.h,v 1.9 2002/05/18 07:00:47 pooka Exp $ */
+/*@-redef@*/
+
+/*
+ * readelf.h
+ * @(#)Id: readelf.h,v 1.9 2002/05/16 18:45:56 christos Exp
+ *
+ * Provide elf data structures for non-elf machines, allowing file
+ * non-elf hosts to determine if an elf binary is stripped.
+ * Note: cobbled from the linux header file, with modifications
+ */
+#ifndef __fake_elf_h__
+#define __fake_elf_h__
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+typedef uint32_t Elf32_Addr;
+typedef uint32_t Elf32_Off;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Word;
+typedef uint8_t Elf32_Char;
+
+#if SIZEOF_UINT64_T != 8
+#define USE_ARRAY_FOR_64BIT_TYPES
+typedef uint32_t Elf64_Addr[2];
+typedef uint32_t Elf64_Off[2];
+typedef uint32_t Elf64_Xword[2];
+#else
+typedef uint64_t Elf64_Addr;
+typedef uint64_t Elf64_Off;
+typedef uint64_t Elf64_Xword;
+#endif
+typedef uint16_t Elf64_Half;
+typedef uint32_t Elf64_Word;
+typedef uint8_t Elf64_Char;
+
+#define EI_NIDENT 16
+
+/*@-matchfields@*/
+typedef struct {
+ Elf32_Char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry; /* Entry point */
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct {
+ Elf64_Char e_ident[EI_NIDENT];
+ Elf64_Half e_type;
+ Elf64_Half e_machine;
+ Elf64_Word e_version;
+ Elf64_Addr e_entry; /* Entry point */
+ Elf64_Off e_phoff;
+ Elf64_Off e_shoff;
+ Elf64_Word e_flags;
+ Elf64_Half e_ehsize;
+ Elf64_Half e_phentsize;
+ Elf64_Half e_phnum;
+ Elf64_Half e_shentsize;
+ Elf64_Half e_shnum;
+ Elf64_Half e_shstrndx;
+} Elf64_Ehdr;
+/*@=matchfields@*/
+
+/* e_type */
+#define ET_EXEC 2
+#define ET_CORE 4
+
+/* sh_type */
+#define SHT_SYMTAB 2
+#define SHT_NOTE 7
+#define SHT_DYNSYM 11
+
+/* elf type */
+#define ELFDATANONE 0 /* e_ident[EI_DATA] */
+#define ELFDATA2LSB 1
+#define ELFDATA2MSB 2
+
+/* elf class */
+#define ELFCLASSNONE 0
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+
+/* magic number */
+#define EI_MAG0 0 /* e_ident[] indexes */
+#define EI_MAG1 1
+#define EI_MAG2 2
+#define EI_MAG3 3
+#define EI_CLASS 4
+#define EI_DATA 5
+#define EI_VERSION 6
+#define EI_PAD 7
+
+#define ELFMAG0 0x7f /* EI_MAG */
+#define ELFMAG1 'E'
+#define ELFMAG2 'L'
+#define ELFMAG3 'F'
+#define ELFMAG "\177ELF"
+
+#define OLFMAG1 'O'
+#define OLFMAG "\177OLF"
+
+typedef struct {
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct {
+ Elf64_Word p_type;
+ Elf64_Word p_flags;
+ Elf64_Off p_offset;
+ Elf64_Addr p_vaddr;
+ Elf64_Addr p_paddr;
+ Elf64_Xword p_filesz;
+ Elf64_Xword p_memsz;
+ Elf64_Xword p_align;
+} Elf64_Phdr;
+
+#define PT_NULL 0 /* p_type */
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_NUM 7
+
+typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+/*@-matchfields@*/
+typedef struct {
+ Elf64_Word sh_name;
+ Elf64_Word sh_type;
+ Elf64_Off sh_flags;
+ Elf64_Addr sh_addr;
+ Elf64_Off sh_offset;
+ Elf64_Off sh_size;
+ Elf64_Word sh_link;
+ Elf64_Word sh_info;
+ Elf64_Off sh_addralign;
+ Elf64_Off sh_entsize;
+} Elf64_Shdr;
+/*@=matchfields@*/
+
+/* Notes used in ET_CORE */
+#define NT_PRSTATUS 1
+#define NT_PRFPREG 2
+#define NT_PRPSINFO 3
+#define NT_TASKSTRUCT 4
+
+#define NT_NETBSD_CORE_PROCINFO 1
+
+/* Note header in a PT_NOTE section */
+typedef struct elf_note {
+ Elf32_Word n_namesz; /* Name size */
+ Elf32_Word n_descsz; /* Content size */
+ Elf32_Word n_type; /* Content type */
+} Elf32_Nhdr;
+
+typedef struct {
+ Elf64_Word n_namesz;
+ Elf64_Word n_descsz;
+ Elf64_Word n_type;
+} Elf64_Nhdr;
+
+#define NT_PRSTATUS 1
+#define NT_PRFPREG 2
+#define NT_PRPSINFO 3
+#define NT_PRXREG 4
+#define NT_PLATFORM 5
+#define NT_AUXV 6
+
+/* Note types used in executables */
+/* NetBSD executables (name = "NetBSD") */
+#define NT_NETBSD_VERSION 1
+#define NT_NETBSD_EMULATION 2
+#define NT_FREEBSD_VERSION 1
+#define NT_OPENBSD_VERSION 1
+/* GNU executables (name = "GNU") */
+#define NT_GNU_VERSION 1
+
+/* GNU OS tags */
+#define GNU_OS_LINUX 0
+#define GNU_OS_HURD 1
+#define GNU_OS_SOLARIS 2
+/*@=redef@*/
+
+#endif
--- /dev/null
+/*
+ * softmagic - interpret variable magic from MAGIC
+ *
+ * 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 "system.h"
+#include "file.h"
+#include "debug.h"
+
+FILE_RCSID("@(#)Id: softmagic.c,v 1.51 2002/07/03 18:26:38 christos Exp ")
+
+/*@access fmagic @*/
+
+/*@-bounds@*/
+static int32_t
+fmagicSPrint(const fmagic fm, struct magic *m)
+ /*@globals fileSystem @*/
+ /*@modifies fm, fileSystem @*/
+{
+ union VALUETYPE * p = &fm->val;
+ uint32_t v;
+ int32_t t = 0;
+
+ switch (m->type) {
+ case BYTE:
+ v = signextend(m, p->b);
+ fmagicPrintf(fm, m->desc, (unsigned char) v);
+/*@-sizeoftype@*/
+ t = m->offset + sizeof(char);
+/*@=sizeoftype@*/
+ break;
+
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = signextend(m, p->h);
+ fmagicPrintf(fm, m->desc, (unsigned short) v);
+/*@-sizeoftype@*/
+ t = m->offset + sizeof(short);
+/*@=sizeoftype@*/
+ break;
+
+ case LONG:
+ case BELONG:
+ case LELONG:
+ v = signextend(m, p->l);
+ fmagicPrintf(fm, m->desc, (uint32_t) v);
+/*@-sizeoftype@*/
+ t = m->offset + sizeof(int32_t);
+/*@=sizeoftype@*/
+ break;
+
+ case STRING:
+ case PSTRING:
+ if (m->reln == '=') {
+ fmagicPrintf(fm, m->desc, m->value.s);
+ t = m->offset + strlen(m->value.s);
+ } else {
+ if (*m->value.s == '\0') {
+ char *cp = strchr(p->s,'\n');
+ if (cp != NULL)
+ *cp = '\0';
+ }
+ fmagicPrintf(fm, m->desc, p->s);
+ t = m->offset + strlen(p->s);
+ }
+ break;
+
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ fmagicPrintf(fm, m->desc, fmttime(p->l, 1));
+/*@-sizeoftype@*/
+ t = m->offset + sizeof(time_t);
+/*@=sizeoftype@*/
+ break;
+
+ case LDATE:
+ case BELDATE:
+ case LELDATE:
+ fmagicPrintf(fm, m->desc, fmttime(p->l, 0));
+/*@-sizeoftype@*/
+ t = m->offset + sizeof(time_t);
+/*@=sizeoftype@*/
+ break;
+
+ case REGEX:
+ fmagicPrintf(fm, m->desc, p->s);
+ t = m->offset + strlen(p->s);
+ break;
+
+ default:
+ error(EXIT_FAILURE, 0, "invalid m->type (%d) in fmagicSPrint().\n", m->type);
+ /*@notreached@*/ break;
+ }
+ return(t);
+}
+/*@=bounds@*/
+
+/*
+ * Convert the byte order of the data we are looking at
+ * While we're here, let's apply the mask operation
+ * (unless you have a better idea)
+ */
+/*@-bounds@*/
+static int
+fmagicSConvert(fmagic fm, struct magic *m)
+ /*@globals fileSystem @*/
+ /*@modifies fm, fileSystem @*/
+{
+ union VALUETYPE * p = &fm->val;
+
+ switch (m->type) {
+ case BYTE:
+ if (m->mask)
+ switch (m->mask_op&0x7F) {
+ case OPAND:
+ p->b &= m->mask;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ p->b |= m->mask;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ p->b ^= m->mask;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ p->b += m->mask;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ p->b -= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ p->b *= m->mask;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ p->b /= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ p->b %= m->mask;
+ /*@innerbreak@*/ break;
+ }
+ if (m->mask_op & OPINVERSE)
+ p->b = ~p->b;
+ return 1;
+ case SHORT:
+ if (m->mask)
+ switch (m->mask_op&0x7F) {
+ case OPAND:
+ p->h &= m->mask;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ p->h |= m->mask;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ p->h ^= m->mask;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ p->h += m->mask;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ p->h -= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ p->h *= m->mask;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ p->h /= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ p->h %= m->mask;
+ /*@innerbreak@*/ break;
+ }
+ if (m->mask_op & OPINVERSE)
+ p->h = ~p->h;
+ return 1;
+ case LONG:
+ case DATE:
+ case LDATE:
+ if (m->mask)
+ switch (m->mask_op&0x7F) {
+ case OPAND:
+ p->l &= m->mask;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ p->l |= m->mask;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ p->l ^= m->mask;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ p->l += m->mask;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ p->l -= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ p->l *= m->mask;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ p->l /= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ p->l %= m->mask;
+ /*@innerbreak@*/ break;
+ }
+ if (m->mask_op & OPINVERSE)
+ p->l = ~p->l;
+ return 1;
+ case STRING:
+ {
+ int n;
+
+ /* Null terminate and eat *trailing* return */
+ p->s[sizeof(p->s) - 1] = '\0';
+ n = strlen(p->s) - 1;
+ if (p->s[n] == '\n')
+ p->s[n] = '\0';
+ return 1;
+ }
+ case PSTRING:
+ {
+ char *ptr1 = p->s, *ptr2 = ptr1 + 1;
+ int n = *p->s;
+ if (n >= sizeof(p->s))
+ n = sizeof(p->s) - 1;
+ while (n--)
+ *ptr1++ = *ptr2++;
+ *ptr1 = '\0';
+ n = strlen(p->s) - 1;
+ if (p->s[n] == '\n')
+ p->s[n] = '\0';
+ return 1;
+ }
+ case BESHORT:
+ p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
+ if (m->mask)
+ switch (m->mask_op&0x7F) {
+ case OPAND:
+ p->h &= m->mask;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ p->h |= m->mask;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ p->h ^= m->mask;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ p->h += m->mask;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ p->h -= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ p->h *= m->mask;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ p->h /= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ p->h %= m->mask;
+ /*@innerbreak@*/ break;
+ }
+ if (m->mask_op & OPINVERSE)
+ p->h = ~p->h;
+ return 1;
+ case BELONG:
+ case BEDATE:
+ case BELDATE:
+ p->l = (int32_t)
+ ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
+ if (m->mask)
+ switch (m->mask_op&0x7F) {
+ case OPAND:
+ p->l &= m->mask;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ p->l |= m->mask;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ p->l ^= m->mask;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ p->l += m->mask;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ p->l -= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ p->l *= m->mask;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ p->l /= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ p->l %= m->mask;
+ /*@innerbreak@*/ break;
+ }
+ if (m->mask_op & OPINVERSE)
+ p->l = ~p->l;
+ return 1;
+ case LESHORT:
+ p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
+ if (m->mask)
+ switch (m->mask_op&0x7F) {
+ case OPAND:
+ p->h &= m->mask;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ p->h |= m->mask;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ p->h ^= m->mask;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ p->h += m->mask;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ p->h -= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ p->h *= m->mask;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ p->h /= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ p->h %= m->mask;
+ /*@innerbreak@*/ break;
+ }
+ if (m->mask_op & OPINVERSE)
+ p->h = ~p->h;
+ return 1;
+ case LELONG:
+ case LEDATE:
+ case LELDATE:
+ p->l = (int32_t)
+ ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
+ if (m->mask)
+ switch (m->mask_op&0x7F) {
+ case OPAND:
+ p->l &= m->mask;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ p->l |= m->mask;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ p->l ^= m->mask;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ p->l += m->mask;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ p->l -= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ p->l *= m->mask;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ p->l /= m->mask;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ p->l %= m->mask;
+ /*@innerbreak@*/ break;
+ }
+ if (m->mask_op & OPINVERSE)
+ p->l = ~p->l;
+ return 1;
+ case REGEX:
+ return 1;
+ default:
+ error(EXIT_FAILURE, 0, "invalid type %d in fmagicSConvert().\n", m->type);
+ /*@notreached@*/
+ return 0;
+ }
+}
+/*@=bounds@*/
+
+
+static void
+fmagicSDebug(int32_t offset, char *str, int len)
+ /*@globals fileSystem @*/
+ /*@modifies fileSystem @*/
+{
+ (void) fprintf(stderr, "fmagicSGet @%d: ", offset);
+ showstr(stderr, (char *) str, len);
+ (void) fputc('\n', stderr);
+ (void) fputc('\n', stderr);
+}
+
+/*@-bounds@*/
+static int
+fmagicSGet(fmagic fm, struct magic *m)
+ /*@globals fileSystem @*/
+ /*@modifies fm, fileSystem @*/
+{
+ unsigned char * buf = fm->buf;
+ int nb = fm->nb;
+ union VALUETYPE * p = &fm->val;
+ int32_t offset = m->offset;
+
+/*@-branchstate@*/
+ if (m->type == REGEX) {
+ /*
+ * offset is interpreted as last line to search,
+ * (starting at 1), not as bytes-from start-of-file
+ */
+ char *last = NULL;
+/*@-temptrans@*/
+ p->buf = buf;
+/*@=temptrans@*/
+ for (; offset && (buf = strchr(buf, '\n')) != NULL; offset--, buf++)
+ last = buf;
+ if (last != NULL)
+ *last = '\0';
+ } else if (offset + sizeof(*p) <= nb)
+ memcpy(p, buf + offset, sizeof(*p));
+ else {
+ /*
+ * the usefulness of padding with zeroes eludes me, it
+ * might even cause problems
+ */
+ int32_t have = nb - offset;
+ memset(p, 0, sizeof(*p));
+ if (have > 0)
+ memcpy(p, buf + offset, have);
+ }
+/*@=branchstate@*/
+
+ if (fm->flags & FMAGIC_FLAGS_DEBUG) {
+ fmagicSDebug(offset, (char *) p, sizeof(*p));
+ mdump(m);
+ }
+
+ if (m->flag & INDIR) {
+ switch (m->in_type) {
+ case BYTE:
+ if (m->in_offset)
+ switch (m->in_op&0x7F) {
+ case OPAND:
+ offset = p->b & m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ offset = p->b | m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ offset = p->b ^ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ offset = p->b + m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ offset = p->b - m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ offset = p->b * m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ offset = p->b / m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ offset = p->b % m->in_offset;
+ /*@innerbreak@*/ break;
+ }
+ if (m->in_op & OPINVERSE)
+ offset = ~offset;
+ break;
+ case BESHORT:
+ if (m->in_offset)
+ switch (m->in_op&0x7F) {
+ case OPAND:
+ offset = (short)((p->hs[0]<<8) | (p->hs[1])) &
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ offset = (short)((p->hs[0]<<8) | (p->hs[1])) |
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ offset = (short)((p->hs[0]<<8) | (p->hs[1])) ^
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ offset = (short)((p->hs[0]<<8) | (p->hs[1])) +
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ offset = (short)((p->hs[0]<<8) | (p->hs[1])) -
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ offset = (short)((p->hs[0]<<8) | (p->hs[1])) *
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ offset = (short)((p->hs[0]<<8) | (p->hs[1])) /
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ offset = (short)((p->hs[0]<<8) | (p->hs[1])) %
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ }
+ if (m->in_op & OPINVERSE)
+ offset = ~offset;
+ break;
+ case LESHORT:
+ if (m->in_offset)
+ switch (m->in_op&0x7F) {
+ case OPAND:
+ offset = (short)((p->hs[1]<<8) | (p->hs[0])) &
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ offset = (short)((p->hs[1]<<8) | (p->hs[0])) |
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ offset = (short)((p->hs[1]<<8) | (p->hs[0])) ^
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ offset = (short)((p->hs[1]<<8) | (p->hs[0])) +
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ offset = (short)((p->hs[1]<<8) | (p->hs[0])) -
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ offset = (short)((p->hs[1]<<8) | (p->hs[0])) *
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ offset = (short)((p->hs[1]<<8) | (p->hs[0])) /
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ offset = (short)((p->hs[1]<<8) | (p->hs[0])) %
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ }
+ if (m->in_op & OPINVERSE)
+ offset = ~offset;
+ break;
+ case SHORT:
+ if (m->in_offset)
+ switch (m->in_op&0x7F) {
+ case OPAND:
+ offset = p->h & m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ offset = p->h | m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ offset = p->h ^ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ offset = p->h + m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ offset = p->h - m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ offset = p->h * m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ offset = p->h / m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ offset = p->h % m->in_offset;
+ /*@innerbreak@*/ break;
+ }
+ if (m->in_op & OPINVERSE)
+ offset = ~offset;
+ break;
+ case BELONG:
+ if (m->in_offset)
+ switch (m->in_op&0x7F) {
+ case OPAND:
+ offset = (int32_t)( (p->hl[0]<<24) | (p->hl[1]<<16) |
+ (p->hl[2]<< 8) | (p->hl[3])) &
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ offset = (int32_t)( (p->hl[0]<<24) | (p->hl[1]<<16) |
+ (p->hl[2]<< 8) | (p->hl[3])) |
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ offset = (int32_t)( (p->hl[0]<<24) | (p->hl[1]<<16) |
+ (p->hl[2]<< 8) | (p->hl[3])) ^
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ offset = (int32_t)( (p->hl[0]<<24) | (p->hl[1]<<16) |
+ (p->hl[2]<< 8) | (p->hl[3])) +
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ offset = (int32_t)( (p->hl[0]<<24) | (p->hl[1]<<16) |
+ (p->hl[2]<< 8) | (p->hl[3])) -
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ offset = (int32_t)( (p->hl[0]<<24) | (p->hl[1]<<16) |
+ (p->hl[2]<< 8) | (p->hl[3])) *
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ offset = (int32_t)( (p->hl[0]<<24) | (p->hl[1]<<16) |
+ (p->hl[2]<< 8) | (p->hl[3])) /
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ offset = (int32_t)( (p->hl[0]<<24) | (p->hl[1]<<16) |
+ (p->hl[2]<< 8) | (p->hl[3])) %
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ }
+ if (m->in_op & OPINVERSE)
+ offset = ~offset;
+ break;
+ case LELONG:
+ if (m->in_offset)
+ switch (m->in_op&0x7F) {
+ case OPAND:
+ offset = (int32_t)( (p->hl[3]<<24) | (p->hl[2]<<16) |
+ (p->hl[1]<< 8) | (p->hl[0])) &
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ offset = (int32_t)( (p->hl[3]<<24) | (p->hl[2]<<16) |
+ (p->hl[1]<< 8) | (p->hl[0])) |
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ offset = (int32_t)( (p->hl[3]<<24) | (p->hl[2]<<16) |
+ (p->hl[1]<< 8) | (p->hl[0])) ^
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ offset = (int32_t)( (p->hl[3]<<24) | (p->hl[2]<<16) |
+ (p->hl[1]<< 8) | (p->hl[0])) +
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ offset = (int32_t)( (p->hl[3]<<24) | (p->hl[2]<<16) |
+ (p->hl[1]<< 8) | (p->hl[0])) -
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ offset = (int32_t)( (p->hl[3]<<24) | (p->hl[2]<<16) |
+ (p->hl[1]<< 8) | (p->hl[0])) *
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ offset = (int32_t)( (p->hl[3]<<24) | (p->hl[2]<<16) |
+ (p->hl[1]<< 8) | (p->hl[0])) /
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ offset = (int32_t)( (p->hl[3]<<24) | (p->hl[2]<<16) |
+ (p->hl[1]<< 8) | (p->hl[0])) %
+ m->in_offset;
+ /*@innerbreak@*/ break;
+ }
+ if (m->in_op & OPINVERSE)
+ offset = ~offset;
+ break;
+ case LONG:
+ if (m->in_offset)
+ switch (m->in_op&0x7F) {
+ case OPAND:
+ offset = p->l & m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPOR:
+ offset = p->l | m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPXOR:
+ offset = p->l ^ m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPADD:
+ offset = p->l + m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMINUS:
+ offset = p->l - m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMULTIPLY:
+ offset = p->l * m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPDIVIDE:
+ offset = p->l / m->in_offset;
+ /*@innerbreak@*/ break;
+ case OPMODULO:
+ offset = p->l % m->in_offset;
+ /*@innerbreak@*/ break;
+ /* case TOOMANYSWITCHBLOCKS:
+ * ugh = p->eye % m->strain;
+ * rub;
+ * case BEER:
+ * off = p->tab & m->in_gest;
+ * sleep;
+ */
+ }
+ if (m->in_op & OPINVERSE)
+ offset = ~offset;
+ break;
+ }
+
+/*@-compmempass@*/
+ if (buf == NULL || offset + sizeof(*p) > nb)
+ return 0;
+/*@=compmempass@*/
+
+ memcpy(p, buf + offset, sizeof(*p));
+
+ if (fm->flags & FMAGIC_FLAGS_DEBUG) {
+ fmagicSDebug(offset, (char *) p, sizeof(*p));
+ mdump(m);
+ }
+ }
+/*@-compmempass@*/
+ if (!fmagicSConvert(fm, m))
+ return 0;
+ return 1;
+/*@=compmempass@*/
+}
+/*@=bounds@*/
+
+/*@-bounds@*/
+static int
+fmagicSCheck(const fmagic fm, struct magic *m)
+ /*@globals fileSystem @*/
+ /*@modifies fileSystem @*/
+{
+ union VALUETYPE * p = &fm->val;
+ uint32_t l = m->value.l;
+ uint32_t v = 0;
+ int matched;
+
+ if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
+ fprintf(stderr, "BOINK");
+ return 1;
+ }
+
+ switch (m->type) {
+ case BYTE:
+ v = p->b;
+ break;
+
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ v = p->h;
+ break;
+
+ case LONG:
+ case BELONG:
+ case LELONG:
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ case LDATE:
+ case BELDATE:
+ case LELDATE:
+ v = p->l;
+ break;
+
+ case STRING:
+ case PSTRING:
+ {
+ /*
+ * What we want here is:
+ * v = strncmp(m->value.s, p->s, m->vallen);
+ * but ignoring any nulls. bcmp doesn't give -/+/0
+ * and isn't universally available anyway.
+ */
+ unsigned char *a = (unsigned char*)m->value.s;
+ unsigned char *b = (unsigned char*)p->s;
+ int len = m->vallen;
+ l = 0;
+ v = 0;
+ if (0L == m->mask) { /* normal string: do it fast */
+ while (--len >= 0)
+ if ((v = *b++ - *a++) != '\0')
+ /*@loopbreak@*/ break;
+ } else { /* combine the others */
+ while (--len >= 0) {
+ if ((m->mask & STRING_IGNORE_LOWERCASE) && islower(*a)) {
+ if ((v = tolower(*b++) - *a++) != '\0')
+ /*@loopbreak@*/ break;
+ } else
+ if ((m->mask & STRING_COMPACT_BLANK) && isspace(*a)) {
+ a++;
+ if (isspace(*b++)) {
+ while (isspace(*b))
+ b++;
+ } else {
+ v = 1;
+ /*@loopbreak@*/ break;
+ }
+ } else
+ if (isspace(*a) && (m->mask & STRING_COMPACT_OPTIONAL_BLANK)) {
+ a++;
+ while (isspace(*b))
+ b++;
+ } else {
+ if ((v = *b++ - *a++) != '\0')
+ /*@loopbreak@*/ break;
+ }
+ }
+ }
+ break;
+ }
+ case REGEX:
+ {
+ int rc;
+ regex_t rx;
+ char errmsg[512];
+
+ rc = regcomp(&rx, m->value.s, REG_EXTENDED|REG_NOSUB);
+ if (rc) {
+ (void) regerror(rc, &rx, errmsg, sizeof(errmsg));
+ error(EXIT_FAILURE, 0, "regex error %d, (%s)\n", rc, errmsg);
+ /*@notreached@*/
+ } else {
+ rc = regexec(&rx, p->buf, 0, NULL, 0);
+ return !rc;
+ }
+ }
+ /*@notreached@*/ break;
+ default:
+ error(EXIT_FAILURE, 0, "invalid type %d in fmagicSCheck().\n", m->type);
+ /*@notreached@*/
+ return 0;
+ }
+
+ if(m->type != STRING && m->type != PSTRING)
+ v = signextend(m, v);
+
+ switch (m->reln) {
+ case 'x':
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "%u == *any* = 1\n", v);
+ matched = 1;
+ break;
+
+ case '!':
+ matched = v != l;
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "%u != %u = %d\n",
+ v, l, matched);
+ break;
+
+ case '=':
+ matched = v == l;
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "%u == %u = %d\n",
+ v, l, matched);
+ break;
+
+ case '>':
+ if (m->flag & UNSIGNED) {
+ matched = v > l;
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "%u > %u = %d\n", v, l, matched);
+ }
+ else {
+ matched = (int32_t) v > (int32_t) l;
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "%d > %d = %d\n", v, l, matched);
+ }
+ break;
+
+ case '<':
+ if (m->flag & UNSIGNED) {
+ matched = v < l;
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "%u < %u = %d\n", v, l, matched);
+ }
+ else {
+ matched = (int32_t) v < (int32_t) l;
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "%d < %d = %d\n", v, l, matched);
+ }
+ break;
+
+ case '&':
+ matched = (v & l) == l;
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "((%x & %x) == %x) = %d\n", v, l, l, matched);
+ break;
+
+ case '^':
+ matched = (v & l) != l;
+ if (fm->flags & FMAGIC_FLAGS_DEBUG)
+ (void) fprintf(stderr, "((%x & %x) != %x) = %d\n", v, l, l, matched);
+ break;
+
+ default:
+ matched = 0;
+ error(EXIT_FAILURE, 0, "fmagicSCheck: can't happen: invalid relation %d.\n", m->reln);
+ /*@notreached@*/ break;
+ }
+
+ return matched;
+}
+/*@=bounds@*/
+
+/*
+ * Go through the whole list, stopping if you find a match. Process all
+ * the continuations of that match before returning.
+ *
+ * We support multi-level continuations:
+ *
+ * At any time when processing a successful top-level match, there is a
+ * current continuation level; it represents the level of the last
+ * successfully matched continuation.
+ *
+ * Continuations above that level are skipped as, if we see one, it
+ * means that the continuation that controls them - i.e, the
+ * lower-level continuation preceding them - failed to match.
+ *
+ * Continuations below that level are processed as, if we see one,
+ * it means we've finished processing or skipping higher-level
+ * continuations under the control of a successful or unsuccessful
+ * lower-level continuation, and are now seeing the next lower-level
+ * continuation and should process it. The current continuation
+ * level reverts to the level of the one we're seeing.
+ *
+ * Continuations at the current level are processed as, if we see
+ * one, there's no lower-level continuation that may have failed.
+ *
+ * If a continuation matches, we bump the current continuation level
+ * so that higher-level continuations are processed.
+ */
+/*@-bounds@*/
+static int
+fmagicSMatch(const fmagic fm)
+ /*@globals fileSystem @*/
+ /*@modifies fm, fileSystem @*/
+{
+ struct magic * m;
+ uint32_t nmagic = fm->ml->nmagic;
+ int cont_level = 0;
+ int need_separator = 0;
+ /*@only@*/
+ static int32_t * tmpoff = NULL;
+ static int tmpdelta = 64;
+ static size_t tmplen = 0;
+ int32_t oldoff = 0;
+ int firstline = 1; /* a flag to print X\n X\n- X */
+ int ret = 0; /* if a match is found it is set to 1*/
+ int i;
+
+ for (i = 0; i < nmagic; i++) {
+ m = &fm->ml->magic[i];
+ /* if main entry matches, print it... */
+ if (!fmagicSGet(fm, m) || !fmagicSCheck(fm, m)) {
+ /* main entry didn't match, flush its continuations */
+ while ((m+1)->cont_level != 0 && ++i < nmagic)
+ m++;
+ continue;
+ }
+
+ if (! firstline) { /* we found another match */
+ /* put a newline and '-' to do some simple formatting */
+ fmagicPrintf(fm, "\n- ");
+ }
+
+ if ((cont_level+1) >= tmplen) {
+ tmplen += tmpdelta;
+ tmpoff = xrealloc(tmpoff, tmplen * sizeof(*tmpoff));
+ }
+ tmpoff[cont_level] = fmagicSPrint(fm, m);
+ cont_level++;
+
+ /*
+ * If we printed something, we'll need to print
+ * a blank before we print something else.
+ */
+ if (m->desc[0])
+ need_separator = 1;
+
+ /* and any continuations that match */
+ while ((m+1)->cont_level != 0 && ++i < nmagic) {
+ m++;
+ if (cont_level < m->cont_level)
+ /*@innercontinue@*/ continue;
+ if (cont_level > m->cont_level) {
+ /* We're at the end of the level "cont_level" continuations. */
+ cont_level = m->cont_level;
+ }
+ if (m->flag & OFFADD) {
+ oldoff = m->offset;
+ m->offset += tmpoff[cont_level-1];
+ }
+ if (fmagicSGet(fm, m) && fmagicSCheck(fm, m)) {
+ /*
+ * This continuation matched.
+ * Print its message, with a blank before it if the previous
+ * item printed and this item isn't empty.
+ */
+ /* space if previous printed */
+ if (need_separator
+ && (m->nospflag == 0) && (m->desc[0] != '\0'))
+ {
+ fmagicPrintf(fm, " ");
+ need_separator = 0;
+ }
+ if ((cont_level+1) >= tmplen) {
+ tmplen += tmpdelta;
+ tmpoff = xrealloc(tmpoff, tmplen * sizeof(*tmpoff));
+ }
+ tmpoff[cont_level] = fmagicSPrint(fm, m);
+ cont_level++;
+ if (m->desc[0])
+ need_separator = 1;
+ }
+ if (m->flag & OFFADD)
+ m->offset = oldoff;
+ }
+ firstline = 0;
+ ret = 1;
+ if (!(fm->flags & FMAGIC_FLAGS_CONTINUE)) /* don't keep searching */
+ return 1;
+ }
+ return ret; /* This is hit if -k is set or there is no match */
+}
+/*@=bounds@*/
+
+/*
+ * fmagicS - lookup one file in database
+ * (already read from MAGIC by apprentice.c).
+ * Passed the name and FILE * of one file to be typed.
+ */
+int
+fmagicS(fmagic fm)
+{
+/*@-branchstate@*/
+ if (fm->mlist != NULL)
+ for (fm->ml = fm->mlist->next; fm->ml != fm->mlist; fm->ml = fm->ml->next) {
+/*@-compmempass@*/
+ if (fmagicSMatch(fm))
+ return 1;
+/*@=compmempass@*/
+ }
+/*@=branchstate@*/
+
+/*@-compmempass@*/
+ return 0;
+/*@=compmempass@*/
+}
--- /dev/null
+/*
+ * Header file for public domain tar (tape archive) program.
+ *
+ * @(#)tar.h 1.20 86/10/29 Public Domain.
+ *
+ * Created 25 August 1985 by John Gilmore, ihnp4!hoptoad!gnu.
+ *
+ * Id: tar.h,v 1.5 1999/01/13 15:44:10 christos Exp # checkin only
+ */
+
+#ifndef __tar_h__
+#define __tar_h__
+
+/*
+ * Header block on tape.
+ *
+ * I'm going to use traditional DP naming conventions here.
+ * A "block" is a big chunk of stuff that we do I/O on.
+ * A "record" is a piece of info that we care about.
+ * Typically many "record"s fit into a "block".
+ */
+#define RECORDSIZE 512
+#define NAMSIZ 100
+#define TUNMLEN 32
+#define TGNMLEN 32
+
+/*@-fielduse@*/
+union record {
+ char charptr[RECORDSIZE];
+ struct header {
+ char name[NAMSIZ];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char linkname[NAMSIZ];
+ char magic[8];
+ char uname[TUNMLEN];
+ char gname[TGNMLEN];
+ char devmajor[8];
+ char devminor[8];
+ } header;
+};
+/*@=fielduse@*/
+
+/* The checksum field is filled with this while the checksum is computed. */
+#define CHKBLANKS " " /* 8 blanks, no null */
+
+/* The magic field is filled with this if uname and gname are valid. */
+#define TARMAGIC "ustar " /* 7 chars and a null */
+
+#if 0
+/* The linkflag defines the type of file */
+#define LF_OLDNORMAL '\0' /* Normal disk file, Unix compat */
+#define LF_NORMAL '0' /* Normal disk file */
+#define LF_LINK '1' /* Link to previously dumped file */
+#define LF_SYMLINK '2' /* Symbolic link */
+#define LF_CHR '3' /* Character special file */
+#define LF_BLK '4' /* Block special file */
+#define LF_DIR '5' /* Directory */
+#define LF_FIFO '6' /* FIFO special file */
+#define LF_CONTIG '7' /* Contiguous file */
+/* Further link types may be defined later. */
+
+/*
+ * Exit codes from the "tar" program
+ */
+#define EX_SUCCESS 0 /* success! */
+#define EX_ARGSBAD 1 /* invalid args */
+#define EX_BADFILE 2 /* invalid filename */
+#define EX_BADARCH 3 /* bad archive */
+#define EX_SYSTEM 4 /* system gave unexpected error */
+
+
+/*
+ * Global variables
+ */
+extern union record *ar_block; /* Start of block of archive */
+extern union record *ar_record; /* Current record of archive */
+extern union record *ar_last; /* Last+1 record of archive block */
+extern char ar_reading; /* 0 writing, !0 reading archive */
+extern int blocking; /* Size of each block, in records */
+extern int blocksize; /* Size of each block, in bytes */
+extern char *ar_file; /* File containing archive */
+extern char *name_file; /* File containing names to work on */
+extern char *tar; /* Name of this program */
+
+/*
+ * Flags from the command line
+ */
+extern char f_reblock; /* -B */
+extern char f_create; /* -c */
+extern char f_debug; /* -d */
+extern char f_sayblock; /* -D */
+extern char f_follow_links; /* -h */
+extern char f_ignorez; /* -i */
+extern char f_keep; /* -k */
+extern char f_modified; /* -m */
+extern char f_oldarch; /* -o */
+extern char f_use_protection; /* -p */
+extern char f_sorted_names; /* -s */
+extern char f_list; /* -t */
+extern char f_namefile; /* -T */
+extern char f_verbose; /* -v */
+extern char f_extract; /* -x */
+extern char f_compress; /* -z */
+
+/*
+ * We now default to Unix Standard format rather than 4.2BSD tar format.
+ * The code can actually produce all three:
+ * f_standard ANSI standard
+ * f_oldarch V7
+ * neither 4.2BSD
+ * but we don't bother, since 4.2BSD can read ANSI standard format anyway.
+ * The only advantage to the "neither" option is that we can cmp(1) our
+ * output to the output of 4.2BSD tar, for debugging.
+ */
+#define f_standard (!f_oldarch)
+
+/*
+ * Structure for keeping track of filenames and lists thereof.
+ */
+struct name {
+ struct name *next;
+ short length;
+ char found;
+ char name[NAMSIZ+1];
+};
+
+extern struct name *namelist; /* Points to first name in list */
+extern struct name *namelast; /* Points to last name in list */
+
+extern int archive; /* File descriptor for archive file */
+extern int errors; /* # of files in error */
+
+/*
+ *
+ * Due to the next struct declaration, each routine that includes
+ * "tar.h" must also include <sys/types.h>. I tried to make it automatic,
+ * but System V has no defines in <sys/types.h>, so there is no way of
+ * knowing when it has been included. In addition, it cannot be included
+ * twice, but must be included exactly once. Argghh!
+ *
+ * Thanks, typedef. Thanks, USG.
+ */
+struct link {
+ struct link *next;
+ dev_t dev;
+ ino_t ino;
+ short linkcount;
+ char name[NAMSIZ+1];
+};
+
+extern struct link *linklist; /* Points to first link in list */
+
+/*
+ * Error recovery stuff
+ */
+extern char read_error_flag;
+#endif
+
+#endif /* __tar_h__ */