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