Annotation of src/usr.bin/file/file.c, Revision 1.8
1.8 ! millert 1: /* $OpenBSD: file.c,v 1.7 1999/02/19 00:28:37 deraadt Exp $ */
1.5 millert 2:
1.1 deraadt 3: /*
4: * file - find type of a file or files - main program.
5: *
6: * Copyright (c) Ian F. Darwin, 1987.
7: * Written by Ian F. Darwin.
8: *
9: * This software is not subject to any license of the American Telephone
10: * and Telegraph Company or of the Regents of the University of California.
11: *
12: * Permission is granted to anyone to use this software for any purpose on
13: * any computer system, and to alter it and redistribute it freely, subject
14: * to the following restrictions:
15: *
16: * 1. The author is not responsible for the consequences of use of this
17: * software, no matter how awful, even if they arise from flaws in it.
18: *
19: * 2. The origin of this software must not be misrepresented, either by
20: * explicit claim or by omission. Since few users ever read sources,
21: * credits must appear in the documentation.
22: *
23: * 3. Altered versions must be plainly marked as such, and must not be
24: * misrepresented as being the original software. Since few users
25: * ever read sources, credits must appear in the documentation.
26: *
27: * 4. This notice may not be removed or altered.
28: */
29: #ifndef lint
1.8 ! millert 30: static char *moduleid = "$OpenBSD: file.c,v 1.7 1999/02/19 00:28:37 deraadt Exp $";
1.1 deraadt 31: #endif /* lint */
32:
33: #include <stdio.h>
34: #include <stdlib.h>
35: #include <string.h>
36: #include <sys/types.h>
37: #include <sys/param.h> /* for MAXPATHLEN */
38: #include <sys/stat.h>
39: #include <fcntl.h> /* for open() */
40: #if (__COHERENT__ >= 0x420)
1.5 millert 41: # include <sys/utime.h>
1.1 deraadt 42: #else
1.5 millert 43: # ifdef USE_UTIMES
44: # include <sys/time.h>
45: # else
46: # include <utime.h>
47: # endif
1.1 deraadt 48: #endif
49: #include <unistd.h> /* for read() */
1.6 mickey 50: #include <err.h>
1.1 deraadt 51:
1.5 millert 52: #include <netinet/in.h> /* for byte swapping */
1.1 deraadt 53:
54: #include "patchlevel.h"
55: #include "file.h"
56:
57: #ifdef S_IFLNK
1.2 deraadt 58: # define USAGE "Usage: %s [-vczL] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 59: #else
1.2 deraadt 60: # define USAGE "Usage: %s [-vcz] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 61: #endif
62:
63: #ifndef MAGIC
64: # define MAGIC "/etc/magic"
65: #endif
66:
67: int /* Global command-line options */
68: debug = 0, /* debugging */
69: lflag = 0, /* follow Symlinks (BSD only) */
70: zflag = 0; /* follow (uncompress) compressed files */
71:
72: int /* Misc globals */
73: nmagic = 0; /* number of valid magic[]s */
74:
75: struct magic *magic; /* array of magic entries */
76:
77: char *magicfile; /* where magic be found */
78:
79: int lineno; /* line number in the magic file */
80:
81:
1.8 ! millert 82: static void unwrap(char *fn);
1.5 millert 83: #if 0
1.8 ! millert 84: static int byteconv4(int, int, int);
! 85: static short byteconv2(int, int, int);
1.5 millert 86: #endif
1.1 deraadt 87:
88: /*
89: * main - parse arguments and handle options
90: */
91: int
92: main(argc, argv)
93: int argc;
94: char *argv[];
95: {
96: int c;
97: int check = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
1.6 mickey 98: extern char *__progname;
1.1 deraadt 99:
100: if (!(magicfile = getenv("MAGIC")))
101: magicfile = MAGIC;
102:
1.4 millert 103: while ((c = getopt(argc, argv, "vcdf:Lm:z")) != -1)
1.1 deraadt 104: switch (c) {
105: case 'v':
1.6 mickey 106: (void) printf("%s-%d.%d\n", __progname,
1.1 deraadt 107: FILE_VERSION_MAJOR, patchlevel);
108: return 1;
109: case 'c':
110: ++check;
111: break;
112: case 'd':
113: ++debug;
114: break;
115: case 'f':
116: if (!app) {
117: ret = apprentice(magicfile, check);
118: if (check)
119: exit(ret);
120: app = 1;
121: }
122: unwrap(optarg);
123: ++didsomefiles;
124: break;
125: #ifdef S_IFLNK
126: case 'L':
127: ++lflag;
128: break;
129: #endif
130: case 'm':
131: magicfile = optarg;
132: break;
133: case 'z':
134: zflag++;
135: break;
136: case '?':
137: default:
138: errflg++;
139: break;
140: }
141:
142: if (errflg) {
1.6 mickey 143: (void) fprintf(stderr, USAGE, __progname);
1.1 deraadt 144: exit(2);
145: }
146:
147: if (!app) {
148: ret = apprentice(magicfile, check);
149: if (check)
150: exit(ret);
151: app = 1;
152: }
153:
154: if (optind == argc) {
1.7 deraadt 155: if (!didsomefiles) {
156: fprintf(stderr, USAGE, __progname);
157: exit(2);
158: }
1.6 mickey 159: } else {
1.1 deraadt 160: int i, wid, nw;
161: for (wid = 0, i = optind; i < argc; i++) {
162: nw = strlen(argv[i]);
163: if (nw > wid)
164: wid = nw;
165: }
166: for (; optind < argc; optind++)
167: process(argv[optind], wid);
168: }
169:
170: return 0;
171: }
172:
173:
174: /*
175: * unwrap -- read a file of filenames, do each one.
176: */
177: static void
178: unwrap(fn)
179: char *fn;
180: {
181: char buf[MAXPATHLEN];
182: FILE *f;
183: int wid = 0, cwid;
184:
1.5 millert 185: if (strcmp("-", fn) == 0) {
186: f = stdin;
187: wid = 1;
188: } else {
189: if ((f = fopen(fn, "r")) == NULL) {
1.6 mickey 190: err(1, "Cannot open `%s'", fn);
1.5 millert 191: /*NOTREACHED*/
192: }
193:
194: while (fgets(buf, sizeof(buf), f) != NULL) {
195: cwid = strlen(buf) - 1;
196: if (cwid > wid)
197: wid = cwid;
198: }
1.1 deraadt 199:
1.5 millert 200: rewind(f);
1.1 deraadt 201: }
202:
1.5 millert 203: while (fgets(buf, sizeof(buf), f) != NULL) {
1.1 deraadt 204: buf[strlen(buf)-1] = '\0';
205: process(buf, wid);
206: }
207:
208: (void) fclose(f);
209: }
210:
211:
1.5 millert 212: #if 0
213: /*
214: * byteconv4
215: * Input:
216: * from 4 byte quantity to convert
217: * same whether to perform byte swapping
218: * big_endian whether we are a big endian host
219: */
220: static int
221: byteconv4(from, same, big_endian)
222: int from;
223: int same;
224: int big_endian;
225: {
226: if (same)
227: return from;
228: else if (big_endian) /* lsb -> msb conversion on msb */
229: {
230: union {
231: int i;
232: char c[4];
233: } retval, tmpval;
234:
235: tmpval.i = from;
236: retval.c[0] = tmpval.c[3];
237: retval.c[1] = tmpval.c[2];
238: retval.c[2] = tmpval.c[1];
239: retval.c[3] = tmpval.c[0];
240:
241: return retval.i;
242: }
243: else
244: return ntohl(from); /* msb -> lsb conversion on lsb */
245: }
246:
247: /*
248: * byteconv2
249: * Same as byteconv4, but for shorts
250: */
251: static short
252: byteconv2(from, same, big_endian)
253: int from;
254: int same;
255: int big_endian;
256: {
257: if (same)
258: return from;
259: else if (big_endian) /* lsb -> msb conversion on msb */
260: {
261: union {
262: short s;
263: char c[2];
264: } retval, tmpval;
265:
266: tmpval.s = (short) from;
267: retval.c[0] = tmpval.c[1];
268: retval.c[1] = tmpval.c[0];
269:
270: return retval.s;
271: }
272: else
273: return ntohs(from); /* msb -> lsb conversion on lsb */
274: }
275: #endif
276:
1.1 deraadt 277: /*
278: * process - process input file
279: */
280: void
281: process(inname, wid)
282: const char *inname;
283: int wid;
284: {
285: int fd = 0;
286: static const char stdname[] = "standard input";
287: unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
288: struct stat sb;
289: int nbytes = 0; /* number of bytes read from a datafile */
290: char match = '\0';
291:
292: if (strcmp("-", inname) == 0) {
293: if (fstat(0, &sb)<0) {
1.6 mickey 294: err(1, "cannot fstat `%s'", stdname);
1.1 deraadt 295: /*NOTREACHED*/
296: }
297: inname = stdname;
298: }
299:
300: if (wid > 0)
301: (void) printf("%s:%*s ", inname,
302: (int) (wid - strlen(inname)), "");
303:
304: if (inname != stdname) {
305: /*
306: * first try judging the file based on its filesystem status
307: */
308: if (fsmagic(inname, &sb) != 0) {
309: putchar('\n');
310: return;
311: }
312:
313: if ((fd = open(inname, O_RDONLY)) < 0) {
314: /* We can't open it, but we were able to stat it. */
315: if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
316: if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
317: ckfprintf(stdout, "can't read `%s' (%s).\n",
318: inname, strerror(errno));
319: return;
320: }
321: }
322:
323:
324: /*
325: * try looking at the first HOWMANY bytes
326: */
327: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
1.6 mickey 328: err(1, "read failed");
1.1 deraadt 329: /*NOTREACHED*/
330: }
331:
332: if (nbytes == 0)
333: ckfputs("empty", stdout);
334: else {
335: buf[nbytes++] = '\0'; /* null-terminate it */
336: match = tryit(buf, nbytes, zflag);
337: }
338:
1.5 millert 339: #ifdef BUILTIN_ELF
340: if (match == 's' && nbytes > 5)
341: tryelf(fd, buf, nbytes);
342: #endif
1.1 deraadt 343:
1.5 millert 344: if (inname != stdname) {
345: #ifdef RESTORE_TIME
1.1 deraadt 346: /*
1.5 millert 347: * Try to restore access, modification times if read it.
1.1 deraadt 348: */
1.5 millert 349: # ifdef USE_UTIMES
350: struct timeval utsbuf[2];
351: utsbuf[0].tv_sec = sb.st_atime;
352: utsbuf[1].tv_sec = sb.st_mtime;
353:
354: (void) utimes(inname, utsbuf); /* don't care if loses */
355: # else
356: struct utimbuf utbuf;
357:
358: utbuf.actime = sb.st_atime;
359: utbuf.modtime = sb.st_mtime;
360: (void) utime(inname, &utbuf); /* don't care if loses */
361: # endif
1.1 deraadt 362: #endif
363: (void) close(fd);
1.5 millert 364: }
1.1 deraadt 365: (void) putchar('\n');
366: }
367:
368:
369: int
370: tryit(buf, nb, zflag)
371: unsigned char *buf;
372: int nb, zflag;
373: {
374: /* try compression stuff */
375: if (zflag && zmagic(buf, nb))
376: return 'z';
377:
378: /* try tests in /etc/magic (or surrogate magic file) */
379: if (softmagic(buf, nb))
380: return 's';
381:
382: /* try known keywords, check whether it is ASCII */
383: if (ascmagic(buf, nb))
384: return 'a';
1.5 millert 385:
386: /* see if it's international language text */
387: if (internatmagic(buf, nb))
388: return 'i';
1.1 deraadt 389:
390: /* abandon hope, all ye who remain here */
391: ckfputs("data", stdout);
392: return '\0';
393: }