summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorjtc <jtc@NetBSD.org>1993-06-10 00:37:55 +0000
committerjtc <jtc@NetBSD.org>1993-06-10 00:37:55 +0000
commitebefd0d08f67d607cf2c3de3e29eebefa732d0f6 (patch)
treecc513781643290d7ffa886bd58cb9b81cd5f10a0 /usr.bin
parentf6779cbdcef13546d3ccf87a68698916e9bda1d2 (diff)
Updated to Ian Darwin's latest release.
Adds lots of neat features from most other vendors file(1) commands, plus (important!) little and big endian file types. This will alow us to detect and extract meaningful information from a many more file types.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/file/LEGAL.NOTICE23
-rw-r--r--usr.bin/file/MAINT33
-rw-r--r--usr.bin/file/Makefile30
-rw-r--r--usr.bin/file/PORTING48
-rw-r--r--usr.bin/file/README68
-rw-r--r--usr.bin/file/apprentice.c325
-rw-r--r--usr.bin/file/ascmagic.c76
-rw-r--r--usr.bin/file/compress.c86
-rw-r--r--usr.bin/file/file.1173
-rw-r--r--usr.bin/file/file.c256
-rw-r--r--usr.bin/file/file.h85
-rw-r--r--usr.bin/file/fsmagic.c119
-rw-r--r--usr.bin/file/is_tar.c17
-rw-r--r--usr.bin/file/magic.5117
-rw-r--r--usr.bin/file/names.h14
-rw-r--r--usr.bin/file/patchlevel.h34
-rw-r--r--usr.bin/file/print.c155
-rw-r--r--usr.bin/file/softmagic.c234
-rw-r--r--usr.bin/file/tar.h2
19 files changed, 1416 insertions, 479 deletions
diff --git a/usr.bin/file/LEGAL.NOTICE b/usr.bin/file/LEGAL.NOTICE
index f466b8f4e02..f65192ff7f3 100644
--- a/usr.bin/file/LEGAL.NOTICE
+++ b/usr.bin/file/LEGAL.NOTICE
@@ -1,8 +1,16 @@
-Copyright (c) Ian F. Darwin 1986, 1987.
-Written by Ian F. Darwin.
+Copyright (c) Ian F. Darwin 1986, 1987, 1989, 1990, 1991, 1992.
+Written by Ian F. Darwin and others.
+$Id: LEGAL.NOTICE,v 1.2 1993/06/10 00:37:55 jtc Exp $
-This software is not subject to any license of the American Telephone
-and Telegraph Company or of the Regents of the University of California.
+This software is not subject to and may not be made subject to any
+license of the American Telephone and Telegraph Company (AT&T Inc.),
+UNIX System Laboratories (USL Inc.), Novell Inc., Sun Microsystems
+Inc., Digital Equipment Inc., Lotus Development Inc., the Regents of
+the University of California, The X Consortium or MIT, or The Free
+Software Foundation.
+
+This software is not subject to any export provision of the United States
+Department of Commerce, and may be exported to any country or planet.
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
@@ -20,3 +28,10 @@ to the following restrictions:
ever read sources, credits must appear in the documentation.
4. This notice may not be removed or altered.
+
+UNIX is a trademark of UNIX System Laboratories (which is probably a
+subsidiary of Novell, Inc., by the time you read this). The name "UNIX"
+may not be used by commercial undertakings without permission in
+writing from USL. Just ask BSDI (Berkeley Software Design Inc.), a
+commercial venture not officially connected with the University of
+California at Berkeley.
diff --git a/usr.bin/file/MAINT b/usr.bin/file/MAINT
new file mode 100644
index 00000000000..7a0411c9064
--- /dev/null
+++ b/usr.bin/file/MAINT
@@ -0,0 +1,33 @@
+$Id: MAINT,v 1.1 1993/06/10 00:37:57 jtc Exp $
+
+Maintenance notes:
+
+I am continuing to maintain the file command. I welcome your help,
+but to make my life easier I'd like to request the following:
+
+- Don't change the version numbers!
+
+If your changes are extensive, I will have to work hard to
+integrate them into my version. If you check it into SCCS locally,
+the version numbers will likely be kept. IF you check it into RCS
+or CVS locally, please use -k to keep the version numbers, and
+please use branch deltas (1.21.1, 1.21.2, ...). If you don't do
+this, I will likely be unable to use your changes; life's just too
+short.
+
+- Do not distribute changed versions.
+
+People trying to be helpful occasionally put up their hacked versions
+of the file command for FTP, then the "archie" server finds and publishes
+the hacked version, and people all over the world get copies of it.
+Within a day or two I am getting email from around the world
+asking me why "my" file command won't compile!!! Needless to say this
+detracts from the limited time I have available to work on the actual
+software. Therefore I ask you again to please NOT distribute
+your changed version.
+
+
+Thank you for your assistance and cooperation.
+
+Ian Darwin.
+ian@sq.com
diff --git a/usr.bin/file/Makefile b/usr.bin/file/Makefile
index b95624c437c..0d6214de0f0 100644
--- a/usr.bin/file/Makefile
+++ b/usr.bin/file/Makefile
@@ -1,16 +1,26 @@
-PROG= file
-MAGIC = /etc/magic
-CFLAGS+= -DMAGIC='"$(MAGIC)"'
-SRCS= file.c apprentice.c fsmagic.c softmagic.c ascmagic.c is_tar.c \
- print.c $(LOCALSRCS)
-MAN5= magic.0
-MAN1= file.0
+MAGIC= /etc/magic
+MAGICOWN= bin
+MAGICGRP= bin
+MAGICMODE= 444
-ascmagic.o: names.h
+PROG= file
+SRCS= file.c apprentice.c fsmagic.c softmagic.c ascmagic.c is_tar.c \
+ print.c compress.c
+CFLAGS+= -DMAGIC='"$(MAGIC)"'
+MAN1= file.0
+MAN5= magic.0
-apprentice.o ascmagic.o file.o fsmagic.o print.o softmagic.o: file.h
+CLEANFILES+= magic
+all: file magic
+
+MAGFILES= $(.CURDIR)/magdir/Header\
+ $(.CURDIR)/magdir/Localstuff\
+ $(.CURDIR)/magdir/[a-z]*
+magic: $(MAGFILES)
+ cat $(MAGFILES) > $(.TARGET)
afterinstall:
- install -c ${.CURDIR}/magic $(MAGIC)
+ install -c -o $(MAGICOWN) -g $(MAGICGRP) -m $(MAGICMODE) magic \
+ $(DESTDIR)$(MAGIC)
.include <bsd.prog.mk>
diff --git a/usr.bin/file/PORTING b/usr.bin/file/PORTING
index fe0133de62b..604effa8c60 100644
--- a/usr.bin/file/PORTING
+++ b/usr.bin/file/PORTING
@@ -1,10 +1,39 @@
Portability of the new file(1) command.
-@(#) $Header: /cvsroot/src/usr.bin/file/Attic/PORTING,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $
+@(#) $Id: PORTING,v 1.2 1993/06/10 00:38:00 jtc 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,
+This release has been around UNIX; it has been compiled and tested
+in the following environments:
+
+SunOS sqarc 4.1.1 8 sun4
+ No problems.
+ULTRIX squint 4.2 0 RISC
+ No problems.
+A/UX sqmac 3.0a9 SVR22 mc68020
+ No problems.
+AIX sqibm 2 3 000XXXXXX100
+ Had weird "make" problems making "magic" file automatically; just
+ built it by hand. Your mileage may vary.
+SCO sqwang 3.2 2 i386
+ Compiles fine; their weird make can't handle "[a-z]*" as a dependancy,
+ so build magic by hand. Runs fine.
+sqzme sqzme 3.1.1 3 3B2
+ The 3B2 SVR3 needed a few tweaks as well as COPTS = -Ilocalinc
+ in order to compile.
+
+This version, reluctanly, includes <stdlib.h>, which won't exist
+on older systems or those that aren't even close to the ANSI C
+standard. There is a null "stdlib.h", and some other bogus headers,
+in subdirectory "localinc"; if you get complaints about missing
+stdlib.h and others, uncomment the line with COPTS=-Ilocalinc
+in the Makefile, and try again.
+
+You must have either <stdarg.h> or the older <varargs.h>, otherwise you'll
+have to butcher some routines in print.c.
+
+Beyond that, 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
@@ -12,9 +41,11 @@ 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've also tried to include source for 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'.
+These are in subdirectory "localsrc", and not used unless you
+need them; again, see the Makefile.
There is one area that just might cause problems. On System
V, they moved the definition of major() and minor() out of
@@ -26,21 +57,20 @@ have a system in which neither types.h nor sysmacros.h defines
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
+ 1) change the appropriate #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.
+to include `-Dvoid=int' in the variable COPTS 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
+care about non-UNIX systems but will collect widely-used magic
numbers for them as well as for UNIX systems.
Ian Darwin
-Toronto, Canada
+(address in README)
diff --git a/usr.bin/file/README b/usr.bin/file/README
index 7681d755c25..3328f7648e4 100644
--- a/usr.bin/file/README
+++ b/usr.bin/file/README
@@ -1,22 +1,41 @@
** README for file(1) Command **
-@(#) $Header: /cvsroot/src/usr.bin/file/Attic/README,v 1.1.1.1 1993/03/21 09:45:37 cgd 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).
+@(#) $Id: README,v 1.2 1993/06/10 00:38:01 jtc Exp $
+
+This is Release 3.x of Ian Darwin's (copyright but distributable)
+file(1) command. Release 3.x is scheduled for inclusion in the
+4.4 BSD (Berkeley Software Distribution) of UNIX-like
+software, and is the standard "file" command for Linux, 386bsd,
+and other systems. (See "patchlevel.h" for the exact release number).
+
+UNIX is a trademark of UNIX System Laboratories.
+
+The prime contributor to Release 3.8 was Guy Harris, who put in megachanges
+including byte-order independance.
+
+The prime contributor to Release 3.0 was Christos Zoulas, who put
+in hundreds of lines of source code changes, including his own
+ANSIfication of the code (I liked my own ANSIfication better, but
+his (__P()) is the "Berkeley standard" way of doing it, and I wanted UCB
+to include the code...), his HP-like "indirection" (a feature of
+the HP file command, I think), and his mods that finally got the
+uncompress (-z) mode finished and working.
+
+This release has compiled in numerous environments; see PORTING
+for a list and problems.
+
+This fine freeware file(1) follows the USG (System V) model of the file
+command, rather than the Research (V7) version or the V7-derived 4.[23]
+Berkeley one. That is, the file /etc/magic contains much of the ritual
+information that is the source of this program's power. My version
+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
+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.
+in magic(4) format please, to the author, Ian Darwin.
LEGAL.NOTICE - read this first.
README - read this second (you are currently reading this file).
@@ -41,8 +60,29 @@ 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
+ magdir/Makefile - ADJUST THIS FOR YOUR CONFIGURATION
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
+
+Ian Darwin
+Darwin Open Systems
+R R 1
+Palgrave, Ontario L0N 1P0
+Canada
+
+E-mail: darwin@cs.toronto.edu
+ ian@sq.com
+ utzoo!ian
+ ian@darwin.uucp
+ uunet!sq!ian
+
+Phone: Do not even think of telephoning me about this program. Send cash first!
+
+Parts of this software were developed at SoftQuad Inc., 56 Aberfoyle
+Cres, # 810, Toronto, Ontario CANADA M8X 2W4. Phone: 416-239-4801 or
+800-387-2777. Email: mail@sq.com. Call for information on SGML editing
+and browsing, Unix text processing, and customised products on Unix,
+DOS and Mac.
diff --git a/usr.bin/file/apprentice.c b/usr.bin/file/apprentice.c
index 6664945b294..42f05d56972 100644
--- a/usr.bin/file/apprentice.c
+++ b/usr.bin/file/apprentice.c
@@ -26,33 +26,34 @@
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
#include "file.h"
#ifndef lint
static char *moduleid =
- "@(#)$Header: /cvsroot/src/usr.bin/file/Attic/apprentice.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
+ "@(#)$Id: apprentice.c,v 1.2 1993/06/10 00:38:02 jtc Exp $";
#endif /* lint */
-#define MAXSTR 500
-#define EATAB {while (isascii(*l) && isspace(*l)) ++l;}
+#define EATAB {while (isascii((unsigned char) *l) && \
+ isspace((unsigned char) *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];
+static int getvalue __P((struct magic *, char **));
+static int hextoint __P((int));
+static char *getstr __P((char *, char *, int, int *));
+static int parse __P((char *, int *, int));
-char *getstr();
+static int maxmagic = 0;
+int
apprentice(fn, check)
char *fn; /* name of magic file */
-int check; /* non-zero: checking-only run. */
+int check; /* non-zero? checking-only run. */
{
FILE *f;
- char line[MAXSTR+1];
+ char line[BUFSIZ+1];
int errs = 0;
f = fopen(fn, "r");
@@ -65,14 +66,24 @@ int check; /* non-zero: checking-only run. */
exit(1);
}
+ maxmagic = MAXMAGIS;
+ if ((magic = (struct magic *) malloc(sizeof(struct magic) * maxmagic))
+ == NULL) {
+ (void) fprintf(stderr, "%s: Out of memory.\n", progname);
+ 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");
+ (void) printf("cont\toffset\ttype\topcode\tmask\tvalue\tdesc\n");
- while (fgets(line, MAXSTR, f) != NULL) {
+ for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
if (line[0]=='#') /* comment, do not parse */
continue;
- if (strlen(line) <= 1) /* null line, garbage, etc */
+ if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
continue;
line[strlen(line)-1] = '\0'; /* delete newline */
if (parse(line, &nmagic, check) != 0)
@@ -86,45 +97,98 @@ int check; /* non-zero: checking-only run. */
/*
* parse one line from magic file, put into magic[index++] if valid
*/
-int
+static 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;
+ char *t, *s;
+
+ if (nd+1 >= maxmagic){
+ maxmagic += 20;
+ if ((magic = (struct magic *) realloc(magic,
+ sizeof(struct magic) *
+ maxmagic)) == NULL) {
+ (void) fprintf(stderr, "%s: Out of memory.\n", progname);
+ if (check)
+ return -1;
+ else
+ exit(1);
+ }
}
m = &magic[*ndx];
+ m->flag = 0;
+ m->cont_level = 0;
- if (*l == '>') {
+ while (*l == '>') {
++l; /* step over */
- m->contflag = 1;
- } else
- m->contflag = 0;
+ m->cont_level++;
+ }
+
+ if (m->cont_level != 0 && *l == '(') {
+ ++l; /* step over */
+ m->flag |= INDIR;
+ }
/* get offset, then skip over it */
- m->offset = atoi(l);
- while (isascii(*l) && isdigit(*l))
+ m->offset = (int) strtol(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 == '.') {
+ switch (*++l) {
+ case 'l':
+ m->in.type = LONG;
+ break;
+ case 's':
+ m->in.type = SHORT;
+ break;
+ case 'b':
+ m->in.type = BYTE;
+ break;
+ default:
+ magwarn("indirect offset type %c invalid", *l);
+ break;
+ }
+ l++;
+ }
+ s = l;
+ if (*l == '+' || *l == '-') l++;
+ if (isdigit((unsigned char)*l)) {
+ m->in.offset = strtol(l, &t, 0);
+ if (*s == '-') m->in.offset = - m->in.offset;
+ }
+ 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 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
+
/* get type, skip it */
if (strncmp(l, "byte", NBYTE)==0) {
m->type = BYTE;
@@ -138,52 +202,90 @@ int *ndx, check;
} 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 {
- errno = 0;
- warning("type %s invalid", l);
+ magwarn("type %s invalid", l);
return -1;
}
- EATAB;
-
- if (*l == '>' || *l == '<' || *l == '&' || *l == '=') {
- m->reln = *l;
+ /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
+ if (*l == '&') {
++l;
+ m->mask = strtol(l, &l, 0);
} else
- m->reln = '=';
+ m->mask = 0L;
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;
+
+ switch (*l) {
+ case '>':
+ case '<':
+ /* Old-style anding: "0 byte &0x80 dynamically linked" */
+ case '&':
+ case '^':
+ case '=':
+ m->reln = *l;
+ ++l;
break;
+ case '!':
+ if (m->type != STRING) {
+ m->reln = *l;
+ ++l;
+ break;
+ }
+ /* FALL THROUGH */
default:
- warning("can't happen: m->type=%d\n", m->type);
- return -1;
+ if (*l == 'x' && isascii((unsigned char)l[1]) &&
+ isspace((unsigned char)l[1])) {
+ m->reln = *l;
+ ++l;
+ goto GetDesc; /* Bill The Cat */
+ }
+ m->reln = '=';
+ break;
}
+ EATAB;
+
+ if (getvalue(m, &l))
+ return -1;
+ /*
+ * TODO finish this macro and start using it!
+ * #define offsetcheck {if (offset > HOWMANY-1)
+ * magwarn("offset too big"); }
+ */
/*
* now get last part - the description
*/
+GetDesc:
EATAB;
+ if (l[0] == '\b') {
+ ++l;
+ m->nospflag = 1;
+ } else if ((l[0] == '\\') && (l[1] == 'b')) {
+ ++l;
+ ++l;
+ m->nospflag = 1;
+ } else
+ m->nospflag = 0;
while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
/* NULLBODY */;
@@ -194,13 +296,61 @@ int *ndx, check;
return 0;
}
+/*
+ * Read a numeric value from a pointer, into the value union of a magic
+ * pointer, according to the magic type. Update the string pointer to point
+ * just after the number read. Return 0 for success, non-zero for failure.
+ */
+static int
+getvalue(m, p)
+struct magic *m;
+char **p;
+{
+ int slen;
+
+ if (m->type == STRING) {
+ *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
+ m->vallen = slen;
+ } else {
+ if (m->reln != 'x') {
+ 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(*p,p,0);
+ break;
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ m->value.l = (short) strtol(*p,p,0);
+ break;
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ case LONG:
+ case BELONG:
+ case LELONG:
+ m->value.l = (long) strtol(*p,p,0);
+ break;
+ default:
+ magwarn("can't happen: m->type=%d\n", m->type);
+ return -1;
+ }
+ }
+ }
+ 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 *
+static char *
getstr(s, p, plen, slen)
register char *s;
register char *p;
@@ -211,8 +361,9 @@ int plen, *slen;
register int c;
register int val;
- while((c = *s++) != '\0') {
- if (isspace(c)) break;
+ while ((c = *s++) != '\0') {
+ if (isspace((unsigned char) c))
+ break;
if (p >= pmax) {
fprintf(stderr, "String too long: %s\n", origs);
break;
@@ -224,7 +375,7 @@ int plen, *slen;
goto out;
default:
- *p++ = c;
+ *p++ = (char) c;
break;
case 'n':
@@ -272,7 +423,7 @@ int plen, *slen;
}
else
--s;
- *p++ = val;
+ *p++ = (char)val;
break;
/* \x and up to 3 hex digits */
@@ -293,28 +444,28 @@ int plen, *slen;
--s;
} else
--s;
- *p++ = val;
+ *p++ = (char)val;
break;
}
} else
- *p++ = c;
+ *p++ = (char)c;
}
out:
*p = '\0';
*slen = p - origp;
- return(s);
+ return s;
}
/* Single hex char to int; -1 if not a hex char. */
-int
+static int
hextoint(c)
- char c;
+int 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';
+ 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;
}
@@ -324,12 +475,12 @@ hextoint(c)
*/
void
showstr(s)
-register char *s;
+const char *s;
{
register char c;
while((c = *s++) != '\0') {
- if(c >= 040 && c <= 0176)
+ if(c >= 040 && c <= 0176) /* TODO isprint && !iscntrl */
putchar(c);
else {
putchar('\\');
diff --git a/usr.bin/file/ascmagic.c b/usr.bin/file/ascmagic.c
index 850287c8c50..3639b67ef7b 100644
--- a/usr.bin/file/ascmagic.c
+++ b/usr.bin/file/ascmagic.c
@@ -27,41 +27,49 @@
*/
#include <stdio.h>
+#include <string.h>
#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
#include "file.h"
#include "names.h"
#ifndef lint
static char *moduleid =
- "@(#)$Header: /cvsroot/src/usr.bin/file/Attic/ascmagic.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
+ "@(#)$Id: ascmagic.c,v 1.2 1993/06/10 00:38:04 jtc 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;
+int
+ascmagic(buf, nbytes)
+unsigned char *buf;
+int nbytes; /* size actually read */
{
- register int i;
- char *s, *strtok(), *token;
+ int i, isblock, has_escapes = 0;
+ unsigned char *s;
+ char nbuf[HOWMANY+1]; /* one extra for terminating '\0' */
+ char *token;
register struct names *p;
- extern int nbytes;
- short has_escapes = 0;
/* these are easy, do them first */
/*
- * for troff, look for . + letter + letter;
+ * for troff, look for . + letter + letter or .\";
* 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 == '.') {
+ unsigned char *tp = buf + 1;
+
+ while (isascii(*tp) && isspace(*tp))
+ ++tp; /* skip leading whitespace */
+ if ((isascii(*tp) && (isalnum(*tp) || *tp=='\\') &&
+ isascii(*(tp+1)) && (isalnum(*(tp+1)) || *tp=='"'))) {
+ ckfputs("troff or preprocessor input text", stdout);
+ return 1;
+ }
}
if ((*buf == 'c' || *buf == 'C') &&
isascii(*(buf + 1)) && isspace(*(buf + 1))) {
@@ -70,12 +78,17 @@ register char *buf;
}
/* look for tokens from names.h - this is expensive! */
- s = buf;
- while ((token = strtok(s, " \t\n\r\f")) != NULL) {
+ /* make a copy of the buffer here because strtok() will destroy it */
+ s = (unsigned char*) memcpy(nbuf, buf, HOWMANY);
+ has_escapes = (memchr(s, '\033', HOWMANY) != NULL);
+ while ((token = strtok((char*)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);
+ if (has_escapes)
+ ckfputs(" (with escape sequences)",
+ stdout);
return 1;
}
}
@@ -90,20 +103,33 @@ register char *buf;
return 1;
}
+ if (i = is_compress(buf, &isblock)) {
+ if (zflag) {
+ unsigned char *newbuf;
+ int newsize;
+
+ if (newsize = uncompress(buf, &newbuf, nbytes)) {
+ tryit(newbuf, newsize);
+ free(newbuf);
+ }
+ printf(" (%scompressed data - %d bits)",
+ isblock ? "block " : "", i);
+ }
+ else printf("%scompressed data - %d bits",
+ isblock ? "block " : "", i);
+ 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);
- }
+ ckfputs("ascii text", stdout);
+ if (has_escapes) {
+ ckfputs(" (with escape sequences)", stdout);
+ }
return 1;
}
diff --git a/usr.bin/file/compress.c b/usr.bin/file/compress.c
new file mode 100644
index 00000000000..9122023d563
--- /dev/null
+++ b/usr.bin/file/compress.c
@@ -0,0 +1,86 @@
+/*
+ * compress routines:
+ * is_compress() returns 0 if uncompressed, number of bits if compressed.
+ * uncompress(old, n, newch) - uncompress old into new, return sizeof new
+ * $Id: compress.c,v 1.1 1993/06/10 00:38:05 jtc Exp $
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include "file.h"
+
+/* Check for compression, return nbits. Algorithm, in magic(4) format:
+ * 0 string \037\235 compressed data
+ * >2 byte&0x80 >0 block compressed
+ * >2 byte&0x1f x %d bits
+ */
+int
+is_compress(p, b)
+const unsigned char *p;
+int *b;
+{
+
+ if (*p != '\037' || *(/*signed*/ char*)(p+1) != '\235')
+ return 0; /* not compress()ed */
+
+ *b = *(p+2) & 0x80;
+ return *(p+2) & 0x1f;
+}
+
+int
+uncompress(old, newch, n)
+const unsigned char *old;
+unsigned char **newch;
+int n;
+{
+ int fdin[2], fdout[2];
+
+ if (pipe(fdin) == -1 || pipe(fdout) == -1) {
+ error("cannot create pipe (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+ }
+ switch (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]);
+
+ execlp("uncompress", "uncompress", "-c", NULL);
+ error("could not execute `uncompress' (%s).\n",
+ strerror(errno));
+ /*NOTREACHED*/
+ case -1:
+ error("could not fork (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+
+ default: /* parent */
+ (void) close(fdin[0]);
+ (void) close(fdout[1]);
+ if (write(fdin[1], old, n) != n) {
+ error("write failed (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+ }
+ (void) close(fdin[1]);
+ if ((*newch = (unsigned char *) malloc(n)) == NULL) {
+ error("out of memory.\n");
+ /*NOTREACHED*/
+ }
+ if ((n = read(fdout[0], *newch, n)) <= 0) {
+ free(*newch);
+ error("read failed (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+ }
+ (void) close(fdout[0]);
+ (void) wait(NULL);
+ return n;
+ }
+}
diff --git a/usr.bin/file/file.1 b/usr.bin/file/file.1
index 4354a75288a..53a0113620c 100644
--- a/usr.bin/file/file.1
+++ b/usr.bin/file/file.1
@@ -1,26 +1,24 @@
-.\"
-.\" PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
-.\" -------------------- ----- ----------------------
-.\" CURRENT PATCH LEVEL: 1 00103
-.\" -------------------- ----- ----------------------
-.\"
-.\" 16 Feb 93 Rodney W. Grimes Fixed all the commands that had two
-.\" dots in them.
-.\"
.TH FILE 1 "Copyright but distributable"
+.\# $Id: file.1,v 1.3 1993/06/10 00:38:06 jtc Exp $
.SH NAME
.I file
\- determine file type
.SH SYNOPSIS
.B file
[
-.B -c
+.B \-c
]
[
-.B -f
+.B \-z
+]
+[
+.B \-L
+]
+[
+.B \-f
namefile ]
[
-.B -m
+.B \-m
magicfile ]
file ...
.SH DESCRIPTION
@@ -50,28 +48,29 @@ or the program itself,
.B "preserve these keywords" .
People depend on knowing that all the readable files in a directory
have the word ``text'' printed.
-Don't do as one computer vendor did \- change ``shell commands text''
+Don't do as Berkeley did \- change ``shell commands text''
to ``shell script''.
.PP
The filesystem tests are based on examining the return from a
-.I stat (2)
+.IR stat (2)
system call.
The program checks to see if the file is empty,
or if it's some sort of special file.
Any known file types appropriate to the system you are running on
-(sockets and symbolic links on 4.2BSD, named pipes (FIFOs) on System V)
+(sockets, symbolic links, or named pipes (FIFOs) on those systems that
+implement them)
are intuited if they are defined in
the system header file
-.I sys/stat.h .
+.BR sys/stat.h .
.PP
The magic number tests are used to check for files with data in
particular fixed formats.
The canonical example of this is a binary executable (compiled program)
-.I a.out
+.B a.out
file, whose format is defined in
-.I a.out.h
+.B a.out.h
and possibly
-.I exec.h
+.B exec.h
in the standard include directory.
These files have a `magic number' stored in a particular place
near the beginning of the file that tells the \s-1UNIX\s0 operating system
@@ -80,7 +79,7 @@ The concept of `magic number' has been applied by extension to data files.
Any file with some invariant identifier at a small fixed
offset into the file can usually be described in this way.
The information in these files is read from the magic file
-.I /etc/magic .
+.I /etc/magic.
.PP
If an argument appears to be an
.SM ASCII
@@ -90,10 +89,10 @@ attempts to guess its language.
The language tests look for particular strings (cf \fInames.h\fP)
that can appear anywhere in the first few blocks of a file.
For example, the keyword
-.I .br
+.B .br
indicates that the file is most likely a troff input file,
just as the keyword
-.I struct
+.B struct
indicates a C program.
These tests are less reliable than the previous
two groups, so they are performed last.
@@ -104,19 +103,23 @@ archives) and determine whether an unknown file should be
labelled as `ascii text' or `data'.
.PP
Use
-.B -m
+.B \-m
.I file
to specify an alternate file of magic numbers.
.PP
The
-.B -c
+.B \-z
+tries to look inside compressed files.
+.PP
+The
+.B \-c
option causes a checking printout of the parsed form of the magic file.
This is usually used in conjunction with
-.B -m
+.B \-m
to debug a new magic file before installing it.
.PP
The
-.B -f
+.B \-f
.I namefile
option specifies that the names of the files to be examined
are to be read (one per line) from
@@ -126,11 +129,16 @@ Either
.I namefile
or at least one filename argument must be present;
to test the standard input, use ``-'' as a filename argument.
+.PP
+The
+.B \-L
+option causes symlinks to be followed, as the like-named option in
+.IR ls (1).
.SH FILES
.I /etc/magic
\- default list of magic numbers
.SH SEE ALSO
-.IR Magic (FILES)
+.IR magic (__SECTION__)
\- description of magic file format.
.br
.IR Strings (1), " od" (1)
@@ -154,21 +162,25 @@ For example,
in an existing magic file would have to be changed to
.br
>10 string language\e impress (imPRESS data)
+.br
+In addition, in this version, if a pattern string contains a backslash,
+it must be escaped. For example
+.br
+0 string \ebegindata Andrew Toolkit document
+.br
+in an existing magic file would have to be changed to
+.br
+0 string \e\ebegindata Andrew Toolkit document
+.br
.PP
-The Sun Microsystems implementation of System V compatibility
-includes a file(1) command that has some extentions.
+SunOS releases 3.2 and later from Sun Microsystems include a
+.IR file (1)
+command derived from the System V one, but with some extensions.
My version differs from Sun's only in minor ways.
-The significant one is the `&' operator, which Sun's program expects as,
+It includes the extension of the `&' operator, used as,
for example,
.br
>16 long&0x7fffffff >0 not stripped
-.br
-would be entered in my version as
-.br
->16 long &0x7fffffff not stripped
-.br
-which is a little less general; it simply tests (location 16)&0x7ffffff
-and returns its truth value as a C expression.
.SH MAGIC DIRECTORY
The magic file entries have been collected from various sources,
mainly USENET, and contributed by various authors.
@@ -203,19 +215,47 @@ the first version.
Geoff Collyer found several inadequacies
and provided some magic file entries.
The program has undergone continued evolution since.
-.SH NOTICE
-Copyright (c) Ian F. Darwin, 1986 and 1987.
+.SH AUTHOR
Written by Ian F. Darwin, UUCP address {utzoo | ihnp4}!darwin!ian,
Internet address ian@sq.com,
postal address: P.O. Box 603, Station F, Toronto, Ontario, CANADA M4Y 2L8.
.PP
-.I Strtok.c
-and
-.I getopt.c
-written by and copyright by Henry Spencer, utzoo!henry.
+Altered by Rob McMahon, cudcv@warwick.ac.uk, 1989, to extend the `&' operator
+from simple `x&y != 0' to `x&y op z'.
+.PP
+Altered by Guy Harris, guy@auspex.com, 1993, to:
+.RS
+.PP
+put the ``old-style'' `&'
+operator back the way it was, because 1) Rob McMahon's change broke the
+previous style of usage, 2) the SunOS ``new-style'' `&' operator,
+which this version of
+.I file
+supports, also handles `x&y op z', and 3) Rob's change wasn't documented
+in any case;
+.PP
+put in multiple levels of `>';
.PP
-This software is not subject to any license of the American Telephone
-and Telegraph Company or of the Regents of the University of California.
+put in ``beshort'', ``leshort'', etc. keywords to look at numbers in the
+file in a specific byte order, rather than in the native byte order of
+the process running
+.IR file .
+.RE
+.PP
+Changes by Ian Darwin and various authors including
+Christos Zoulas (christos@ee.cornell.edu), 1990-1992.
+.SH LEGAL NOTICE
+Copyright (c) Ian F. Darwin, Toronto, Canada,
+1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993.
+.PP
+This software is not subject to and may not be made subject to any
+license of the American Telephone and Telegraph Company, Sun
+Microsystems Inc., Digital Equipment Inc., Lotus Development Inc., the
+Regents of the University of California, The X Consortium or MIT, or
+The Free Software Foundation.
+.PP
+This software is not subject to any export provision of the United States
+Department of Commerce, and may be exported to any country or planet.
.PP
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
@@ -250,8 +290,14 @@ were written by John Gilmore from his public-domain
.I tar
program, and are not covered by the above restrictions.
.SH BUGS
-There must be a way to automate the construction of the Magic
-file from all the glop in magdir. What is it?
+There must be a better way to automate the construction of the Magic
+file from all the glop in Magdir. What is it?
+Better yet, the magic file should be compiled into binary (say,
+.IR ndbm (3)
+or, better yet, fixed-length ASCII strings
+for use in heterogenous network environments) for faster startup.
+Then the program would run as fast as the Version 7 program of the same name,
+with the flexibility of the System V version.
.PP
.I File
uses several algorithms that favor speed over accuracy,
@@ -260,14 +306,11 @@ thus it can be misled about the contents of ASCII files.
The support for ASCII files (primarily for programming languages)
is simplistic, inefficient and requires recompilation to update.
.PP
-Should there be an ``else'' clause to follow a series of continuation lines?
-.PP
-Is it worthwhile to implement recursive file inspection,
-so that compressed files, uuencoded, etc., can say ``compressed
-ascii text'' or ``compressed executable'' or ``compressed tar archive"
-or whatever?
+There should be an ``else'' clause to follow a series of continuation lines.
.PP
The magic file and keywords should have regular expression support.
+Their use of ASCII TAB as a field delimiter is ugly and makes
+it hard to edit the files, but is entrenched.
.PP
It might be advisable to allow upper-case letters in keywords
for e.g., troff commands vs man page macros.
@@ -283,18 +326,6 @@ The list of keywords in
probably belongs in the Magic file.
This could be done by using some keyword like `*' for the offset value.
.PP
-The program should malloc the magic file structures,
-rather than using a fixed-size array as at present.
-.PP
-The magic file should be compiled into binary
-(or better yet, fixed-length ASCII strings
-for use in heterogenous network environments) for faster startup.
-Then the program would run as fast as the Version 7 program of the same name,
-with the flexibility of the System V version.
-But then there would have to be yet another magic number for the
-.I magic.out
-file.
-.PP
Another optimisation would be to sort
the magic file so that we can just run down all the
tests for the first byte, first word, first long, etc, once we
@@ -309,10 +340,12 @@ they are not as good as other guesses (e.g. ``Newsgroups:'' versus
"Return-Path:"). Still, if the others don't pan out, it should be
possible to use the first guess.
.PP
-Perhaps the program should automatically try all tests with
-byte-swapping done, to avoid having to figure out the byte-swapped values
-when constructing the magic file.
-Of course this will run more slowly, so it should probably be
-an option (-a?).
+This program is slower than some vendors' file commands.
.PP
This manual page, and particularly this section, is too long.
+.SH AVAILABILITY
+You can obtain the original author's latest version by anonymous FTP
+on
+.B ftp.cs.toronto.edu
+in the directory
+.BR /pub/darwin/file .
diff --git a/usr.bin/file/file.c b/usr.bin/file/file.c
index a6cdcb87f1e..fea1b2e87ef 100644
--- a/usr.bin/file/file.c
+++ b/usr.bin/file/file.c
@@ -24,50 +24,68 @@
*
* 4. This notice may not be removed or altered.
*/
+#ifndef lint
+static char *moduleid =
+ "@(#)$Id: file.c,v 1.2 1993/06/10 00:38:08 jtc Exp $";
+#endif /* lint */
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
+#include <sys/param.h> /* for MAXPATHLEN */
#include <sys/stat.h>
-#include "file.h"
+#include <fcntl.h> /* for open() */
+#include <utime.h>
+#include <unistd.h> /* for read() */
-#define USAGE "usage: %s [-c] [-f namefile] [-m magicfile] file...\n"
+#include "file.h"
-#ifndef lint
-static char *moduleid =
- "@(#)$Header: /cvsroot/src/usr.bin/file/Attic/file.c,v 1.1.1.1 1993/03/21 09:45:37 cgd 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 */
+#ifdef S_IFLNK
+# define USAGE "Usage: %s [-czL] [-f namefile] [-m magicfile] file...\n"
#else
-char *magicfile = "/etc/magic"; /* where magic be found */
+# define USAGE "Usage: %s [-cz] [-f namefile] [-m magicfile] file...\n"
#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 */
-};
+
+#ifndef MAGIC
+# define MAGIC "/etc/magic"
+#endif
+
+int /* Global command-line options */
+ debug = 0, /* debugging */
+ lflag = 0, /* follow Symlinks (BSD only) */
+ zflag = 0; /* follow (uncompress) compressed files */
+
+int /* Misc globals */
+ nmagic = 0; /* number of valid magic[]s */
+
+struct magic *magic; /* array of magic entries */
+
+char *magicfile = MAGIC;/* where magic be found */
+
+char *progname; /* used throughout */
+int lineno; /* line number in the magic file */
+
+
+static void unwrap __P((char *fn));
/*
* main - parse arguments and handle options
*/
+int
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];
+ if ((progname = strrchr(argv[0], '/')) != NULL)
+ progname++;
+ else
+ progname = argv[0];
- while ((c = getopt(argc, argv, "cdf:m:")) != EOF)
+ while ((c = getopt(argc, argv, "cdf:Lm:z")) != EOF)
switch (c) {
case 'c':
++check;
@@ -79,9 +97,17 @@ char *argv[];
unwrap(optarg);
++didsomefiles;
break;
+#ifdef S_IFLNK
+ case 'L':
+ ++lflag;
+ break;
+#endif
case 'm':
magicfile = optarg;
break;
+ case 'z':
+ zflag++;
+ break;
case '?':
default:
errflg++;
@@ -97,108 +123,150 @@ char *argv[];
exit(ret);
if (optind == argc) {
- if (!didsomefiles)
+ if (!didsomefiles) {
(void)fprintf(stderr, USAGE, progname);
+ exit(2);
+ }
}
- else
+ 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++)
- process(argv[optind]);
+ process(argv[optind], wid);
+ }
- exit(0);
+ return 0;
}
+
/*
* unwrap -- read a file of filenames, do each one.
*/
+static void
unwrap(fn)
char *fn;
{
-#define FILENAMELEN 128
- char buf[FILENAMELEN];
+ char buf[MAXPATHLEN];
FILE *f;
+ int wid = 0, cwid;
- 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);
+ if ((f = fopen(fn, "r")) == NULL) {
+ error("Cannot open `%s' (%s).\n", fn, strerror(errno));
+ /*NOTREACHED*/
}
+
+ while (fgets(buf, MAXPATHLEN, f) != NULL) {
+ cwid = strlen(buf) - 1;
+ if (cwid > wid)
+ wid = cwid;
+ }
+
+ rewind(f);
+
+ while (fgets(buf, MAXPATHLEN, f) != NULL) {
+ buf[strlen(buf)-1] = '\0';
+ process(buf, wid);
+ }
+
+ (void) fclose(f);
}
+
/*
* process - process input file
*/
-process(inname)
-char *inname;
+void
+process(inname, wid)
+const char *inname;
+int wid;
{
- int fd;
- char buf[HOWMANY];
- struct utimbuf utbuf;
+ int fd = 0;
+ static const char stdname[] = "standard input";
+ unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
+ struct utimbuf utbuf;
+ struct stat sb;
+ int nbytes = 0; /* number of bytes read from a datafile */
if (strcmp("-", inname) == 0) {
- (void) printf("standard input:\t");
- if (fstat(0, &statbuf)<0)
- warning("cannot fstat; ");
- fd = 0;
- goto readit;
+ if (fstat(0, &sb)<0) {
+ error("cannot fstat `%s' (%s).\n", stdname,
+ strerror(errno));
+ /*NOTREACHED*/
+ }
+ inname = stdname;
}
+
+ if (wid > 0)
+ (void) printf("%s:%*s ", inname, wid - strlen(inname), "");
+
+ if (inname != stdname) {
+ /*
+ * first try judging the file based on its filesystem status
+ */
+ if (fsmagic(inname, &sb) != 0) {
+ putchar('\n');
+ return;
+ }
- (void) printf("%s:\t", inname);
+ if ((fd = open(inname, O_RDONLY)) < 0) {
+ /* We can't open it, but we were able to stat it. */
+ if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
+ if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
+ ckfprintf(stdout, "can't read `%s' (%s).\n",
+ inname, strerror(errno));
+ return;
+ }
+ }
+
/*
- * first try judging the file based on its filesystem status
- * Side effect: fsmagic updates global data `statbuf'.
+ * try looking at the first HOWMANY bytes
*/
- 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
+ if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
+ error("read failed (%s).\n", strerror(errno));
+ /*NOTREACHED*/
+ }
+
+ if (nbytes == 0)
+ ckfputs("empty", stdout);
+ else {
+ buf[nbytes] = '\0'; /* null-terminate it */
+ tryit(buf, nbytes);
+ }
+
+ if (inname != stdname) {
/*
- * try tests in /etc/magic (or surrogate magic file)
+ * Try to restore access, modification times if read it.
*/
- 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);
- }
+ utbuf.actime = sb.st_atime;
+ utbuf.modtime = sb.st_mtime;
+ (void) utime(inname, &utbuf); /* don't care if loses */
+ (void) close(fd);
}
-
(void) putchar('\n');
}
+void
+tryit(buf, nb)
+unsigned char *buf;
+int nb;
+{
+ /*
+ * try tests in /etc/magic (or surrogate magic file)
+ */
+ if (softmagic(buf, nb) != 1)
+ /*
+ * try known keywords, check for ascii-ness too.
+ */
+ if (ascmagic(buf, nb) != 1)
+ /*
+ * abandon hope, all ye who remain here
+ */
+ ckfputs("data", stdout);
+}
+
diff --git a/usr.bin/file/file.h b/usr.bin/file/file.h
index a2c1d51c958..3768164e62d 100644
--- a/usr.bin/file/file.h
+++ b/usr.bin/file/file.h
@@ -1,6 +1,6 @@
/*
* file.h - definitions for file(1) program
- # @(#)$Header: /cvsroot/src/usr.bin/file/Attic/file.h,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $
+ * @(#)$Id: file.h,v 1.2 1993/06/10 00:38:09 jtc Exp $
*
* Copyright (c) Ian F. Darwin, 1987.
* Written by Ian F. Darwin.
@@ -27,28 +27,101 @@
*/
#define HOWMANY 1024 /* how much of the file to look at */
-#define MAXMAGIS 250 /* max entries in /etc/magic */
+#define MAXMAGIS 1000 /* 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 */
+ short flag;
+#define INDIR 1 /* if '>(...)' appears, */
+ short cont_level; /* level of ">" */
+ struct {
+ char type; /* byte short long */
+ long offset; /* offset from indirection */
+ } in;
long offset; /* offset to magic number */
- char reln; /* relation (0=eq, '>'=gt, etc) */
+#define MASK 0200 /* this is a masked op, like & v1 = v2 */
+ unsigned char reln; /* relation (0=eq, '>'=gt, etc) */
char type; /* int, short, long or string. */
char vallen; /* length of string value, if any */
#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
union VALUETYPE {
char b;
short h;
long l;
char s[MAXstring];
+ unsigned char hs[2]; /* 2 bytes of a fixed-endian "short" */
+ unsigned char hl[4]; /* 2 bytes of a fixed-endian "long" */
} value; /* either number or string */
+ long mask; /* mask before comparison with value */
+ char nospflag; /* supress space character */
char desc[MAXDESC]; /* description */
};
-extern void error(), exit();
+#include <stdio.h> /* Include that here, to make sure __P gets defined */
+
+#ifndef __P
+# if __STDC__ || __cplusplus
+# define __P(a) a
+# else
+# define __P(a) ()
+# define const
+# endif
+#endif
+
+extern int apprentice __P((char *, int));
+extern int ascmagic __P((unsigned char *, int));
+extern void error __P((const char *, ...));
+extern void ckfputs __P((const char *, FILE *));
+struct stat;
+extern int fsmagic __P((const char *, struct stat *));
+extern int is_compress __P((const unsigned char *, int *));
+extern int is_tar __P((unsigned char *));
+extern void magwarn __P((const char *, ...));
+extern void mdump __P((struct magic *));
+extern void process __P((const char *, int));
+extern void showstr __P((const char *));
+extern int softmagic __P((unsigned char *, int));
+extern void tryit __P((unsigned char *, int));
+extern int uncompress __P((const unsigned char *, unsigned char **, int));
+extern void ckfprintf __P((FILE *, const char *, ...));
+
+
+
+extern int errno; /* Some unixes don't define this.. */
+
+extern char *progname; /* the program name */
+extern char *magicfile; /* name of the magic file */
+extern int lineno; /* current line number in magic file */
+
+extern struct magic *magic; /* array of magic entries */
+extern int nmagic; /* number of valid magic[]s */
+
+
+extern int debug; /* enable debugging? */
+extern int zflag; /* process compressed files? */
+extern int lflag; /* follow symbolic links? */
+
+extern int optind; /* From getopt(3) */
+extern char *optarg;
+
+#if !defined(__STDC__) || defined(sun)
+extern int sys_nerr;
+extern char *sys_errlist[];
+#define strerror(e) \
+ (((e) >= 0 && (e) < sys_nerr) ? sys_errlist[(e)] : "Unknown error")
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 512
+#endif
diff --git a/usr.bin/file/fsmagic.c b/usr.bin/file/fsmagic.c
index 272f7579bdb..b051048dad5 100644
--- a/usr.bin/file/fsmagic.c
+++ b/usr.bin/file/fsmagic.c
@@ -26,8 +26,11 @@
*/
#include <stdio.h>
+#include <string.h>
#include <sys/types.h>
-#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
#ifndef major /* if `major' not defined in types.h, */
#include <sys/sysmacros.h> /* try this one. */
#endif
@@ -36,58 +39,57 @@
/* 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.
+ 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: /cvsroot/src/usr.bin/file/Attic/fsmagic.c,v 1.2 1993/05/19 06:21:23 cgd Exp $";
+ "@(#)$Id: fsmagic.c,v 1.3 1993/06/10 00:38:10 jtc Exp $";
#endif /* lint */
-extern char *progname;
-extern char *ckfmsg, *magicfile;
-extern int debug;
-extern FILE *efopen();
-
-fsmagic(fn)
-char *fn;
+int
+fsmagic(fn, sb)
+const char *fn;
+struct stat *sb;
{
- extern struct stat statbuf;
-#ifdef S_IFLNK
- char slink[PATH_MAX+1];
-#endif
-
+ int ret = 0;
+
/*
* 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.
+ * On 4.2BSD and similar systems, use lstat() to identify symlinks.
*/
#ifdef S_IFLNK
- if (lstat(fn, &statbuf) <0)
-#else
- if (stat(fn, &statbuf) <0)
+ if (!lflag)
+ ret = lstat(fn, sb);
+ else
#endif
- {
- warning("can't stat", "");
- return -1;
- }
+ ret = stat(fn, sb); /* don't merge into if; see "ret =" above */
- 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);
+ if (ret) {
+ ckfprintf(stdout,
+ /* Yes, I do mean stdout. */
+ /* No \n, caller will provide. */
+ "can't stat `%s' (%s).", fn, strerror(errno));
+ return 1;
+ }
+
+ if (sb->st_mode & S_ISUID) ckfputs("setuid ", stdout);
+ if (sb->st_mode & S_ISGID) ckfputs("setgid ", stdout);
+ if (sb->st_mode & S_ISVTX) ckfputs("sticky ", stdout);
- switch (statbuf.st_mode & S_IFMT) {
+ switch (sb->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));
+ major(sb->st_rdev), minor(sb->st_rdev));
return 1;
case S_IFBLK:
(void) printf("block special (%d/%d)",
- major(statbuf.st_rdev), minor(statbuf.st_rdev));
+ major(sb->st_rdev), minor(sb->st_rdev));
return 1;
/* TODO add code to handle V7 MUX and Blit MUX files */
#ifdef S_IFIFO
@@ -97,10 +99,54 @@ char *fn;
#endif
#ifdef S_IFLNK
case S_IFLNK:
- ckfputs("symbolic link", stdout);
- if (readlink(fn, slink, sizeof(slink)) >= 0) {
- ckfputs(" to ", stdout);
- ckfputs(slink, stdout);
+ {
+ char buf[BUFSIZ+4];
+ register int nch;
+ struct stat tstatbuf;
+
+ if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
+ ckfprintf(stdout, "unreadable symlink (%s).",
+ strerror(errno));
+ return 1;
+ }
+ buf[nch] = '\0'; /* readlink(2) forgets this */
+
+ /* If broken symlink, say so and quit early. */
+ if (*buf == '/') {
+ if (stat(buf, &tstatbuf) < 0) {
+ ckfprintf(stdout,
+ "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) {
+ ckfprintf(stdout,
+ "broken symbolic link to %s", buf);
+ return 1;
+ }
+ }
+
+ /* Otherwise, handle it. */
+ if (lflag) {
+ process(buf, strlen(buf));
+ return 1;
+ } else { /* just print what it points to */
+ ckfputs("symbolic link to ", stdout);
+ ckfputs(buf, stdout);
+ }
}
return 1;
#endif
@@ -112,13 +158,14 @@ char *fn;
case S_IFREG:
break;
default:
- warning("invalid st_mode %d in statbuf!", statbuf.st_mode);
+ error("invalid mode 0%o.\n", sb->st_mode);
+ /*NOTREACHED*/
}
/*
* regular file, check next possibility
*/
- if (statbuf.st_size == 0) {
+ if (sb->st_size == 0) {
ckfputs("empty", stdout);
return 1;
}
diff --git a/usr.bin/file/is_tar.c b/usr.bin/file/is_tar.c
index e0c32d7f974..da43fc260f9 100644
--- a/usr.bin/file/is_tar.c
+++ b/usr.bin/file/is_tar.c
@@ -5,18 +5,24 @@
* Pubic Domain version written 26 Aug 1985 John Gilmore (ihnp4!hoptoad!gnu).
*
* @(#)list.c 1.18 9/23/86 Public Domain - gnu
+ * $Id: is_tar.c,v 1.2 1993/06/10 00:38:12 jtc Exp $
*
* Comments changed and some code/comments reformatted
* for file command by Ian Darwin.
*/
+#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include "tar.h"
#define isodigit(c) ( ((c) >= '0') && ((c) <= '7') )
-long from_oct(); /* Decode octal number */
+#if defined(__STDC__) || defined(__cplusplus)
+static long from_oct(int, char*); /* Decode octal number */
+#else
+static long from_oct();
+#endif
/*
* Return
@@ -25,9 +31,10 @@ long from_oct(); /* Decode octal number */
* 2 for Unix Std (POSIX) tar file.
*/
int
-is_tar(header)
- register union record *header;
+is_tar(buf)
+unsigned char *buf;
{
+ register union record *header = (union record *)buf;
register int i;
register long sum, recsum;
register char *p;
@@ -36,7 +43,7 @@ is_tar(header)
sum = 0;
p = header->charptr;
- for (i = sizeof(*header); --i >= 0;) {
+ for (i = sizeof(union record); --i >= 0;) {
/*
* We can't use unsigned char here because of old compilers,
* e.g. V7.
@@ -64,7 +71,7 @@ is_tar(header)
*
* Result is -1 if the field is invalid (all blank, or nonoctal).
*/
-long
+static long
from_oct(digs, where)
register int digs;
register char *where;
diff --git a/usr.bin/file/magic.5 b/usr.bin/file/magic.5
index b149ab43566..5a56de7c9f9 100644
--- a/usr.bin/file/magic.5
+++ b/usr.bin/file/magic.5
@@ -1,13 +1,4 @@
-.\"
-.\" PATCHES MAGIC LEVEL PATCH THAT GOT US HERE
-.\" -------------------- ----- ----------------------
-.\" CURRENT PATCH LEVEL: 1 00103
-.\" -------------------- ----- ----------------------
-.\"
-.\" 16 Feb 93 Rodney W. Grimes Fixed all the commands that had two
-.\" dots in them.
-.\"
-.TH MAGIC FILES "Public Domain"
+.TH MAGIC 5 "Public Domain"
.\" install as magic.4 on USG, magic.5 on V7 or Berkeley systems.
.SH NAME
magic \- file command's magic number file
@@ -38,12 +29,33 @@ The type of the data to be tested. The possible values are:
.IP byte \w'message'u+2n
A one-byte value.
.IP short
-A two-byte value (on most systems).
+A two-byte value (on most systems) in this machine's native byte order.
.IP long
-A four-byte value (on most systems).
+A four-byte value (on most systems) in this machine's native byte order.
.IP string
A string of bytes.
+.IP date
+A four-byte value interpreted as a unix date.
+.IP beshort
+A two-byte value (on most systems) in big-endian byte order.
+.IP belong
+A four-byte value (on most systems) in big-endian byte order.
+.IP bedate
+A four-byte value (on most systems) in big-endian byte order,
+interpreted as a unix date.
+.IP leshort
+A two-byte value (on most systems) in little-endian byte order.
+.IP lelong
+A four-byte value (on most systems) in little-endian byte order.
+.IP ledate
+A four-byte value (on most systems) in little-endian byte order,
+interpreted as a unix date.
.RE
+The numeric types may optionally be followed by
+.B &
+and a numeric value,
+to specify that the value is to be AND'ed with the
+numeric value before any comparisons are done.
.IP test
The value to be compared with the value from the file. If the type is
numeric, this value
@@ -61,10 +73,14 @@ value,
.BR > ,
to specify that the value from the file must be greater than the specified
value,
-or
.BR & ,
-to specify that the value is to be AND'ed with the
-numeric value before any comparisons are done.
+to specify that the value from the file must have set all of the bits
+that are set in the specified value,
+or
+.BR ^ ,
+to specify that the value from the file must have clear any of the bits
+that are set in the specified value.
+.IP
Numeric values are specified in C form; e.g.
.B 13
is decimal,
@@ -78,9 +94,19 @@ is omitted, it is assumed to be
.IP
For string values, the byte string from the
file must match the specified byte string.
-The operators =, < and > (but not &) can be applied to strings.
+The operators
+.BR = ,
+.B <
+and
+.B >
+(but not
+.BR & )
+can be applied to strings.
The length used for matching is that of the string argument
-in the magic file.
+in the magic file. This means that a line can match any string, and
+then presumably print that string, by doing
+.B >\e0
+(because all strings are greater than the null string).
.IP message
The message to be printed if the comparison succeeds. If the string
contains a
@@ -91,30 +117,61 @@ performed) is printed using the message as the format string.
Some file formats contain additional information which is to be printed
along with the file type. A line which begins with the character
.B >
-indicates additional tests and messages to be printed. If the test on the
-line preceding the first line with a
+indicates additional tests and messages to be printed. The number of
.B >
-succeeds, the tests specified in all the subsequent lines beginning with
+on the line indicates the level of the test; a line with no
.B >
+at the beginning is considered to be at level 0.
+Each line at level
+.IB n \(pl1
+is under the control of the line at level
+.IB n
+most closely preceding it in the magic file.
+If the test on a line at level
+.I n
+succeeds, the tests specified in all the subsequent lines at level
+.IB n \(pl1
are performed, and the messages printed if the tests succeed. The next
-line which does not begin with a
-.B >
+line at level
+.I n
terminates this.
+If the first character following the last
+.B >
+is a
+.B (
+then the string after the parenthesis is interpreted as an indirect offset.
+That means that the number after the parenthesis is used as a offset in
+the file. The value at that offset is read, and is used again as an offset
+in the file. Indirect offsets are of the form:
+.BI (( x [.[bsl]][+-][ y ]).
+The value of
+.I x
+is used as an offset in the file. A byte, short or long is read at that offset
+depending on the
+.B [bsl]
+type specifier. To that number the value of
+.I y
+is added and the result is used as an offset in the file. The default type
+if one is not specified is long.
.SH BUGS
The formats
-.I long
+.IR long ,
+.IR belong ,
+.IR lelong ,
+.IR short ,
+.IR beshort ,
+.IR leshort ,
+.IR date ,
+.IR bedate ,
and
-.I short
+.I ledate
are system-dependant; perhaps they should be specified as a number
of bytes (2B, 4B, etc),
since the files being recognized typically come from
a system on which the lengths are invariant.
.PP
-There should be more than one level of subtests,
-with the level possibly indicated by
-the number of
-.B >
-at the beginning of the line.
+There is (currently) no support for specified-endian data to be used in
+indirect offsets.
.SH SEE ALSO
.IR file (1)
\- the command that reads this file.
@@ -131,4 +188,4 @@ at the beginning of the line.
.\" the changes I posted to the S5R2 version.
.\"
.\" Modified for Ian Darwin's version of the file command.
-.\" @(#)$Header: /cvsroot/src/usr.bin/file/Attic/magic.5,v 1.2 1993/03/21 18:04:42 cgd Exp $
+.\" @(#)$Id: magic.5,v 1.3 1993/06/10 00:38:13 jtc Exp $
diff --git a/usr.bin/file/names.h b/usr.bin/file/names.h
index cdc641c489b..0a0d4040371 100644
--- a/usr.bin/file/names.h
+++ b/usr.bin/file/names.h
@@ -8,12 +8,9 @@
* 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.
+ * See LEGAL.NOTICE
*
- * 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 terms in the accompanying LEGAL.NOTICE file.
+ * $Id: names.h,v 1.2 1993/06/10 00:38:14 jtc Exp $
*/
/* these types are used to index the table 'types': keep em in sync! */
@@ -27,7 +24,7 @@
#define L_MAIL 7 /* Electronic mail */
#define L_NEWS 8 /* Usenet Netnews */
-char *types[] = {
+static char *types[] = {
"c program text",
"fortran program text",
"make commands text" ,
@@ -40,7 +37,7 @@ char *types[] = {
"can't happen error on names.h/types",
0};
-struct names {
+static struct names {
char *name;
short type;
} names[] = {
@@ -88,5 +85,6 @@ struct names {
{"Newsgroups:", L_NEWS},
{"Path:", L_NEWS},
{"Organization:",L_NEWS},
- 0};
+ {0}
+ };
#define NNAMES ((sizeof(names)/sizeof(struct names)) - 1)
diff --git a/usr.bin/file/patchlevel.h b/usr.bin/file/patchlevel.h
new file mode 100644
index 00000000000..ad0a5a742e9
--- /dev/null
+++ b/usr.bin/file/patchlevel.h
@@ -0,0 +1,34 @@
+#define FILE_VERSION_MAJOR 3
+#define patchlevel 9
+
+/*
+ * Patchlevel file for Ian Darwin's MAGIC command.
+ * $Id: patchlevel.h,v 1.1 1993/06/10 00:38:15 jtc Exp $
+ *
+ * $Log: patchlevel.h,v $
+ * Revision 1.1 1993/06/10 00:38:15 jtc
+ * Updated to Ian Darwin's latest release.
+ * Adds lots of neat features from most other vendors file(1) commands,
+ * plus (important!) little and big endian file types. This will alow
+ * us to detect and extract meaningful information from a many more
+ * file types.
+ *
+ * Revision 1.9 93/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.
+ *
+ */
+
diff --git a/usr.bin/file/print.c b/usr.bin/file/print.c
index cca2f799313..63d8671c7e5 100644
--- a/usr.bin/file/print.c
+++ b/usr.bin/file/print.c
@@ -27,71 +27,144 @@
#include <stdio.h>
#include <errno.h>
+#include <string.h>
+#if __STDC__
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+#include <stdlib.h>
+#include <unistd.h>
#include "file.h"
-#ifndef lint
-static char *moduleid =
- "@(#)$Header: /cvsroot/src/usr.bin/file/Attic/print.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
-#endif /* lint */
-
-#define MAXSTR 500
-
-extern char *progname;
-extern char *magicfile;
-extern int debug, nmagic; /* number of valid magic[]s */
-extern void showstr();
+#ifndef lint
+static char *moduleid =
+ "@(#)$Id: print.c,v 1.2 1993/06/10 00:38:17 jtc Exp $";
+#endif /* lint */
+void
mdump(m)
struct magic *m;
{
- (void) printf("%d\t%d\t%d\t%c\t",
- m->contflag,
+ static char *offs[] = { "absolute", "offset",
+ "indirect", "indirect-offset" };
+ static char *typ[] = { "invalid", "byte", "short", "invalid",
+ "long", "string", "date", "beshort",
+ "belong", "bedate", "leshort", "lelong",
+ "ledate" };
+ (void) fprintf(stderr, "[%s,%d,%s,%s%c,",
+ (m->flag >= 0 && m->flag < 4 ? offs[m->flag]: "*bad*"),
m->offset,
- m->type,
- m->reln,
- 0);
+ (m->type >= 0 && m->type < 13 ?
+ typ[(unsigned char) m->type] : "*bad*"),
+ m->reln & MASK ? "&" : "",
+ m->reln & ~MASK);
+ if (m->flag & INDIR)
+ (void) fprintf(stderr, "(%s,%d)",
+ (m->in.type >= 0 &&
+ m->in.type < 6 ? typ[(unsigned char) m->in.type] : "*bad*"),
+ m->in.offset);
+
if (m->type == STRING)
showstr(m->value.s);
else
- (void) printf("%d",m->value.l);
- (void) printf("\t%s", m->desc);
- (void) putchar('\n');
+ (void) fprintf(stderr, "%d",m->value.l);
+ (void) fprintf(stderr, ",%s", m->desc);
+ (void) fputs("]\n", stderr);
}
/*
- * error - print best error message possible and exit
+ * ckfputs - futs, but with error checking
+ * ckfprintf - fprintf, but with error checking
*/
-/*ARGSUSED1*/
+void
+ckfputs(str, fil)
+ const char *str;
+ FILE *fil;
+{
+ if (fputs(str,fil) == EOF)
+ error("write failed.\n");
+}
+
/*VARARGS*/
void
-error(s1, s2)
-char *s1, *s2;
+#if __STDC__
+ckfprintf(FILE *f, const char *fmt, ...)
+#else
+ckfprintf(va_alist)
+ va_dcl
+#endif
{
- warning(s1, s2);
- exit(1);
+ va_list va;
+#if __STDC__
+ va_start(va, fmt);
+#else
+ FILE *f;
+ const char *fmt;
+ va_start(va);
+ f = va_arg(va, FILE *);
+ fmt = va_arg(va, const char *);
+#endif
+ (void) vfprintf(f, fmt, va);
+ if (ferror(f))
+ error("write failed.\n");
+ va_end(va);
}
-/*ARGSUSED1*/
+/*
+ * error - print best error message possible and exit
+ */
/*VARARGS*/
-warning(f, a)
-char *f, *a;
+void
+#if __STDC__
+error(const char *f, ...)
+#else
+error(va_alist)
+ va_dcl
+#endif
{
- extern int errno, sys_nerr;
- extern char *sys_errlist[];
- int myerrno;
+ va_list va;
+#if __STDC__
+ va_start(va, f);
+#else
+ const char *f;
+ va_start(va);
+ f = va_arg(va, const char *);
+#endif
+ /* cuz we use stdout for most, stderr here */
+ (void) fflush(stdout);
- myerrno = errno;
+ if (progname != NULL)
+ (void) fprintf(stderr, "%s: ", progname);
+ (void) vfprintf(stderr, f, va);
+ va_end(va);
+ exit(1);
+}
+/*VARARGS*/
+void
+#if __STDC__
+magwarn(const char *f, ...)
+#else
+magwarn(va_alist)
+ va_dcl
+#endif
+{
+ va_list va;
+#if __STDC__
+ va_start(va, f);
+#else
+ const char *f;
+ va_start(va);
+ f = va_arg(va, const char *);
+#endif
/* 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);
+ if (progname != NULL)
+ (void) fprintf(stderr, "%s: %s, %d: ",
+ progname, magicfile, lineno);
+ (void) vfprintf(stderr, f, va);
+ va_end(va);
+ fputc('\n', stderr);
}
diff --git a/usr.bin/file/softmagic.c b/usr.bin/file/softmagic.c
index 91c22c61b75..4fce60f1479 100644
--- a/usr.bin/file/softmagic.c
+++ b/usr.bin/file/softmagic.c
@@ -26,29 +26,32 @@
*/
#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+
#include "file.h"
#ifndef lint
static char *moduleid =
- "@(#)$Header: /cvsroot/src/usr.bin/file/Attic/softmagic.c,v 1.1.1.1 1993/03/21 09:45:37 cgd Exp $";
+ "@(#)$Id: softmagic.c,v 1.2 1993/06/10 00:38:18 jtc 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;
+static int match __P((unsigned char *));
+static int mcheck __P((unsigned char *, struct magic *));
+static void mprint __P((struct magic *, unsigned char *));
/*
* 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;
+/*ARGSUSED1*/ /* nbytes passed for regularity, maybe need later */
+int
+softmagic(buf, nbytes)
+unsigned char *buf;
+int nbytes;
{
- magindex = 0;
if (match(buf))
return 1;
@@ -56,29 +59,100 @@ char *buf;
}
/*
- * go through the whole list, stopping if you find a match.
- * Be sure to process every continuation of this match.
+ * 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.
*/
+static int
match(s)
-char *s;
+unsigned char *s;
{
+ int magindex = 0;
+ int cont_level = 0;
+ int need_separator = 0;
+
while (magindex < nmagic) {
/* if main entry matches, print it... */
if (mcheck(s, &magic[magindex])) {
mprint(&magic[magindex],s);
+ /*
+ * If we printed something, we'll need to print
+ * a blank before we print something else.
+ */
+ if (magic[magindex].desc[0])
+ need_separator = 1;
/* and any continuations that match */
- while (magic[magindex+1].contflag &&
+ cont_level++;
+ while (magic[magindex+1].cont_level != 0 &&
magindex < nmagic) {
++magindex;
- if (mcheck(s, &magic[magindex])){
- (void) putchar(' ');
- mprint(&magic[magindex],s);
+ if (cont_level >=
+ magic[magindex].cont_level) {
+ if (cont_level >
+ magic[magindex].cont_level) {
+ /*
+ * We're at the end of the
+ * level-"cont_level"
+ * continuations.
+ */
+ cont_level =
+ magic[magindex].cont_level;
+ }
+ if (mcheck(s, &magic[magindex])) {
+ /*
+ * 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
+ && (magic[magindex].nospflag == 0)
+ && (magic[magindex].desc[0] != '\0')
+ ) {
+ (void) putchar(' ');
+ need_separator = 0;
+ }
+ mprint(&magic[magindex],s);
+ if (magic[magindex].desc[0])
+ need_separator = 1;
+
+ /*
+ * If we see any continuations
+ * at a higher level,
+ * process them.
+ */
+ cont_level++;
+ }
}
}
return 1; /* all through */
} else {
- /* main entry didn't match, flush its continuations */
- while (magic[magindex+1].contflag &&
+ /* main entry didn't match, flush its continuation */
+ while (magic[magindex+1].cont_level != 0 &&
magindex < nmagic) {
++magindex;
}
@@ -88,53 +162,101 @@ char *s;
return 0; /* no match at all */
}
-
-mprint(m,s)
+static void
+mprint(m, s)
struct magic *m;
-char *s;
+unsigned char *s;
{
register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
- char *pp, *strchr();
+ char *pp, *rt;
+ /* correct byte order dependancies */
switch (m->type) {
- case BYTE:
- (void) printf(m->desc, p->b);
+ case BESHORT:
+ p->h = (short)((p->hs[0]<<8)|(p->hs[1]));
break;
- case SHORT:
- (void) printf(m->desc, p->h);
+ case BELONG:
+ case BEDATE:
+ p->l = (long)
+ ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
break;
- case LONG:
- (void) printf(m->desc, p->l);
+ case LESHORT:
+ p->h = (short)((p->hs[1]<<8)|(p->hs[0]));
break;
- case STRING:
- if ((pp=strchr(p->s, '\n')) != NULL)
- *pp = '\0';
+ case LELONG:
+ case LEDATE:
+ p->l = (long)
+ ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
+ break;
+ }
+
+ switch (m->type) {
+ case BYTE:
+ (void) printf(m->desc,
+ (m->reln & MASK) ? p->b & m->mask : p->b);
+ break;
+ case SHORT:
+ case BESHORT:
+ case LESHORT:
+ (void) printf(m->desc,
+ (m->reln & MASK) ? p->h & m->mask : p->h);
+ break;
+ case LONG:
+ case BELONG:
+ case LELONG:
+ (void) printf(m->desc,
+ (m->reln & MASK) ? p->l & m->mask : p->l);
+ break;
+ case STRING:
+ if ((rt=strchr(p->s, '\n')) != NULL)
+ *rt = '\0';
(void) printf(m->desc, p->s);
+ if (rt)
+ *rt = '\n';
+ break;
+ case DATE:
+ case BEDATE:
+ case LEDATE:
+ pp = ctime((time_t*) &p->l);
+ if ((rt = strchr(pp, '\n')) != NULL)
+ *rt = '\0';
+ (void) printf(m->desc, pp);
+ if (rt)
+ *rt = '\n';
break;
default:
- warning("invalid m->type (%d) in mprint()", m->type);
+ error("invalid m->type (%d) in mprint().\n", m->type);
+ /*NOTREACHED*/
}
}
-int
+static int
mcheck(s, m)
-char *s;
+unsigned char *s;
struct magic *m;
{
register union VALUETYPE *p = (union VALUETYPE *)(s+m->offset);
register long l = m->value.l;
+ register long mask = m->mask;
register long v;
if (debug) {
(void) printf("mcheck: %10.10s ", s);
mdump(m);
}
+
+ if ( (m->value.s[0] == 'x') && (m->value.s[1] == '\0') ) {
+ printf("BOINK");
+ return 1;
+ }
+
switch (m->type) {
case BYTE:
v = p->b; break;
case SHORT:
v = p->h; break;
case LONG:
+ case DATE:
v = p->l; break;
case STRING:
l = 0;
@@ -143,6 +265,7 @@ struct magic *m;
* but ignoring any nulls. bcmp doesn't give -/+/0
* and isn't universally available anyway.
*/
+ v = 0;
{
register unsigned char *a = (unsigned char*)m->value.s;
register unsigned char *b = (unsigned char*)p->s;
@@ -153,12 +276,35 @@ struct magic *m;
break;
}
break;
+ case BESHORT:
+ v = (short)((p->hs[0]<<8)|(p->hs[1]));
+ break;
+ case BELONG:
+ case BEDATE:
+ v = (long)
+ ((p->hl[0]<<24)|(p->hl[1]<<16)|(p->hl[2]<<8)|(p->hl[3]));
+ break;
+ case LESHORT:
+ v = (short)((p->hs[1]<<8)|(p->hs[0]));
+ break;
+ case LELONG:
+ case LEDATE:
+ v = (long)
+ ((p->hl[3]<<24)|(p->hl[2]<<16)|(p->hl[1]<<8)|(p->hl[0]));
+ break;
default:
- warning("invalid type %d in mcheck()", m->type);
- return 0;
+ error("invalid type %d in mcheck().\n", m->type);
+ return -1;/*NOTREACHED*/
}
+ if (m->mask != 0L)
+ v &= m->mask;
+
switch (m->reln) {
+ case 'x':
+ return 1;
+ case '!':
+ return v != l;
case '=':
return v == l;
case '>':
@@ -166,9 +312,17 @@ struct magic *m;
case '<':
return v < l;
case '&':
- return v & l;
+ return (v & l) == l;
+ case '^':
+ return (v & l) != l;
+ case MASK | '=':
+ return (v & mask) == l;
+ case MASK | '>':
+ return (v & mask) > l;
+ case MASK | '<':
+ return (v & mask) < l;
default:
- warning("mcheck: can't happen: invalid relation %d", m->reln);
- return 0;
+ error("mcheck: can't happen: invalid relation %d.\n", m->reln);
+ return -1;/*NOTREACHED*/
}
}
diff --git a/usr.bin/file/tar.h b/usr.bin/file/tar.h
index 652e518efe0..876b4c091f9 100644
--- a/usr.bin/file/tar.h
+++ b/usr.bin/file/tar.h
@@ -4,6 +4,8 @@
* @(#)tar.h 1.20 86/10/29 Public Domain.
*
* Created 25 August 1985 by John Gilmore, ihnp4!hoptoad!gnu.
+ *
+ * $Id: tar.h,v 1.2 1993/06/10 00:38:20 jtc Exp $ # checkin only
*/
/*