home *** CD-ROM | disk | FTP | other *** search
- Subject: v13i027: Replacement for the file(1) program, Part01/02
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: "Ian F. Darwin" <ian@sq.com>
- Posting-number: Volume 13, Issue 27
- Archive-name: file/part01
-
- This is Ian Darwin's (copyright but distributable) file(1) command. It
- follows the USG (Sys V) model of the file command, rather than the
- Research (V7) version or the V7-derived Berkeley one. 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 (with one
- exception; see the man page).
-
- : To unbundle, sh this file
- mkdir magdir tst
- echo x - LEGAL.NOTICE 1>&2
- cat >LEGAL.NOTICE <<'@@@End of LEGAL.NOTICE'
- Copyright (c) Ian F. Darwin 1986, 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.
- @@@End of LEGAL.NOTICE
- echo x - README 1>&2
- cat >README <<'@@@End of README'
- ** README for file(1) Command **
- @(#) $Header: README,v 1.9 87/11/07 12:38:30 ian Exp $
-
- This is Ian Darwin's (copyright but distributable) file(1)
- command. It follows the USG (Sys V) model of the file command,
- rather than the Research (V7) version or the V7-derived Berkeley
- one. 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 (with
- one exception; see the man page).
-
- In addition, the /etc/magic file is built from a subdirectory
- for easier maintenance. I will act as a clearinghouse for
- magic numbers assigned to all sorts of data files that
- are in reasonable circulation. Send your magic numbers,
- in magic(4) format please, to the author, Ian Darwin,
- {utzoo|ihnp4}!darwin!ian, ian@sq.com.
-
- LEGAL.NOTICE - read this first.
- README - read this second (you are currently reading this file).
- PORTING - read this only if the program won't compile.
- Makefile - read this next, adapt it as needed (particularly
- the location of the old existing file command and
- the man page layouts), type "make" to compile,
- "make try" to try it out against your old version.
- Expect some diffs, particularly since your original
- file(1) may not grok the imbedded-space ("\ ") in
- the current magic file, or may even not use the
- magic file.
- apprentice.c - parses /etc/magic to learn magic
- ascmagic.c - third & last set of tests, based on hardwired assumptions.
- core - not included in distribution due to mailer limitations.
- debug.c - includes -c printout routine
- file.1 - man page for the command
- magic.4 - man page for the magic file, courtesy Guy Harris.
- Install as magic.4 on USG and magic.5 on V7 or Berkeley; cf Makefile.
- file.c - main program
- file.h - header file
- fsmagic.c - first set of tests the program runs, based on filesystem info
- is_tar.c - knows about tarchives (courtesy John Gilmore).
- magdir - directory of /etc/magic pieces
- names.h - header file for ascmagic.c
- softmagic.c - 2nd set of tests, based on /etc/magic
- strtok.c, getopt.c - in case you them (courtesy of Henry Spencer).
- strtol.c, strchr.c - in case you need them - public domain.
- tst - simple test suite, built from tst/Makefile
- @@@End of README
- echo x - PORTING 1>&2
- cat >PORTING <<'@@@End of PORTING'
- Portability of the new file(1) command.
- @(#) $Header: PORTING,v 1.6 87/11/08 23:03:41 ian Exp $
-
- Read this file only if the program doesn't compile on your system.
-
- I have tried to make a program that doesn't need any command-line
- defines (-D) to specify what version of UNIX is in use,
- by using the definitions available in the system #include
- files. For example, the lstat(2) call is normally found in
- 4BSD systems, but might be grafted into some other variant
- of UNIX. If it's done right (ie., using the same definitions),
- my program will compile and work correctly. Look at the #ifdefs
- to see how it's done.
-
- I've also tried to include all the non-portable library routines
- I used (getopt, str*). Non-portable here means `not in every
- reasonably standard UNIX out there: V7, System V, 4BSD'.
-
- There is one area that just might cause problems. On System
- V, they moved the definition of major() and minor() out of
- <sys/types.h> into <sys/sysmacros.h>. Hence, if major isn't
- defined after including types.h, I automatically include sys/sysmacros.h.
- This will work for 99% of the systems out there. ONLY if you
- have a system in which neither types.h nor sysmacros.h defines
- `major' will this automatic include fail (I hope). On such
- systems, 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.
-
- If you are running the old Ritchie PDP-11 C compiler or
- some other compiler that doesn't know about `void', you will have
- to un-comment-out the definition of `void=int' in the Makefile.
-
- 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 for non-UNIX systems but will collect widely-used magic
- numbers for them as well as for UNIX systems.
-
- Ian Darwin
- Toronto, Canada
- @@@End of PORTING
- echo x - file.c 1>&2
- cat >file.c <<'@@@End of file.c'
- /*
- * 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 <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "file.h"
-
- #define USAGE "usage: %s [-c] [-f namefile] [-m magicfile] file...\n"
-
- #ifndef lint
- static char *moduleid =
- "@(#)$Header: file.c,v 1.14 87/11/12 13:11:06 ian Exp $";
- #endif /* lint */
- extern char *ckfmsg;
- int debug = 0, /* huh? */
- nbytes = 0, /* number of bytes read from a datafile */
- nmagic = 0; /* number of valid magic[]s */
- FILE *efopen();
- #ifdef MAGIC
- char *magicfile = MAGIC; /* where magic be found */
- #else
- char *magicfile = "/etc/magic"; /* where magic be found */
- #endif
- 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 check = 0, didsomefiles = 0, errflg = 0, ret = 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);
- ++didsomefiles;
- break;
- case 'm':
- magicfile = optarg;
- break;
- case '?':
- default:
- errflg++;
- break;
- }
- if (errflg) {
- (void) fprintf(stderr, USAGE, progname);
- exit(2);
- }
-
- ret = apprentice(magicfile, check);
- if (check)
- exit(ret);
-
- if (optind == argc) {
- if (!didsomefiles)
- (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;
-
- if (strcmp("-", inname) == 0) {
- (void) printf("standard input:\t");
- if (fstat(0, &statbuf)<0)
- warning("cannot fstat; ");
- fd = 0;
- goto readit;
- }
-
- (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) {
- /* We can't open it, but we were able to stat it. */
- if (statbuf.st_mode & 0002) ckfputs("writeable, ", stdout);
- if (statbuf.st_mode & 0111) ckfputs("executable, ", stdout);
- warning("can't read");
- } else {
- readit:
- /*
- * try looking at the first HOWMANY bytes
- */
- if ((nbytes = read(fd, buf, HOWMANY)) == -1)
- warning("read failed");
- if (nbytes == 0) {
- ckfputs("empty", stdout);
- } else
- /*
- * 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);
- }
- if (strcmp("-", inname) != 0) {
- /*
- * Restore access, modification times if we read it.
- */
- utbuf.actime = statbuf.st_atime;
- utbuf.modtime = statbuf.st_mtime;
- (void) utime(inname, &utbuf);
- /* we don't care if we lack perms */
- (void) close(fd);
- }
- }
-
- (void) putchar('\n');
- }
-
-
- @@@End of file.c
- echo x - apprentice.c 1>&2
- cat >apprentice.c <<'@@@End of apprentice.c'
- /*
- * 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 <stdio.h>
- #include <ctype.h>
- #include "file.h"
-
- #ifndef lint
- static char *moduleid =
- "@(#)$Header: apprentice.c,v 1.8 87/11/06 21:14:34 ian Exp $";
- #endif /* lint */
-
- #define MAXSTR 500
- #define EATAB {while (isascii(*l) && isspace(*l)) ++l;}
-
- extern char *progname;
- extern char *magicfile;
- extern int debug; /* option */
- extern int nmagic; /* number of valid magic[]s */
- extern long strtol();
-
- struct magic magic[MAXMAGIS];
-
- char *getstr();
-
- apprentice(fn, check)
- char *fn; /* name of magic file */
- int check; /* non-zero: checking-only run. */
- {
- FILE *f;
- char line[MAXSTR+1];
- int errs = 0;
-
- f = fopen(fn, "r");
- if (f==NULL) {
- (void) fprintf(stderr, "%s: can't read magic file %s\n",
- progname, fn);
- if (check)
- return -1;
- else
- 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]=='#') /* comment, do not parse */
- continue;
- if (strlen(line) <= 1) /* null line, garbage, etc */
- continue;
- line[strlen(line)-1] = '\0'; /* delete newline */
- if (parse(line, &nmagic, check) != 0)
- ++errs;
- }
-
- (void) fclose(f);
- return errs ? -1 : 0;
- }
-
- /*
- * parse one line from magic file, put into magic[index++] if valid
- */
- int
- parse(l, ndx, check)
- char *l;
- int *ndx, check;
- {
- int i = 0, nd = *ndx;
- int slen;
- static int warned = 0;
- struct magic *m;
- extern int errno;
-
- /*
- * TODO malloc the magic structures (linked list?) so this can't happen
- */
- if (nd+1 >= MAXMAGIS){
- if (warned++ == 0)
- warning(
- "magic table overflow - increase MAXMAGIS beyond %d in file/apprentice.c\n",
- MAXMAGIS);
- return -1;
- }
- 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 {
- errno = 0;
- warning("type %s invalid", l);
- return -1;
- }
- EATAB;
-
- if (*l == '>' || *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) {
- /*
- * Do not remove the casts below. They are vital.
- * When later compared with the data, the sign extension must
- * have happened.
- */
- case BYTE:
- m->value.l = (char) strtol(l,&l,0);
- break;
- case SHORT:
- m->value.l = (short) strtol(l,&l,0);
- break;
- case LONG:
- m->value.l = (long) strtol(l,&l,0);
- break;
- case STRING:
- l = getstr(l, m->value.s, sizeof(m->value.s), &slen);
- m->vallen = slen;
- break;
- default:
- warning("can't happen: m->type=%d\n", m->type);
- return -1;
- }
-
- /*
- * now get last part - the description
- */
- EATAB;
- while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
- /* NULLBODY */;
-
- if (check) {
- mdump(m);
- }
- ++(*ndx); /* make room for next */
- return 0;
- }
-
- /*
- * Convert a string containing C character escapes. Stop at an unescaped
- * space or tab.
- * Copy the converted version to "p", returning its length in *slen.
- * Return updated scan pointer as function result.
- */
- char *
- getstr(s, p, plen, slen)
- register char *s;
- register char *p;
- int plen, *slen;
- {
- char *origs = s, *origp = p;
- char *pmax = p + plen - 1;
- register int c;
- register int val;
-
- while((c = *s++) != '\0') {
- if (isspace(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++ = c;
- break;
-
- case 'n':
- *p++ = '\n';
- break;
-
- case 'r':
- *p++ = '\r';
- break;
-
- case 'b':
- *p++ = '\b';
- break;
-
- case 't':
- *p++ = '\t';
- break;
-
- case 'f':
- *p++ = '\f';
- break;
-
- case 'v':
- *p++ = '\v';
- break;
-
- /* \ and up to 3 octal digits */
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- val = c - '0';
- c = *s++; /* try for 2 */
- if(c >= '0' && c <= '7') {
- val = (val<<3) | (c - '0');
- c = *s++; /* try for 3 */
- if(c >= '0' && c <= '7')
- val = (val<<3) | (c-'0');
- else
- --s;
- }
- else
- --s;
- *p++ = val;
- break;
-
- /* \x and up to 3 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;
- c = hextoint(*s++);
- if (c >= 0) {
- val = (val << 4) + c;
- } else
- --s;
- } else
- --s;
- } else
- --s;
- *p++ = val;
- break;
- }
- } else
- *p++ = c;
- }
- out:
- *p = '\0';
- *slen = p - origp;
- return(s);
- }
-
-
- /* Single hex char to int; -1 if not a hex char. */
- int
- hextoint(c)
- char c;
- {
- if (!isascii(c)) return -1;
- if (isdigit(c)) return c - '0';
- if ((c>='a')&(c<='f')) return c + 10 - 'a';
- if ((c>='A')&(c<='F')) return c + 10 - 'A';
- return -1;
- }
-
-
- /*
- * Print a string containing C character escapes.
- */
- void
- showstr(s)
- register char *s;
- {
- register char c;
-
- while((c = *s++) != '\0') {
- if(c >= 040 && c <= 0176)
- putchar(c);
- else {
- putchar('\\');
- switch (c) {
-
- case '\n':
- putchar('n');
- break;
-
- case '\r':
- putchar('r');
- break;
-
- case '\b':
- putchar('b');
- break;
-
- case '\t':
- putchar('t');
- break;
-
- case '\f':
- putchar('f');
- break;
-
- case '\v':
- putchar('v');
- break;
-
- default:
- printf("%.3o", c & 0377);
- break;
- }
- }
- }
- putchar('\t');
- }
- @@@End of apprentice.c
- echo x - fsmagic.c 1>&2
- cat >fsmagic.c <<'@@@End of fsmagic.c'
- /*
- * 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 <stdio.h>
- #include <sys/types.h>
- #ifndef major /* if `major' not defined in types.h, */
- #include <sys/sysmacros.h> /* try this one. */
- #endif
- #ifndef major /* still not defined? give up, manual intervention needed */
- /* 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 <sys/stat.h>
- #include "file.h"
-
- #ifndef lint
- static char *moduleid =
- "@(#)$Header: fsmagic.c,v 1.8 88/01/15 12:13:52 ian Exp $";
- #endif /* lint */
-
- 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;
- }
-
- if (statbuf.st_mode & S_ISUID) ckfputs("setuid ", stdout);
- if (statbuf.st_mode & S_ISGID) ckfputs("setgid ", stdout);
- if (statbuf.st_mode & S_ISVTX) ckfputs("sticky ", stdout);
-
- 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;
- }
-
- @@@End of fsmagic.c
- echo x - softmagic.c 1>&2
- cat >softmagic.c <<'@@@End of softmagic.c'
- /*
- * softmagic - interpret variable magic from /etc/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 <stdio.h>
- #include "file.h"
-
- #ifndef lint
- static char *moduleid =
- "@(#)$Header: softmagic.c,v 1.7 87/11/06 11:25:31 ian Exp $";
- #endif /* lint */
-
- 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 database
- * (already read from /etc/magic by apprentice.c).
- * 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);
- char *pp, *strchr();
-
- 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:
- if ((pp=strchr(p->s, '\n')) != NULL)
- *pp = '\0';
- (void) printf(m->desc, p->s);
- break;
- default:
- warning("invalid m->type (%d) in mprint()", m->type);
- }
- }
-
- int
- mcheck(s, m)
- char *s;
- struct magic *m;
- {
- register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
- register long l = m->value.l;
- register long v;
-
- if (debug) {
- (void) printf("mcheck: %10.10s ", s);
- mdump(m);
- }
- switch (m->type) {
- case BYTE:
- v = p->b; break;
- case SHORT:
- v = p->h; break;
- case LONG:
- v = p->l; break;
- case STRING:
- l = 0;
- /* 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.
- */
- {
- register unsigned char *a = (unsigned char*)m->value.s;
- register unsigned char *b = (unsigned char*)p->s;
- register int len = m->vallen;
-
- while (--len >= 0)
- if ((v = *b++ - *a++) != 0)
- break;
- }
- break;
- default:
- warning("invalid type %d in mcheck()", m->type);
- return 0;
- }
-
- switch (m->reln) {
- case '=':
- return v == l;
- case '>':
- return v > l;
- case '<':
- return v < l;
- case '&':
- return v & l;
- default:
- warning("mcheck: can't happen: invalid relation %d", m->reln);
- return 0;
- }
- }
- @@@End of softmagic.c
- echo x - ascmagic.c 1>&2
- cat >ascmagic.c <<'@@@End of ascmagic.c'
- /*
- * 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.
- *
- * 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 <stdio.h>
- #include <ctype.h>
- #include "file.h"
- #include "names.h"
-
- #ifndef lint
- static char *moduleid =
- "@(#)$Header: ascmagic.c,v 1.5 87/09/16 14:44:45 ian Exp $";
- #endif /* lint */
-
- char *ckfmsg = "write error on output";
-
- /* 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;
- }
- }
- }
-
- switch (is_tar(buf)) {
- case 1:
- ckfputs("tar archive", stdout);
- return 1;
- case 2:
- ckfputs("POSIX 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;
- }
-
-
- @@@End of ascmagic.c
- echo x - is_tar.c 1>&2
- cat >is_tar.c <<'@@@End of is_tar.c'
- /*
- * is_tar() -- figure out whether file is a tar archive.
- *
- * Stolen (by the author!) from the public domain tar program:
- * Pubic Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
- *
- * @(#)list.c 1.18 9/23/86 Public Domain - gnu
- *
- * Comments changed and some code/comments reformatted
- * for file command by Ian Darwin.
- */
-
- #include <ctype.h>
- #include <sys/types.h>
- #include "tar.h"
-
- #define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
-
- long from_oct(); /* Decode octal number */
-
- /*
- * 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.
- */
- int
- is_tar(header)
- register union record *header;
- {
- register int i;
- register long sum, recsum;
- register char *p;
-
- recsum = from_oct(8, header->header.chksum);
-
- sum = 0;
- p = header->charptr;
- for (i = sizeof(*header); --i >= 0;) {
- /*
- * 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 (0==strcmp(header->header.magic, TMAGIC))
- return 2; /* Unix Standard tar archive */
-
- return 1; /* Old fashioned tar archive */
- }
-
-
- /*
- * Quick and dirty octal conversion.
- *
- * Result is -1 if the field is invalid (all blank, or nonoctal).
- */
- long
- from_oct(digs, where)
- register int digs;
- register char *where;
- {
- register long value;
-
- while (isspace(*where)) { /* Skip spaces */
- where++;
- if (--digs <= 0)
- return -1; /* All blank field */
- }
- value = 0;
- while (digs > 0 && isodigit(*where)) { /* Scan til nonoctal */
- value = (value << 3) | (*where++ - '0');
- --digs;
- }
-
- if (digs > 0 && *where && !isspace(*where))
- return -1; /* Ended on non-space/nul */
-
- return value;
- }
- @@@End of is_tar.c
- echo x - print.c 1>&2
- cat >print.c <<'@@@End of print.c'
- /*
- * 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 <stdio.h>
- #include <errno.h>
- #include "file.h"
-
- #ifndef lint
- static char *moduleid =
- "@(#)$Header: print.c,v 1.11 88/01/15 12:17:06 ian Exp $";
- #endif /* lint */
-
- #define MAXSTR 500
-
- extern char *progname;
- extern char *magicfile;
- extern int debug, nmagic; /* number of valid magic[]s */
- extern void showstr();
-
- 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)
- showstr(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
- */
- /*ARGSUSED1*/
- /*VARARGS*/
- void
- error(s1, s2)
- char *s1, *s2;
- {
- warning(s1, s2);
- exit(1);
- }
-
- /*ARGSUSED1*/
- /*VARARGS*/
- warning(f, a)
- char *f, *a;
- {
- extern int errno, sys_nerr;
- extern char *sys_errlist[];
- int myerrno;
-
- myerrno = errno;
-
- /* cuz we use stdout for most, stderr here */
- (void) fflush(stdout);
-
- if (progname != NULL) {
- (void) fputs(progname, stderr);
- (void) putc(':', stderr);
- (void) putc(' ', stderr);
- }
- (void) fprintf(stderr, f, a);
- if (myerrno > 0 && myerrno < sys_nerr)
- (void) fprintf(stderr, " (%s)", sys_errlist[myerrno]);
- putc('\n', stderr);
- }
- @@@End of print.c
- echo x - getopt.c 1>&2
- cat >getopt.c <<'@@@End of getopt.c'
-
- /*
- * getopt - get option letter from argv
- *
- * Copyright (c) Henry Spencer.
- * Written by Henry Spencer.
- *
- * 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.
- */
-
- /*
- * changed index() calls to strchr() - darwin, oct 87.
- */
-
- #include <stdio.h>
-
- char *optarg; /* Global argument pointer. */
- int optind = 0; /* Global argv index. */
-
- static char *scan = NULL; /* Private scan pointer. */
-
- extern char *strchr();
-
- int
- getopt(argc, argv, optstring)
- int argc;
- char *argv[];
- char *optstring;
- {
- register char c;
- register char *place;
-
- optarg = NULL;
-
- if (scan == NULL || *scan == '\0') {
- if (optind == 0)
- optind++;
-
- if (optind >= argc || argv[optind][0] != '-' || argv[optind][1] == '\0')
- return(EOF);
- if (strcmp(argv[optind], "--")==0) {
- optind++;
- return(EOF);
- }
-
- scan = argv[optind]+1;
- optind++;
- }
-
- c = *scan++;
- place = strchr(optstring, c);
-
- if (place == NULL || c == ':') {
- fprintf(stderr, "%s: unknown option -%c\n", argv[0], c);
- return('?');
- }
-
- place++;
- if (*place == ':') {
- if (*scan != '\0') {
- optarg = scan;
- scan = NULL;
- } else if (optind < argc) {
- optarg = argv[optind];
- optind++;
- } else {
- fprintf(stderr, "%s: -%c argument missing\n", argv[0], c);
- return('?');
- }
- }
-
- return(c);
- }
- @@@End of getopt.c
- echo x - strtol.c 1>&2
- cat >strtol.c <<'@@@End of strtol.c'
- /*
- * strtol - convert string to long integer.
- *
- * Written by reading the System V Interface Definition, not the code.
- *
- * Totally public domain.
- *
- * Compile with -DTEST to get short interactive main() for testing.
- */
-
- #include <stdio.h>
- #include <ctype.h>
-
- long
- strtol(s, p, b)
- char *s, **p;
- int b;
- {
- int base = 10, n = 0, sign = 1, valid = 1;
-
- /*
- * leading sign?
- */
- if (*s=='-')
- sign=(-1);
- else
- sign=1;
- if (*s=='+' || *s=='-')
- ++s; /* skip sign */
-
- /*
- * what base are we really using?
- */
- if (b == 0) {
- if (strncmp(s, "0x", 2) == 0 ||
- strncmp(s, "0X", 2) == 0) {
- s += 2;
- base = 16;
- } else
- if (*s == '0')
- base = 8;
- }
-
- /*
- * convert the string to a number.
- */
- while (isascii(*s) && valid) {
- switch(*s) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- n = base*n + *s-'0';
- break;
- case '8':
- case '9':
- if (base >8)
- n = base*n + *s-'0';
- else
- valid = 0;
- break;
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- if (base == 16)
- n = base*n + *s-'a'+10;
- else
- valid = 0;
- break;
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- if (base == 16)
- n = base*n + *s-'A'+10;
- else
- valid = 0;
- break;
- default:
- valid = 0;
- break;
- }
- ++s;
- }
-
- /*
- * if arg `p' is not NULL, a ptr to the character
- * terminating the scan will be returned in `p'
- */
- if (*p != NULL)
- *p = s;
-
- return sign * n;
- }
-
- #ifdef TEST
- main(argc, argv)
- int argc;
- char **argv;
- {
- int i;
- long j, strtol();
-
- for (i=1; i<argc; i++) {
- j = strtol(argv[i], 0, 0);
- printf("%s -> %ld(%lx)\n", argv[i], j, j);
- }
- exit(0);
- }
- #endif /*TEST*/
- @@@End of strtol.c
-
-