2 * file - find type of a file or files - main program.
4 * Copyright (c) Ian F. Darwin, 1987.
5 * Written by Ian F. Darwin.
7 * This software is not subject to any license of the American Telephone
8 * and Telegraph Company or of the Regents of the University of California.
10 * Permission is granted to anyone to use this software for any purpose on
11 * any computer system, and to alter it and redistribute it freely, subject
12 * to the following restrictions:
14 * 1. The author is not responsible for the consequences of use of this
15 * software, no matter how awful, even if they arise from flaws in it.
17 * 2. The origin of this software must not be misrepresented, either by
18 * explicit claim or by omission. Since few users ever read sources,
19 * credits must appear in the documentation.
21 * 3. Altered versions must be plainly marked as such, and must not be
22 * misrepresented as being the original software. Since few users
23 * ever read sources, credits must appear in the documentation.
25 * 4. This notice may not be removed or altered.
32 #include <sys/param.h> /* for MAXPATHLEN */
33 #include <fcntl.h> /* for open() */
35 # if (__COHERENT__ >= 0x420)
36 # include <sys/utime.h>
39 # include <sys/time.h>
46 #include <unistd.h> /* for read() */
53 #include <getopt.h> /* for long options (is this portable?)*/
56 #include <netinet/in.h> /* for byte swapping */
58 #include "patchlevel.h"
61 FILE_RCSID("@(#)$Id: file.c,v 1.69 2003/02/27 20:47:46 christos Exp $")
66 # define USAGE "Usage: %s [-bciknsvzL] [-f namefile] [-m magicfiles] file...\n"
68 # define USAGE "Usage: %s [-bciknsvz] [-f namefile] [-m magicfiles] file...\n"
72 static char *apptypeName = NULL;
73 int os2_apptype (const char *fn, char *buf, int nb);
77 # define MAGIC "/etc/magic"
81 #define MAXPATHLEN 512
84 int /* Global command-line options */
85 debug = 0, /* debugging */
86 lflag = 0, /* follow Symlinks (BSD only) */
87 bflag = 0, /* brief output format */
88 zflag = 0, /* follow (uncompress) compressed files */
89 sflag = 0, /* read block special files */
91 nopad = 0, /* Don't pad output */
92 nobuffer = 0, /* Do not buffer stdout */
93 kflag = 0; /* Keep going after the first match */
95 int /* Misc globals */
96 nmagic = 0; /* number of valid magic[]s */
98 struct magic *magic; /* array of magic entries */
100 const char *magicfile = 0; /* where the magic is */
101 const char *default_magicfile = MAGIC;
103 char separator = ':'; /* Default field separator */
105 char *progname; /* used throughout */
106 int lineno; /* line number in the magic file */
109 static void unwrap(char *fn);
110 static void usage(void);
111 #ifdef HAVE_GETOPT_LONG
112 static void help(void);
115 static int byteconv4(int, int, int);
116 static short byteconv2(int, int, int);
119 int main(int, char *[]);
122 * main - parse arguments and handle options
125 main(int argc, char **argv)
128 int action = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
129 char *mime, *home, *usermagic;
131 #define OPTSTRING "bcdf:F:ikm:nNsvzCL"
132 #ifdef HAVE_GETOPT_LONG
134 static struct option long_options[] =
136 {"version", 0, 0, 'v'},
138 {"brief", 0, 0, 'b'},
139 {"checking-printout", 0, 0, 'c'},
140 {"debug", 0, 0, 'd'},
141 {"files-from", 1, 0, 'f'},
142 {"separator", 1, 0, 'F'},
144 {"keep-going", 0, 0, 'k'},
146 {"dereference", 0, 0, 'L'},
148 {"magic-file", 1, 0, 'm'},
149 {"uncompress", 0, 0, 'z'},
150 {"no-buffer", 0, 0, 'n'},
151 {"no-pad", 0, 0, 'N'},
152 {"special-files", 0, 0, 's'},
153 {"compile", 0, 0, 'C'},
159 setlocale(LC_CTYPE, ""); /* makes islower etc work for other langs */
163 /* sh-like wildcard expansion! Shouldn't hurt at least ... */
164 _wildcard(&argc, &argv);
167 if ((progname = strrchr(argv[0], '/')) != NULL)
172 magicfile = default_magicfile;
173 if ((usermagic = getenv("MAGIC")) != NULL)
174 magicfile = usermagic;
176 if ((home = getenv("HOME")) != NULL) {
177 if ((usermagic = malloc(strlen(home) + 8)) != NULL) {
178 (void)strcpy(usermagic, home);
179 (void)strcat(usermagic, "/.magic");
180 if (stat(usermagic, &sb)<0)
183 magicfile = usermagic;
187 #ifndef HAVE_GETOPT_LONG
188 while ((c = getopt(argc, argv, OPTSTRING)) != -1)
190 while ((c = getopt_long(argc, argv, OPTSTRING, long_options,
194 #ifdef HAVE_GETOPT_LONG
214 ret = apprentice(magicfile, action);
227 if ((mime = malloc(strlen(magicfile) + 6)) != NULL) {
228 (void)strcpy(mime, magicfile);
229 (void)strcat(mime, ".mime");
249 (void) fprintf(stdout, "%s-%d.%d\n", progname,
250 FILE_VERSION_MAJOR, patchlevel);
251 (void) fprintf(stdout, "magic file from %s\n",
273 ret = apprentice(magicfile, action);
279 if (optind == argc) {
286 for (wid = 0, i = optind; i < argc; i++) {
287 nw = strlen(argv[i]);
291 for (; optind < argc; optind++)
292 process(argv[optind], wid);
300 * unwrap -- read a file of filenames, do each one.
305 char buf[MAXPATHLEN];
309 if (strcmp("-", fn) == 0) {
313 if ((f = fopen(fn, "r")) == NULL) {
314 error("Cannot open `%s' (%s).\n", fn, strerror(errno));
318 while (fgets(buf, MAXPATHLEN, f) != NULL) {
319 cwid = strlen(buf) - 1;
327 while (fgets(buf, MAXPATHLEN, f) != NULL) {
328 buf[strlen(buf)-1] = '\0';
331 (void) fflush(stdout);
342 * from 4 byte quantity to convert
343 * same whether to perform byte swapping
344 * big_endian whether we are a big endian host
347 byteconv4(int from, int same, int big_endian)
351 else if (big_endian) { /* lsb -> msb conversion on msb */
358 retval.c[0] = tmpval.c[3];
359 retval.c[1] = tmpval.c[2];
360 retval.c[2] = tmpval.c[1];
361 retval.c[3] = tmpval.c[0];
366 return ntohl(from); /* msb -> lsb conversion on lsb */
371 * Same as byteconv4, but for shorts
374 byteconv2(int from, int same, int big_endian)
378 else if (big_endian) { /* lsb -> msb conversion on msb */
384 tmpval.s = (short) from;
385 retval.c[0] = tmpval.c[1];
386 retval.c[1] = tmpval.c[0];
391 return ntohs(from); /* msb -> lsb conversion on lsb */
396 * process - process input file
399 process(const char *inname, int wid)
402 static const char stdname[] = "standard input";
403 unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
405 int nbytes = 0; /* number of bytes read from a datafile */
408 if (strcmp("-", inname) == 0) {
409 if (fstat(0, &sb)<0) {
410 error("cannot fstat `%s' (%s).\n", stdname,
417 if (wid > 0 && !bflag)
418 (void) printf("%s%c%*s", inname, separator,
419 (int) (nopad ? 0 : 1 + (wid - strlen(inname))), "");
421 if (inname != stdname) {
423 * first try judging the file based on its filesystem status
425 if (fsmagic(inname, &sb) != 0) {
430 if ((fd = open(inname, O_RDONLY)) < 0) {
431 /* We can't open it, but we were able to stat it. */
432 if (sb.st_mode & 0002) ckfputs("writable, ", stdout);
433 if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
434 ckfprintf(stdout, "can't read `%s' (%s).\n",
435 inname, strerror(errno));
442 * try looking at the first HOWMANY bytes
444 if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
445 error("read failed (%s).\n", strerror(errno));
450 ckfputs(iflag ? "application/x-empty" : "empty", stdout);
452 buf[nbytes++] = '\0'; /* null-terminate it */
453 match = tryit(inname, buf, nbytes, zflag);
457 if (match == 's' && nbytes > 5) {
459 * We matched something in the file, so this *might*
460 * be an ELF file, and the file is at least 5 bytes long,
461 * so if it's an ELF file it has at least one byte
462 * past the ELF magic number - try extracting information
463 * from the ELF headers that can't easily be extracted
464 * with rules in the magic file.
466 tryelf(fd, buf, nbytes);
470 if (inname != stdname) {
473 * Try to restore access, modification times if read it.
474 * This is really *bad* because it will modify the status
475 * time of the file... And of course this will affect
479 struct timeval utsbuf[2];
480 utsbuf[0].tv_sec = sb.st_atime;
481 utsbuf[1].tv_sec = sb.st_mtime;
483 (void) utimes(inname, utsbuf); /* don't care if loses */
485 struct utimbuf utbuf;
487 utbuf.actime = sb.st_atime;
488 utbuf.modtime = sb.st_mtime;
489 (void) utime(inname, &utbuf); /* don't care if loses */
494 (void) putchar('\n');
499 tryit(const char *fn, unsigned char *buf, int nb, int zfl)
503 * The main work is done here!
504 * We have the file name and/or the data buffer to be identified.
509 * Ok, here's the right place to add a call to some os-specific
512 if (os2_apptype(fn, buf, nb) == 1)
515 /* try compression stuff */
516 if (zfl && zmagic(fn, buf, nb))
519 /* try tests in /etc/magic (or surrogate magic file) */
520 if (softmagic(buf, nb))
523 /* try known keywords, check whether it is ASCII */
524 if (ascmagic(buf, nb))
527 /* abandon hope, all ye who remain here */
528 ckfputs(iflag ? "application/octet-stream" : "data", stdout);
535 (void)fprintf(stderr, USAGE, progname);
536 (void)fprintf(stderr, "Usage: %s -C [-m magic]\n", progname);
537 #ifdef HAVE_GETOPT_LONG
538 (void)fputs("Try `file --help' for more information.\n", stderr);
543 #ifdef HAVE_GETOPT_LONG
548 "Usage: file [OPTION]... [FILE]...\n"
549 "Determine file type of FILEs.\n"
551 " -m, --magic-file LIST use LIST as a colon-separated list of magic\n"
553 " -z, --uncompress try to look inside compressed files\n"
554 " -b, --brief do not prepend filenames to output lines\n"
555 " -c, --checking-printout print the parsed form of the magic file, use in\n"
556 " conjunction with -m to debug a new magic file\n"
557 " before installing it\n"
558 " -f, --files-from FILE read the filenames to be examined from FILE\n"
559 " -i, --mime output mime type strings\n"
560 " -k, --keep-going don't stop at the first match\n"
561 " -L, --dereference causes symlinks to be followed\n"
562 " -n, --no-buffer do not buffer output\n"
563 " -s, --special-files treat special (block/char devices) files as\n"
565 " --help display this help and exit\n"
566 " --version output version information and exit\n"