Annotation of src/usr.bin/file/file.c, Revision 1.10
1.10 ! henning 1: /* $OpenBSD: file.c,v 1.9 2002/11/29 00:27:03 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.10 ! henning 30: static char *moduleid = "$OpenBSD: file.c,v 1.9 2002/11/29 00:27:03 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.9 millert 58: # define USAGE "Usage: %s [-vbczL] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 59: #else
1.9 millert 60: # define USAGE "Usage: %s [-vbcz] [-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 */
1.9 millert 69: bflag = 0, /* Don't print filename */
1.1 deraadt 70: lflag = 0, /* follow Symlinks (BSD only) */
71: zflag = 0; /* follow (uncompress) compressed files */
72:
73: int /* Misc globals */
74: nmagic = 0; /* number of valid magic[]s */
75:
76: struct magic *magic; /* array of magic entries */
77:
78: char *magicfile; /* where magic be found */
79:
80: int lineno; /* line number in the magic file */
81:
82:
1.8 millert 83: static void unwrap(char *fn);
1.5 millert 84: #if 0
1.8 millert 85: static int byteconv4(int, int, int);
86: static short byteconv2(int, int, int);
1.5 millert 87: #endif
1.1 deraadt 88:
89: /*
90: * main - parse arguments and handle options
91: */
92: int
93: main(argc, argv)
94: int argc;
95: char *argv[];
96: {
97: int c;
98: int check = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
1.6 mickey 99: extern char *__progname;
1.1 deraadt 100:
101: if (!(magicfile = getenv("MAGIC")))
102: magicfile = MAGIC;
103:
1.9 millert 104: while ((c = getopt(argc, argv, "bvcdf:Lm:z")) != -1)
1.1 deraadt 105: switch (c) {
106: case 'v':
1.6 mickey 107: (void) printf("%s-%d.%d\n", __progname,
1.1 deraadt 108: FILE_VERSION_MAJOR, patchlevel);
109: return 1;
1.9 millert 110: case 'b':
111: ++bflag;
112: break;
1.1 deraadt 113: case 'c':
114: ++check;
115: break;
116: case 'd':
117: ++debug;
118: break;
119: case 'f':
120: if (!app) {
121: ret = apprentice(magicfile, check);
122: if (check)
123: exit(ret);
124: app = 1;
125: }
126: unwrap(optarg);
127: ++didsomefiles;
128: break;
129: #ifdef S_IFLNK
130: case 'L':
131: ++lflag;
132: break;
133: #endif
134: case 'm':
135: magicfile = optarg;
136: break;
137: case 'z':
138: zflag++;
139: break;
140: case '?':
141: default:
142: errflg++;
143: break;
144: }
145:
146: if (errflg) {
1.6 mickey 147: (void) fprintf(stderr, USAGE, __progname);
1.1 deraadt 148: exit(2);
149: }
150:
151: if (!app) {
152: ret = apprentice(magicfile, check);
153: if (check)
154: exit(ret);
155: app = 1;
156: }
157:
158: if (optind == argc) {
1.7 deraadt 159: if (!didsomefiles) {
160: fprintf(stderr, USAGE, __progname);
161: exit(2);
162: }
1.6 mickey 163: } else {
1.1 deraadt 164: int i, wid, nw;
165: for (wid = 0, i = optind; i < argc; i++) {
166: nw = strlen(argv[i]);
167: if (nw > wid)
168: wid = nw;
169: }
170: for (; optind < argc; optind++)
171: process(argv[optind], wid);
172: }
173:
174: return 0;
175: }
176:
177:
178: /*
179: * unwrap -- read a file of filenames, do each one.
180: */
181: static void
182: unwrap(fn)
183: char *fn;
184: {
185: char buf[MAXPATHLEN];
186: FILE *f;
187: int wid = 0, cwid;
188:
1.5 millert 189: if (strcmp("-", fn) == 0) {
190: f = stdin;
191: wid = 1;
192: } else {
193: if ((f = fopen(fn, "r")) == NULL) {
1.6 mickey 194: err(1, "Cannot open `%s'", fn);
1.5 millert 195: /*NOTREACHED*/
196: }
197:
198: while (fgets(buf, sizeof(buf), f) != NULL) {
199: cwid = strlen(buf) - 1;
200: if (cwid > wid)
201: wid = cwid;
202: }
1.1 deraadt 203:
1.5 millert 204: rewind(f);
1.1 deraadt 205: }
206:
1.5 millert 207: while (fgets(buf, sizeof(buf), f) != NULL) {
1.1 deraadt 208: buf[strlen(buf)-1] = '\0';
209: process(buf, wid);
210: }
211:
212: (void) fclose(f);
213: }
214:
215:
1.5 millert 216: #if 0
217: /*
218: * byteconv4
219: * Input:
220: * from 4 byte quantity to convert
221: * same whether to perform byte swapping
222: * big_endian whether we are a big endian host
223: */
224: static int
225: byteconv4(from, same, big_endian)
226: int from;
227: int same;
228: int big_endian;
229: {
230: if (same)
231: return from;
232: else if (big_endian) /* lsb -> msb conversion on msb */
233: {
234: union {
235: int i;
236: char c[4];
237: } retval, tmpval;
238:
239: tmpval.i = from;
240: retval.c[0] = tmpval.c[3];
241: retval.c[1] = tmpval.c[2];
242: retval.c[2] = tmpval.c[1];
243: retval.c[3] = tmpval.c[0];
244:
245: return retval.i;
246: }
247: else
248: return ntohl(from); /* msb -> lsb conversion on lsb */
249: }
250:
251: /*
252: * byteconv2
253: * Same as byteconv4, but for shorts
254: */
255: static short
256: byteconv2(from, same, big_endian)
257: int from;
258: int same;
259: int big_endian;
260: {
261: if (same)
262: return from;
263: else if (big_endian) /* lsb -> msb conversion on msb */
264: {
265: union {
266: short s;
267: char c[2];
268: } retval, tmpval;
269:
270: tmpval.s = (short) from;
271: retval.c[0] = tmpval.c[1];
272: retval.c[1] = tmpval.c[0];
273:
274: return retval.s;
275: }
276: else
277: return ntohs(from); /* msb -> lsb conversion on lsb */
278: }
279: #endif
280:
1.1 deraadt 281: /*
282: * process - process input file
283: */
284: void
285: process(inname, wid)
286: const char *inname;
287: int wid;
288: {
289: int fd = 0;
290: static const char stdname[] = "standard input";
291: unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
292: struct stat sb;
293: int nbytes = 0; /* number of bytes read from a datafile */
294: char match = '\0';
295:
296: if (strcmp("-", inname) == 0) {
297: if (fstat(0, &sb)<0) {
1.6 mickey 298: err(1, "cannot fstat `%s'", stdname);
1.1 deraadt 299: /*NOTREACHED*/
300: }
301: inname = stdname;
302: }
303:
1.9 millert 304: if (wid > 0 && !bflag)
1.1 deraadt 305: (void) printf("%s:%*s ", inname,
306: (int) (wid - strlen(inname)), "");
307:
308: if (inname != stdname) {
309: /*
310: * first try judging the file based on its filesystem status
311: */
312: if (fsmagic(inname, &sb) != 0) {
313: putchar('\n');
314: return;
315: }
316:
317: if ((fd = open(inname, O_RDONLY)) < 0) {
318: /* We can't open it, but we were able to stat it. */
1.10 ! henning 319: if (sb.st_mode & 0002) ckfputs("writable, ", stdout);
1.1 deraadt 320: if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
321: ckfprintf(stdout, "can't read `%s' (%s).\n",
322: inname, strerror(errno));
323: return;
324: }
325: }
326:
327:
328: /*
329: * try looking at the first HOWMANY bytes
330: */
331: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
1.6 mickey 332: err(1, "read failed");
1.1 deraadt 333: /*NOTREACHED*/
334: }
335:
336: if (nbytes == 0)
337: ckfputs("empty", stdout);
338: else {
339: buf[nbytes++] = '\0'; /* null-terminate it */
340: match = tryit(buf, nbytes, zflag);
341: }
342:
1.5 millert 343: #ifdef BUILTIN_ELF
344: if (match == 's' && nbytes > 5)
345: tryelf(fd, buf, nbytes);
346: #endif
1.1 deraadt 347:
1.5 millert 348: if (inname != stdname) {
349: #ifdef RESTORE_TIME
1.1 deraadt 350: /*
1.5 millert 351: * Try to restore access, modification times if read it.
1.1 deraadt 352: */
1.5 millert 353: # ifdef USE_UTIMES
354: struct timeval utsbuf[2];
355: utsbuf[0].tv_sec = sb.st_atime;
356: utsbuf[1].tv_sec = sb.st_mtime;
357:
358: (void) utimes(inname, utsbuf); /* don't care if loses */
359: # else
360: struct utimbuf utbuf;
361:
362: utbuf.actime = sb.st_atime;
363: utbuf.modtime = sb.st_mtime;
364: (void) utime(inname, &utbuf); /* don't care if loses */
365: # endif
1.1 deraadt 366: #endif
367: (void) close(fd);
1.5 millert 368: }
1.1 deraadt 369: (void) putchar('\n');
370: }
371:
372:
373: int
374: tryit(buf, nb, zflag)
375: unsigned char *buf;
376: int nb, zflag;
377: {
378: /* try compression stuff */
379: if (zflag && zmagic(buf, nb))
380: return 'z';
381:
382: /* try tests in /etc/magic (or surrogate magic file) */
383: if (softmagic(buf, nb))
384: return 's';
385:
386: /* try known keywords, check whether it is ASCII */
387: if (ascmagic(buf, nb))
388: return 'a';
1.5 millert 389:
390: /* see if it's international language text */
391: if (internatmagic(buf, nb))
392: return 'i';
1.1 deraadt 393:
394: /* abandon hope, all ye who remain here */
395: ckfputs("data", stdout);
396: return '\0';
397: }