Annotation of src/usr.bin/file/file.c, Revision 1.13
1.13 ! deraadt 1: /* $OpenBSD: file.c,v 1.12 2003/06/13 18:31:14 deraadt Exp $ */
1.5 millert 2:
1.1 deraadt 3: /*
4: * file - find type of a file or files - main program.
5: *
1.11 ian 6: * Copyright (c) Ian F. Darwin 1986-1995.
7: * Software written by Ian F. Darwin and others;
8: * maintained 1995-present by Christos Zoulas and others.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice immediately at the beginning of the file, without modification,
15: * this list of conditions, and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
24: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
1.1 deraadt 31: */
1.11 ian 32:
1.1 deraadt 33: #ifndef lint
1.13 ! deraadt 34: static char *moduleid = "$OpenBSD: file.c,v 1.12 2003/06/13 18:31:14 deraadt Exp $";
1.1 deraadt 35: #endif /* lint */
36:
37: #include <stdio.h>
38: #include <stdlib.h>
39: #include <string.h>
40: #include <sys/types.h>
41: #include <sys/param.h> /* for MAXPATHLEN */
42: #include <sys/stat.h>
43: #include <fcntl.h> /* for open() */
44: #if (__COHERENT__ >= 0x420)
1.5 millert 45: # include <sys/utime.h>
1.1 deraadt 46: #else
1.5 millert 47: # ifdef USE_UTIMES
48: # include <sys/time.h>
49: # else
50: # include <utime.h>
51: # endif
1.1 deraadt 52: #endif
53: #include <unistd.h> /* for read() */
1.6 mickey 54: #include <err.h>
1.1 deraadt 55:
1.5 millert 56: #include <netinet/in.h> /* for byte swapping */
1.1 deraadt 57:
58: #include "patchlevel.h"
59: #include "file.h"
60:
61: #ifdef S_IFLNK
1.9 millert 62: # define USAGE "Usage: %s [-vbczL] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 63: #else
1.9 millert 64: # define USAGE "Usage: %s [-vbcz] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 65: #endif
66:
67: #ifndef MAGIC
68: # define MAGIC "/etc/magic"
69: #endif
70:
71: int /* Global command-line options */
72: debug = 0, /* debugging */
1.9 millert 73: bflag = 0, /* Don't print filename */
1.1 deraadt 74: lflag = 0, /* follow Symlinks (BSD only) */
75: zflag = 0; /* follow (uncompress) compressed files */
76:
77: int /* Misc globals */
78: nmagic = 0; /* number of valid magic[]s */
79:
80: struct magic *magic; /* array of magic entries */
81:
82: char *magicfile; /* where magic be found */
83:
84: int lineno; /* line number in the magic file */
85:
86:
1.8 millert 87: static void unwrap(char *fn);
1.5 millert 88: #if 0
1.8 millert 89: static int byteconv4(int, int, int);
90: static short byteconv2(int, int, int);
1.5 millert 91: #endif
1.1 deraadt 92:
93: /*
94: * main - parse arguments and handle options
95: */
96: int
1.13 ! deraadt 97: main(int argc, char *argv[])
1.1 deraadt 98: {
99: int c;
100: int check = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
1.6 mickey 101: extern char *__progname;
1.1 deraadt 102:
103: if (!(magicfile = getenv("MAGIC")))
104: magicfile = MAGIC;
105:
1.9 millert 106: while ((c = getopt(argc, argv, "bvcdf:Lm:z")) != -1)
1.1 deraadt 107: switch (c) {
108: case 'v':
1.6 mickey 109: (void) printf("%s-%d.%d\n", __progname,
1.1 deraadt 110: FILE_VERSION_MAJOR, patchlevel);
111: return 1;
1.9 millert 112: case 'b':
113: ++bflag;
114: break;
1.1 deraadt 115: case 'c':
116: ++check;
117: break;
118: case 'd':
119: ++debug;
120: break;
121: case 'f':
122: if (!app) {
123: ret = apprentice(magicfile, check);
124: if (check)
125: exit(ret);
126: app = 1;
127: }
128: unwrap(optarg);
129: ++didsomefiles;
130: break;
131: #ifdef S_IFLNK
132: case 'L':
133: ++lflag;
134: break;
135: #endif
136: case 'm':
137: magicfile = optarg;
138: break;
139: case 'z':
140: zflag++;
141: break;
142: case '?':
143: default:
144: errflg++;
145: break;
146: }
147:
148: if (errflg) {
1.6 mickey 149: (void) fprintf(stderr, USAGE, __progname);
1.1 deraadt 150: exit(2);
151: }
152:
153: if (!app) {
154: ret = apprentice(magicfile, check);
155: if (check)
156: exit(ret);
157: app = 1;
158: }
159:
160: if (optind == argc) {
1.7 deraadt 161: if (!didsomefiles) {
162: fprintf(stderr, USAGE, __progname);
163: exit(2);
164: }
1.6 mickey 165: } else {
1.1 deraadt 166: int i, wid, nw;
167: for (wid = 0, i = optind; i < argc; i++) {
168: nw = strlen(argv[i]);
169: if (nw > wid)
170: wid = nw;
171: }
172: for (; optind < argc; optind++)
173: process(argv[optind], wid);
174: }
175:
176: return 0;
177: }
178:
179:
180: /*
181: * unwrap -- read a file of filenames, do each one.
182: */
183: static void
184: unwrap(fn)
185: char *fn;
186: {
187: char buf[MAXPATHLEN];
188: FILE *f;
189: int wid = 0, cwid;
190:
1.5 millert 191: if (strcmp("-", fn) == 0) {
192: f = stdin;
193: wid = 1;
194: } else {
195: if ((f = fopen(fn, "r")) == NULL) {
1.6 mickey 196: err(1, "Cannot open `%s'", fn);
1.5 millert 197: /*NOTREACHED*/
198: }
199:
200: while (fgets(buf, sizeof(buf), f) != NULL) {
201: cwid = strlen(buf) - 1;
202: if (cwid > wid)
203: wid = cwid;
204: }
1.1 deraadt 205:
1.5 millert 206: rewind(f);
1.1 deraadt 207: }
208:
1.5 millert 209: while (fgets(buf, sizeof(buf), f) != NULL) {
1.1 deraadt 210: buf[strlen(buf)-1] = '\0';
211: process(buf, wid);
212: }
213:
214: (void) fclose(f);
215: }
216:
217:
1.5 millert 218: #if 0
219: /*
220: * byteconv4
221: * Input:
222: * from 4 byte quantity to convert
223: * same whether to perform byte swapping
224: * big_endian whether we are a big endian host
225: */
226: static int
227: byteconv4(from, same, big_endian)
228: int from;
229: int same;
230: int big_endian;
231: {
232: if (same)
233: return from;
234: else if (big_endian) /* lsb -> msb conversion on msb */
235: {
236: union {
237: int i;
238: char c[4];
239: } retval, tmpval;
240:
241: tmpval.i = from;
242: retval.c[0] = tmpval.c[3];
243: retval.c[1] = tmpval.c[2];
244: retval.c[2] = tmpval.c[1];
245: retval.c[3] = tmpval.c[0];
246:
247: return retval.i;
248: }
249: else
250: return ntohl(from); /* msb -> lsb conversion on lsb */
251: }
252:
253: /*
254: * byteconv2
255: * Same as byteconv4, but for shorts
256: */
257: static short
258: byteconv2(from, same, big_endian)
259: int from;
260: int same;
261: int big_endian;
262: {
263: if (same)
264: return from;
265: else if (big_endian) /* lsb -> msb conversion on msb */
266: {
267: union {
268: short s;
269: char c[2];
270: } retval, tmpval;
271:
272: tmpval.s = (short) from;
273: retval.c[0] = tmpval.c[1];
274: retval.c[1] = tmpval.c[0];
275:
276: return retval.s;
277: }
278: else
279: return ntohs(from); /* msb -> lsb conversion on lsb */
280: }
281: #endif
282:
1.1 deraadt 283: /*
284: * process - process input file
285: */
286: void
287: process(inname, wid)
288: const char *inname;
289: int wid;
290: {
291: int fd = 0;
292: static const char stdname[] = "standard input";
293: unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
294: struct stat sb;
295: int nbytes = 0; /* number of bytes read from a datafile */
296: char match = '\0';
297:
298: if (strcmp("-", inname) == 0) {
299: if (fstat(0, &sb)<0) {
1.6 mickey 300: err(1, "cannot fstat `%s'", stdname);
1.1 deraadt 301: /*NOTREACHED*/
302: }
303: inname = stdname;
304: }
305:
1.9 millert 306: if (wid > 0 && !bflag)
1.1 deraadt 307: (void) printf("%s:%*s ", inname,
308: (int) (wid - strlen(inname)), "");
309:
310: if (inname != stdname) {
311: /*
312: * first try judging the file based on its filesystem status
313: */
314: if (fsmagic(inname, &sb) != 0) {
315: putchar('\n');
316: return;
317: }
318:
319: if ((fd = open(inname, O_RDONLY)) < 0) {
320: /* We can't open it, but we were able to stat it. */
1.10 henning 321: if (sb.st_mode & 0002) ckfputs("writable, ", stdout);
1.1 deraadt 322: if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
323: ckfprintf(stdout, "can't read `%s' (%s).\n",
324: inname, strerror(errno));
325: return;
326: }
327: }
328:
329:
330: /*
331: * try looking at the first HOWMANY bytes
332: */
333: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
1.6 mickey 334: err(1, "read failed");
1.1 deraadt 335: /*NOTREACHED*/
336: }
337:
338: if (nbytes == 0)
339: ckfputs("empty", stdout);
340: else {
341: buf[nbytes++] = '\0'; /* null-terminate it */
342: match = tryit(buf, nbytes, zflag);
343: }
344:
1.5 millert 345: #ifdef BUILTIN_ELF
346: if (match == 's' && nbytes > 5)
347: tryelf(fd, buf, nbytes);
348: #endif
1.1 deraadt 349:
1.5 millert 350: if (inname != stdname) {
351: #ifdef RESTORE_TIME
1.1 deraadt 352: /*
1.5 millert 353: * Try to restore access, modification times if read it.
1.1 deraadt 354: */
1.5 millert 355: # ifdef USE_UTIMES
356: struct timeval utsbuf[2];
357: utsbuf[0].tv_sec = sb.st_atime;
358: utsbuf[1].tv_sec = sb.st_mtime;
359:
360: (void) utimes(inname, utsbuf); /* don't care if loses */
361: # else
362: struct utimbuf utbuf;
363:
364: utbuf.actime = sb.st_atime;
365: utbuf.modtime = sb.st_mtime;
366: (void) utime(inname, &utbuf); /* don't care if loses */
367: # endif
1.1 deraadt 368: #endif
369: (void) close(fd);
1.5 millert 370: }
1.1 deraadt 371: (void) putchar('\n');
372: }
373:
374:
375: int
376: tryit(buf, nb, zflag)
377: unsigned char *buf;
378: int nb, zflag;
379: {
380: /* try compression stuff */
381: if (zflag && zmagic(buf, nb))
382: return 'z';
383:
384: /* try tests in /etc/magic (or surrogate magic file) */
385: if (softmagic(buf, nb))
386: return 's';
387:
388: /* try known keywords, check whether it is ASCII */
389: if (ascmagic(buf, nb))
390: return 'a';
1.5 millert 391:
392: /* see if it's international language text */
393: if (internatmagic(buf, nb))
394: return 'i';
1.1 deraadt 395:
396: /* abandon hope, all ye who remain here */
397: ckfputs("data", stdout);
398: return '\0';
399: }