From: Ian Darwin Date: Sun, 23 Aug 1987 19:51:03 +0000 (+0000) Subject: Initial revision X-Git-Tag: FILE3_27~438 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8136dbd62eb3aea8a8ce865c7cb2c0a87c183e2b;p=file Initial revision --- 8136dbd62eb3aea8a8ce865c7cb2c0a87c183e2b diff --git a/LEGAL.NOTICE b/LEGAL.NOTICE new file mode 100644 index 00000000..12e56457 --- /dev/null +++ b/LEGAL.NOTICE @@ -0,0 +1,29 @@ +Written by Ian Darwin, +Box 603, Station F, Toronto, CANADA M4Y 2L8. +Uucp: {utzoo|ihnp4}!darwin!ian. +Internet: ian@sq.com (proposed). + +Copyright (c) 1986, Ian Darwin. All rights reserved, except as noted below. + +This program may be used for its intended purpose on any computer system. + + *** Unmodified copies *** +of the source may be freely copied for this purpose +provided this notice is maintained. + *** Redistribution of modified source copies is prohibited; *** +distribute the original source with your changes as diff listings +or as RCS archives (or SCCS if you can find a way to mail them). +Please send me your changes; if I like 'em I'll incorporate them. + +Binary copies may also be distributed; if they are derived from +modified source then you must inform every recipient of the +origin of the program and that the source is available from the author. + +The module is_tar.c is by Fred Blonder at the University of Maryland +and appeared as part of his fixes to the UNIX file(1) program +in net.sources; it is not covered by the above restrictions. + +The module strtok.c is by Henry Spencer at the University of Toronto +and is not covered by the above restrictions. + +The module strtol is a quick hack and is not covered by the above. diff --git a/README b/README new file mode 100644 index 00000000..1dca6f38 --- /dev/null +++ b/README @@ -0,0 +1,43 @@ +** ALPHA TEST RELEASE ** +You are getting this ahead of the rest of the world because +you need it or because I like you or something. Please do not +forward it to anybody yet. The "official" version will appear +in mod.sources at a theater or USENET site near you in time +for the Christmas rush. + +** File(1) Command ** +This is Ian Darwin's (copyright but distributable unmodified) +file(1) command. It follows the USG (Sys V) model of the file +command, rather than the Research (V7) version. That is, there +is a file (/etc/magic) that contains much of the ritual information +that is the source of this program's power. It knows a little +more magic (including tar archives) than System V; the /etc/magic +parsing seems to be compatible with the (poorly documented) +System V /etc/magic format. + +In addition, the /etc/magic file is built from a subdirectory +for easier maintenance. At the instigation of John Gilmore, +I will act as a clearinghouse for magic numbers assigned to +all sorts of whacko data files that are in reasonable circulation. +Send your whacko magic numbers, in file(5) format please(!), to the +address above. + +LEGAL.NOTICE - read this first. +README - read this second. +Makefile - read this third. +TODO - read this last (sigh). +apprentice.c - parses /etc/magic to learn magic +ascmagic.c - third & last set of tests, based on hardwired assumptions. +core - not included in distribution +debug.c - includes -c printout routine +file.1 - man page +file.c - main program +file.h - fairly standard header file +fsmagic.c - first set of tests the program runs, based on filesystem info +is_tar.c - knows about tarchives (courtesy of Fred Blonder, U Maryland) +magdir - directory of /etc/magic pieces +names.h - header file for ascmagic.c +softmagic.c - 2nd set of tests, based on /etc/magic +strtol.c - in case you need it +strtol.tst.c - in case you need to test it + diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..2d73011e --- /dev/null +++ b/src/Makefile @@ -0,0 +1,41 @@ +# Makefile for file(1) cmd. Copyright (c) Darwin 86/09/01 - see LEGAL.NOTICE. + +DEFS = # -Dvoid=int +CFLAGS = -O $(DEFS) +OTHERS = darwin!ian # people to whom we mail updates +FILE=/usr/bin/file.sun # old version or system-provided command, for comparison + +# There are no system-dependant configuration options (except maybe CFLAGS); +# you may delete some of LOCALSRCS and LOCALOBJS if they're in your C library. +LOCALSRCS = strtol.c strtok.c +SRCS = file.c apprentice.c fsmagic.c softmagic.c ascmagic.c is_tar.c \ + print.c $(LOCALSRCS) +LOCALOBJS = strtol.o strtok.o +OBJS = file.o apprentice.o fsmagic.o softmagic.o ascmagic.o is_tar.o \ + print.o $(LOCALOBJS) + +ALLSRC = LEGAL.NOTICE README PORTING TODO $(SRCS) *.h \ + Makefile file.[15] magdir tst/Makefile + +run: file magic + time $(FILE) -m ./magic * tst/* >/tmp/t1 + time ./file -m ./magic * tst/* >/tmp/t2 + diff -b /tmp/t[12] + +file: $(OBJS) + cc $(CFLAGS) $(OBJS) -o $@ +lint: $(SRCS) + lint -ha $(DEFS) $(SRCS) +magic: magdir + cat magdir/[a-z]* >$@ # exclude RCS or SCCS dirs + +ascmagic.o: names.h + +apprentice.o ascmagic.o file.o fsmagic.o print.o softmagic.o: file.h + +dist: $(ALLSRC) + (echo mkdir tst; bundle $(ALLSRC)) | \ + mailx -s 'semi-public-domain file(1)' $(OTHERS) +update: $(ALLSRC) + (echo mkdir tst; bundle $?; echo touch $@) | mail $(OTHERS) + touch $@ diff --git a/src/PORTING b/src/PORTING new file mode 100644 index 00000000..1eacce7b --- /dev/null +++ b/src/PORTING @@ -0,0 +1,28 @@ +Portability of the new file(1) command. + +Obviously if you are running the old Ritchie compiler or +something else that doesn't know about void, you will have +to un-comment-out the definition of `void=int' in the Makefile. + +I had hoped to be able to make a file command that +didn't have any system-dependant #ifdefs, no special libraries, +etc., etc. Well, System V shot me down. They moved the definition +of major() and minor() out of into . +So, if major isn't defined after including types.h, I automatically +include sys/sysmacros.h. If you have a system in which neither +types.h nor sysmacros.h defines `major', you will get a compilation +error in trying to compile a warning message. Please do the following: + 1) change the appropriate (2nd) #include at the start of + fsmagic.c +and 2) let me know the name of the system, the release number, + and the name of the header file that *does* include + this "standard" definition. + +Other than this, there should be no portability problems, +but one never knows these days. Please let me know of any +other problems you find porting to a UNIX system. I don't much +care about non-UNIX systems but will collect magic numbers +for them. + +Ian Darwin +Toronto, Canada diff --git a/src/apprentice.c b/src/apprentice.c new file mode 100644 index 00000000..9b5d15e2 --- /dev/null +++ b/src/apprentice.c @@ -0,0 +1,142 @@ +/* + * make one pass through /etc/magic, reading it into core + */ + +#include +#include +#include "file.h" + +#define MAXSTR 500 +#define EATAB {while (isascii(*l) && *l == '\t') ++l;} + +extern char *progname; +extern char *magicfile; +extern int debug, check; /* options */ +extern int nmagic; /* number of valid magic[]s */ +extern long strtol(); + +struct magic magic[MAXMAGIS]; + +apprentice(fn) +char *fn; +{ + FILE *f; + char line[MAXSTR+1]; + + f = fopen(fn, "r"); + if (f==NULL) { + (void) fprintf(stderr, "%s: can't read magic file %s\n", + progname, fn); + exit(1); + } + + /* parse it */ + if (check) /* print silly verbose header for USG compat. */ + (void) printf("cont\toffset\ttype\topcode\tvalue\tdesc\n"); + while (fgets(line, MAXSTR, f) != NULL) { + if (line[0]=='#') + continue; + line[strlen(line)-1] = '\0'; /* nuke newline */ + (void) parse(line, &nmagic); + } + + (void) fclose(f); +} + +/* + * parse one line from magic file, put into magic[index++] if valid + */ + + +parse(l, ndx) +char *l; +int *ndx; +{ + int i = 0, nd = *ndx; + static int warned = 0; + struct magic *m; + + if (nd+1 >= MAXMAGIS){ + if (warned++ == 0) + warning("magic tab overflow - increase MAXMAGIS beyond %d in file/apprentice.c\n", MAXMAGIS); + return 0; + } + m = &magic[*ndx]; + + if (*l == '>') { + ++l; /* step over */ + m->contflag = 1; + } else + m->contflag = 0; + + /* get offset, then skip over it */ + m->offset = atoi(l); + while (isascii(*l) && isdigit(*l)) + ++l; + EATAB; + +#define NBYTE 4 +#define NSHORT 5 +#define NLONG 4 +#define NSTRING 6 + /* get type, skip it */ + 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 { + warning("type %s invalid\n", l); + return 0; + } + EATAB; + + if (*l == '>' || *l == '&' || *l == '=') { + m->reln = *l; + ++l; + } else + m->reln = '='; + EATAB; + +/* TODO finish this macro and start using it! */ +#define offsetcheck {if (offset > HOWMANY-1) warning("offset too big"); } + switch(m->type) { + case BYTE: + m->value.l = strtol(l,&l,0); + break; + case SHORT: + m->value.l = strtol(l,&l,0); + break; + case LONG: + m->value.l = strtol(l,&l,0); + break; + case STRING: + /* TODO check return from sscanf (system dependant?) */ + (void) sscanf(l, "%[^\t]", m->value.s); + l += strlen(m->value.s); + break; + default: + warning("can't happen: m->type=%d\n", m->type); + } + + /* + * now get last part - the description + */ + EATAB; + while ((m->desc[i++] = *l++) != '\0' && i +#include +#include "file.h" +char ckfmsg[] = "write error on output"; +#include "names.h" + + /* an optimisation over plain strcmp() */ +#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) + +ascmagic(buf) +register char *buf; +{ + register int i; + char *s, *strtok(), *token; + register struct names *p; + extern int nbytes; + short has_escapes = 0; + + /* these are easy, do them first */ + + /* + * for troff, look for . + letter + letter; + * this must be done to disambiguate tar archives' ./file + * and other trash from real troff input. + */ + if (*buf == '.' && + isascii(*(buf+1)) && isalnum(*(buf+1)) && + isascii(*(buf+2)) && isalnum(*(buf+2))){ + ckfputs("troff or preprocessor input text", stdout); + return 1; + } + if ((*buf == 'c' || *buf == 'C') && + isascii(*(buf + 1)) && isspace(*(buf + 1))) { + ckfputs("fortran program text", stdout); + return 1; + } + + /* look for tokens from names.h - this is expensive! */ + s = buf; + while ((token = strtok(s, " \t\n\r\f")) != NULL) { + s = NULL; /* make strtok() keep on tokin' */ + for (p = names; p < names + NNAMES; p++) { + if (STREQ(p->name, token)) { + ckfputs(types[p->type], stdout); + return 1; + } + } + } + + if (is_tar(buf)) { + ckfputs("tar archive", stdout); + return 1; + } + + for (i = 0; i < nbytes; i++) { + if (!isascii(*(buf+i))) + return 0; /* not all ascii */ + if (*(buf+i) == '\033') /* ascii ESCAPE */ + has_escapes ++; + } + + /* all else fails, but it is ascii... */ + if (has_escapes){ + ckfputs("ascii text (with escape sequences)", stdout); + } + else { + ckfputs("ascii text", stdout); + } + return 1; +} + + diff --git a/src/file.c b/src/file.c new file mode 100644 index 00000000..66cb4cb5 --- /dev/null +++ b/src/file.c @@ -0,0 +1,151 @@ +/* + * file - find type of a file or files + */ + +#include +#include +#include +#include "file.h" + +#define USAGE "usage: %s [-f file] [-m magicfile] file...\n" + +extern char *ckfmsg; +int check = 0, /* check format of magic file */ + debug = 0, /* huh? */ + nbytes = 0, /* number of bytes read from a datafile */ + nmagic = 0; /* number of valid magic[]s */ +FILE *efopen(); +char *magicfile = "/etc/magic"; /* where magic be found */ +char *progname; +struct stat statbuf; +struct utimbuf { /* for utime(2), belongs in a .h file */ + time_t actime; /* access time */ + time_t modtime; /* modification time */ +}; + +/* + * main - parse arguments and handle options + */ +main(argc, argv) +int argc; +char *argv[]; +{ + int c; + int errflg = 0; + extern int optind; + extern char *optarg; + + progname = argv[0]; + + while ((c = getopt(argc, argv, "cdf:m:")) != EOF) + switch (c) { + case 'c': + ++check; + break; + case 'd': + ++debug; + break; + case 'f': + unwrap(optarg); + break; + case 'm': + magicfile = optarg; + break; + case '?': + default: + errflg++; + break; + } + if (errflg) { + (void) fprintf(stderr, USAGE, progname); + exit(2); + } + + apprentice(magicfile); + + if (optind == argc) + (void)fprintf(stderr, USAGE, progname); + else + for (; optind < argc; optind++) + process(argv[optind]); + + exit(0); +} + +/* + * unwrap -- read a file of filenames, do each one. + */ +unwrap(fn) +char *fn; +{ +#define FILENAMELEN 128 + char buf[FILENAMELEN]; + FILE *f; + + if ((f = fopen(fn, "r")) == NULL) + (void) fprintf(stderr, "%s: file %s unreadable\n", + progname, fn); + else { + while (fgets(buf, FILENAMELEN, f) != NULL) { + buf[strlen(buf)-1] = '\0'; + process(buf); + } + (void) fclose(f); + } +} + +/* + * process - process input file + */ +process(inname) +char *inname; +{ + int fd; + char buf[HOWMANY]; + struct utimbuf utbuf; + + (void) printf("%s:\t", inname); + + /* + * first try judging the file based on its filesystem status + * Side effect: fsmagic updates global data `statbuf'. + */ + if (fsmagic(inname) != 0) { + /*NULLBODY*/; + } else if ((fd = open(inname, 0)) < 0) { + warning("can't open for reading"); + } else { + /* + * try looking at the first HOWMANY bytes + */ + if ((nbytes = read(fd, buf, HOWMANY)) == -1) + warning("read failed"); + /* + * try tests in /etc/magic (or surrogate magic file + */ + if (softmagic(buf) == 1) + /*NULLBODY*/; + else if (ascmagic(buf) == 1) + /* + * try known keywords, check for ascii-ness too. + */ + /*NULLBODY*/; + else { + /* + * abandon hope, all ye who remain here + */ + ckfputs("data", stdout); + } + /* + * Restore access, modification times if we read the file. + */ + utbuf.actime = statbuf.st_atime; + utbuf.modtime = statbuf.st_mtime; + (void) utime(inname, &utbuf); /* don't care if we lack perms */ + (void) close(fd); + } + + (void) putchar('\n'); +} + + diff --git a/src/file.h b/src/file.h new file mode 100644 index 00000000..d15bfd28 --- /dev/null +++ b/src/file.h @@ -0,0 +1,29 @@ +/* + * definitions for file(1) program: + */ + +#define HOWMANY 1024 /* how much of the file to look at */ +#define MAXMAGIS 250 /* max entries in /etc/magic */ +#define MAXDESC 50 /* max leng of text description */ +#define MAXstring 32 /* max leng of "string" types */ +#define ckfputs(str,fil) {if (fputs(str,fil)==EOF) error(ckfmsg,"");} + +struct magic { + short contflag; /* 1 if '>0' appears */ + long offset; /* offset to magic number */ + char reln; /* relation (0=.eq, '>'=gt, etc) */ + short type; /* int, short, long or string. */ +#define BYTE 1 +#define SHORT 2 +#define LONG 4 +#define STRING 5 + union VALUETYPE { + char b; + short h; + long l; + char s[MAXstring]; + } value; /* either number or string */ + char desc[MAXDESC]; /* description */ +}; + +extern void error(), exit(); diff --git a/src/fsmagic.c b/src/fsmagic.c new file mode 100644 index 00000000..541a3545 --- /dev/null +++ b/src/fsmagic.c @@ -0,0 +1,88 @@ +/* + * magic based on mode of file - directory, special files, etc. + */ + +#include +#include +#ifndef major /* if `major' not defined in types.h, */ +#include /* try this one. */ +#endif +#ifndef major + /* If cc tries to compile this, read and act on it. */ + /* On most systems cpp will discard it automatically */ + Congratulations, you have found a portability bug. + Please grep /usr/include/sys and edit the above #include + to point at the file that defines the `major' macro. +#endif /*major*/ +#include +#include "file.h" + +#define USAGE "usage: %s [-f file] [-m magicfile] file...\n" + +extern char *progname; +extern char *ckfmsg, *magicfile; +extern int debug; +extern FILE *efopen(); + +fsmagic(fn) +char *fn; +{ + extern struct stat statbuf; + + /* + * Fstat is cheaper but fails for files you don't have read perms on. + * On 4.2BSD and similar systems, use lstat() so identify symlinks. + */ +#ifdef S_IFLNK + if (lstat(fn, &statbuf) <0) +#else + if (stat(fn, &statbuf) <0) +#endif + { + warning("can't stat"); + return -1; + } + switch (statbuf.st_mode & S_IFMT) { + case S_IFDIR: + ckfputs("directory", stdout); + return 1; + case S_IFCHR: + (void) printf("character special (%d/%d)", + major(statbuf.st_rdev), minor(statbuf.st_rdev)); + return 1; + case S_IFBLK: + (void) printf("block special (%d/%d)", + major(statbuf.st_rdev), minor(statbuf.st_rdev)); + return 1; + /* TODO add code to handle V7 MUX and Blit MUX files */ +#ifdef S_IFIFO + case S_IFIFO: + ckfputs("fifo (named pipe)", stdout); + return 1; +#endif +#ifdef S_IFLNK + case S_IFLNK: + ckfputs("symbolic link", stdout); + return 1; +#endif +#ifdef S_IFSOCK + case S_IFSOCK: + ckfputs("socket", stdout); + return 1; +#endif + case S_IFREG: + break; + default: + warning("invalid st_mode %d in statbuf!", statbuf.st_mode); + } + + /* + * regular file, check next possibility + */ + if (statbuf.st_size == 0) { + ckfputs("empty", stdout); + return 1; + } + return 0; +} + diff --git a/src/is_tar.c b/src/is_tar.c new file mode 100644 index 00000000..7f840624 --- /dev/null +++ b/src/is_tar.c @@ -0,0 +1,44 @@ +/* + * istar() - see if it is a tar file. Found in code written by + * Fred Blonder (301) 454-7690 + * harpo!seismo!umcp-cs!fred + * Fred@Maryland.ARPA + * Net.sources, <9@gyre.uucp>, October 1983 + * I changed the calling sequence, added a cast or two, and ran through cb -sj. + */ + +is_tar(buf) /* Is it a tar file? */ +char *buf; +{ + /* This stuff is copied from tar.c. */ +#define TBLOCK 512 +#define NAMSIZ 100 + register 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]; + }; + register comp_chksum; + register char *cp; + int header_chksum; + + /* Compute checksum */ + comp_chksum = 0; + for (cp = buf; cp < &buf[TBLOCK]; cp++) + comp_chksum += (cp < ((struct header *)buf)->chksum + || cp >= &((struct header *)buf)->chksum[8]) ? + *cp : ' '; + + /* Convert checksum field to integer */ + (void) sscanf(((struct header *)buf)->chksum, "%o", &header_chksum); + + return (comp_chksum == header_chksum); /* Is checksum correct? */ +} + + diff --git a/src/names.h b/src/names.h new file mode 100644 index 00000000..d7499f36 --- /dev/null +++ b/src/names.h @@ -0,0 +1,65 @@ +/* + * 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 /etc/magic must + * appear at fixed offsets into the file. Don't make HOWMANY + * too high unless you have a very fast CPU. + */ + +/* these types are used to index the table 'types': keep em in sync! */ +#define L_C 0 /* first and foremost on UNIX */ +#define L_FORT 1 /* the oldest one */ +#define L_MAKE 2 /* Makefiles */ +#define L_PLI 3 /* PL/1 */ +#define L_MACH 4 /* some kinda assembler */ +#define L_ENG 5 /* English */ +#define L_PAS 6 /* Pascal */ + +char *types[] = { + "c program text", + "fortran program text", + "makefile commands text" , + "pl/1 (blech) program text", + "assembler (blech) program text", + "english text", + "pascal program text", + "can't happen error on names.h/types", + 0}; + +struct names { + char *name; + short type; +} names[] = { + /* These must be sorted by eye for optimal hit rate */ + /* Add to this list only after substantial meditation */ + {"/*", L_C}, + {"#include", L_C}, + {"char", L_C}, + {"The", L_ENG}, + {"double", L_C}, + {"extern", L_C}, + {"float", L_C}, + {"real", L_C}, + {"struct", L_C}, + {"union", L_C}, + {"CFLAGS", L_MAKE}, + {"LDFLAGS", L_MAKE}, + {"all:", L_MAKE}, + {".PRECIOUS", L_MAKE}, + {"subroutine", L_FORT}, + {"function", L_FORT}, + {"block", L_FORT}, + {"common", L_FORT}, + {"dimension", L_FORT}, + {"integer", L_FORT}, + {"data", L_FORT}, + {".ascii", L_MACH}, + {".asciiz", L_MACH}, + {".byte", L_MACH}, + {".even", L_MACH}, + {".globl", L_MACH}, + {"clr", L_MACH}, + {"(input,", L_PAS}, + {"dcl", L_PLI}, + 0}; +#define NNAMES ((sizeof(names)/sizeof(struct names)) - 1) diff --git a/src/print.c b/src/print.c new file mode 100644 index 00000000..0226e25a --- /dev/null +++ b/src/print.c @@ -0,0 +1,55 @@ +/* + * Debugging printout routines + */ + +#include +#include +#include "file.h" + +#define MAXSTR 500 + +extern char *progname; +extern char *magicfile; +extern int debug, nmagic; /* number of valid magic[]s */ + +mdump(m) +struct magic *m; +{ + (void) printf("%d\t%d\t%d\t%c\t", + m->contflag, + m->offset, + m->type, + m->reln, + 0); + if (m->type == STRING) + (void) printf("%s",m->value.s); + else + (void) printf("%d",m->value.l); + (void) printf("\t%s", m->desc); + (void) putchar('\n'); +} + +/* + * error - print best error message possible and exit + */ +void +error(s1, s2) +char *s1, *s2; +{ + warning(s1, s2); + exit(1); +} + +/*VARARGS*/ +warning(f, a) +char *f, *a; +{ + extern int errno, sys_nerr; + extern char *sys_errlist[]; + int myerrno; + + myerrno = errno; + (void) printf(f, a); + if (myerrno > 0 && myerrno < sys_nerr) + (void) printf(" (%s)", sys_errlist[myerrno]); +} diff --git a/src/softmagic.c b/src/softmagic.c new file mode 100644 index 00000000..6cb7d914 --- /dev/null +++ b/src/softmagic.c @@ -0,0 +1,148 @@ +/* + * variable magic from /etc/magic + */ + +#include +#include "file.h" + +#define USAGE "usage: %s [-f file] [-m magicfile] file...\n" + +extern char *progname; +extern char *magicfile; /* name of current /etc/magic or clone */ +extern int debug, nmagic; +extern FILE *efopen(); +extern struct magic magic[]; +static int magindex; + +/* + * softmagic - lookup one file in /etc/magic database. + * Passed the name and FILE * of one file to be typed. + */ +softmagic(buf) +char *buf; +{ + magindex = 0; + if (match(buf)) + return 1; + + return 0; +} + +/* + * go through the whole list, stopping if you find a match. + * Be sure to process every continuation of this match. + */ +match(s) +char *s; +{ + while (magindex < nmagic) { + /* if main entry matches, print it... */ + if (mcheck(s, &magic[magindex])) { + mprint(&magic[magindex],s); + /* and any continuations that match */ + while (magic[magindex+1].contflag && + magindex < nmagic) { + ++magindex; + if (mcheck(s, &magic[magindex])){ + (void) putchar(' '); + mprint(&magic[magindex],s); + } + } + return 1; /* all through */ + } else { + /* main entry didn't match, flush its continuations */ + while (magic[magindex+1].contflag && + magindex < nmagic) { + ++magindex; + } + } + ++magindex; /* on to the next */ + } + return 0; /* no match at all */ +} + + +mprint(m,s) +struct magic *m; +char *s; +{ + register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset); + + switch (m->type) { + case BYTE: + (void) printf(m->desc, p->b); + break; + case SHORT: + (void) printf(m->desc, p->h); + break; + case LONG: + (void) printf(m->desc, p->l); + break; + case STRING: + (void) printf(m->desc, p->s); + break; + default: + warning("invalid m->type (%d) in mprint()", m->type); + } +} + +mcheck(s, m) +char *s; +struct magic *m; +{ + register char reln = m->reln; + register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset); + register long l = m->value.l; + + if (debug) { + (void) printf("mcheck: %10.10s ", s); + mdump(m); + } + switch (m->type) { + case BYTE: + if (reln == '>') + return p->b > l; + if (reln == '&') + return l & p->b; + if (reln == '=') + return l == p->b; + warning("mcheck: can't happen: invalid BYTE reln %d", reln); + return 0; + case SHORT: + if (reln == '=') + return l == p->h; + if (reln == '>') + return p->h > l; + if (reln == '&') + return l & p->h; + warning("mcheck: can't happen: invalid SHORT reln %d", reln); + return 0; + case LONG: + if (reln == '=') + return l == p->l; + if (reln == '>') + return p->l > l; + if (reln == '&') + return l & p->l; + warning("mcheck: can't happen: invalid LONG reln %d", reln); + return 0; + case STRING: + if (reln == '=') + return strncmp(m->value.s, p->s, + strlen(m->value.s)) == 0; + if (reln == '>') + if (strcmp(m->value.s, "0") == 0) /* special case! */ + return *s > '\0'; + else + return strncmp(m->value.s, p->s, + strlen(m->value.s)) > 0; + warning("mcheck: can't happen: invalid STRING reln %c(0%o)", + reln, reln); + return 0; + default: + warning("invalid type %d in mcheck()", m->type); + return 0; + } +} + +