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