Annotation of src/usr.bin/file/file.c, Revision 1.6
1.6 ! mickey 1: /* $OpenBSD: file.c,v 1.5 1997/02/09 23:58:22 millert 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.6 ! mickey 30: static char *moduleid = "$OpenBSD: file.c,v 1.5 1997/02/09 23:58:22 millert 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.5 millert 82: static void unwrap __P((char *fn));
83: #if 0
84: static int byteconv4 __P((int, int, int));
85: static short byteconv2 __P((int, int, int));
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.6 ! mickey 155: if (!didsomefiles)
! 156: err(2, USAGE, __progname);
! 157: } else {
1.1 deraadt 158: int i, wid, nw;
159: for (wid = 0, i = optind; i < argc; i++) {
160: nw = strlen(argv[i]);
161: if (nw > wid)
162: wid = nw;
163: }
164: for (; optind < argc; optind++)
165: process(argv[optind], wid);
166: }
167:
168: return 0;
169: }
170:
171:
172: /*
173: * unwrap -- read a file of filenames, do each one.
174: */
175: static void
176: unwrap(fn)
177: char *fn;
178: {
179: char buf[MAXPATHLEN];
180: FILE *f;
181: int wid = 0, cwid;
182:
1.5 millert 183: if (strcmp("-", fn) == 0) {
184: f = stdin;
185: wid = 1;
186: } else {
187: if ((f = fopen(fn, "r")) == NULL) {
1.6 ! mickey 188: err(1, "Cannot open `%s'", fn);
1.5 millert 189: /*NOTREACHED*/
190: }
191:
192: while (fgets(buf, sizeof(buf), f) != NULL) {
193: cwid = strlen(buf) - 1;
194: if (cwid > wid)
195: wid = cwid;
196: }
1.1 deraadt 197:
1.5 millert 198: rewind(f);
1.1 deraadt 199: }
200:
1.5 millert 201: while (fgets(buf, sizeof(buf), f) != NULL) {
1.1 deraadt 202: buf[strlen(buf)-1] = '\0';
203: process(buf, wid);
204: }
205:
206: (void) fclose(f);
207: }
208:
209:
1.5 millert 210: #if 0
211: /*
212: * byteconv4
213: * Input:
214: * from 4 byte quantity to convert
215: * same whether to perform byte swapping
216: * big_endian whether we are a big endian host
217: */
218: static int
219: byteconv4(from, same, big_endian)
220: int from;
221: int same;
222: int big_endian;
223: {
224: if (same)
225: return from;
226: else if (big_endian) /* lsb -> msb conversion on msb */
227: {
228: union {
229: int i;
230: char c[4];
231: } retval, tmpval;
232:
233: tmpval.i = from;
234: retval.c[0] = tmpval.c[3];
235: retval.c[1] = tmpval.c[2];
236: retval.c[2] = tmpval.c[1];
237: retval.c[3] = tmpval.c[0];
238:
239: return retval.i;
240: }
241: else
242: return ntohl(from); /* msb -> lsb conversion on lsb */
243: }
244:
245: /*
246: * byteconv2
247: * Same as byteconv4, but for shorts
248: */
249: static short
250: byteconv2(from, same, big_endian)
251: int from;
252: int same;
253: int big_endian;
254: {
255: if (same)
256: return from;
257: else if (big_endian) /* lsb -> msb conversion on msb */
258: {
259: union {
260: short s;
261: char c[2];
262: } retval, tmpval;
263:
264: tmpval.s = (short) from;
265: retval.c[0] = tmpval.c[1];
266: retval.c[1] = tmpval.c[0];
267:
268: return retval.s;
269: }
270: else
271: return ntohs(from); /* msb -> lsb conversion on lsb */
272: }
273: #endif
274:
1.1 deraadt 275: /*
276: * process - process input file
277: */
278: void
279: process(inname, wid)
280: const char *inname;
281: int wid;
282: {
283: int fd = 0;
284: static const char stdname[] = "standard input";
285: unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
286: struct stat sb;
287: int nbytes = 0; /* number of bytes read from a datafile */
288: char match = '\0';
289:
290: if (strcmp("-", inname) == 0) {
291: if (fstat(0, &sb)<0) {
1.6 ! mickey 292: err(1, "cannot fstat `%s'", stdname);
1.1 deraadt 293: /*NOTREACHED*/
294: }
295: inname = stdname;
296: }
297:
298: if (wid > 0)
299: (void) printf("%s:%*s ", inname,
300: (int) (wid - strlen(inname)), "");
301:
302: if (inname != stdname) {
303: /*
304: * first try judging the file based on its filesystem status
305: */
306: if (fsmagic(inname, &sb) != 0) {
307: putchar('\n');
308: return;
309: }
310:
311: if ((fd = open(inname, O_RDONLY)) < 0) {
312: /* We can't open it, but we were able to stat it. */
313: if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
314: if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
315: ckfprintf(stdout, "can't read `%s' (%s).\n",
316: inname, strerror(errno));
317: return;
318: }
319: }
320:
321:
322: /*
323: * try looking at the first HOWMANY bytes
324: */
325: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
1.6 ! mickey 326: err(1, "read failed");
1.1 deraadt 327: /*NOTREACHED*/
328: }
329:
330: if (nbytes == 0)
331: ckfputs("empty", stdout);
332: else {
333: buf[nbytes++] = '\0'; /* null-terminate it */
334: match = tryit(buf, nbytes, zflag);
335: }
336:
1.5 millert 337: #ifdef BUILTIN_ELF
338: if (match == 's' && nbytes > 5)
339: tryelf(fd, buf, nbytes);
340: #endif
1.1 deraadt 341:
1.5 millert 342: if (inname != stdname) {
343: #ifdef RESTORE_TIME
1.1 deraadt 344: /*
1.5 millert 345: * Try to restore access, modification times if read it.
1.1 deraadt 346: */
1.5 millert 347: # ifdef USE_UTIMES
348: struct timeval utsbuf[2];
349: utsbuf[0].tv_sec = sb.st_atime;
350: utsbuf[1].tv_sec = sb.st_mtime;
351:
352: (void) utimes(inname, utsbuf); /* don't care if loses */
353: # else
354: struct utimbuf utbuf;
355:
356: utbuf.actime = sb.st_atime;
357: utbuf.modtime = sb.st_mtime;
358: (void) utime(inname, &utbuf); /* don't care if loses */
359: # endif
1.1 deraadt 360: #endif
361: (void) close(fd);
1.5 millert 362: }
1.1 deraadt 363: (void) putchar('\n');
364: }
365:
366:
367: int
368: tryit(buf, nb, zflag)
369: unsigned char *buf;
370: int nb, zflag;
371: {
372: /* try compression stuff */
373: if (zflag && zmagic(buf, nb))
374: return 'z';
375:
376: /* try tests in /etc/magic (or surrogate magic file) */
377: if (softmagic(buf, nb))
378: return 's';
379:
380: /* try known keywords, check whether it is ASCII */
381: if (ascmagic(buf, nb))
382: return 'a';
1.5 millert 383:
384: /* see if it's international language text */
385: if (internatmagic(buf, nb))
386: return 'i';
1.1 deraadt 387:
388: /* abandon hope, all ye who remain here */
389: ckfputs("data", stdout);
390: return '\0';
391: }