Annotation of src/usr.bin/file/file.c, Revision 1.4
1.4 ! millert 1: /* $OpenBSD: file.c,v 1.3 1996/06/26 05:32:56 deraadt Exp $ */
1.1 deraadt 2: /*
3: * file - find type of a file or files - main program.
4: *
5: * Copyright (c) Ian F. Darwin, 1987.
6: * Written by Ian F. Darwin.
7: *
8: * This software is not subject to any license of the American Telephone
9: * and Telegraph Company or of the Regents of the University of California.
10: *
11: * Permission is granted to anyone to use this software for any purpose on
12: * any computer system, and to alter it and redistribute it freely, subject
13: * to the following restrictions:
14: *
15: * 1. The author is not responsible for the consequences of use of this
16: * software, no matter how awful, even if they arise from flaws in it.
17: *
18: * 2. The origin of this software must not be misrepresented, either by
19: * explicit claim or by omission. Since few users ever read sources,
20: * credits must appear in the documentation.
21: *
22: * 3. Altered versions must be plainly marked as such, and must not be
23: * misrepresented as being the original software. Since few users
24: * ever read sources, credits must appear in the documentation.
25: *
26: * 4. This notice may not be removed or altered.
27: */
28: #ifndef lint
1.4 ! millert 29: static char *moduleid = "$OpenBSD: file.c,v 1.3 1996/06/26 05:32:56 deraadt Exp $";
1.1 deraadt 30: #endif /* lint */
31:
32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <string.h>
35: #include <sys/types.h>
36: #include <sys/param.h> /* for MAXPATHLEN */
37: #include <sys/stat.h>
38: #include <fcntl.h> /* for open() */
39: #if (__COHERENT__ >= 0x420)
40: #include <sys/utime.h>
41: #else
42: #include <utime.h>
43: #endif
44: #include <unistd.h> /* for read() */
45:
46: #ifdef __ELF__
47: #include <elf.h>
48: #endif
49:
50: #include "patchlevel.h"
51: #include "file.h"
52:
53: #ifdef S_IFLNK
1.2 deraadt 54: # define USAGE "Usage: %s [-vczL] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 55: #else
1.2 deraadt 56: # define USAGE "Usage: %s [-vcz] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 57: #endif
58:
59: #ifndef MAGIC
60: # define MAGIC "/etc/magic"
61: #endif
62:
63: int /* Global command-line options */
64: debug = 0, /* debugging */
65: lflag = 0, /* follow Symlinks (BSD only) */
66: zflag = 0; /* follow (uncompress) compressed files */
67:
68: int /* Misc globals */
69: nmagic = 0; /* number of valid magic[]s */
70:
71: struct magic *magic; /* array of magic entries */
72:
73: char *magicfile; /* where magic be found */
74:
75: char *progname; /* used throughout */
76: int lineno; /* line number in the magic file */
77:
78:
79: static void unwrap __P((char *fn));
80:
81: /*
82: * main - parse arguments and handle options
83: */
84: int
85: main(argc, argv)
86: int argc;
87: char *argv[];
88: {
89: int c;
90: int check = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
91:
92: if ((progname = strrchr(argv[0], '/')) != NULL)
93: progname++;
94: else
95: progname = argv[0];
96:
97: if (!(magicfile = getenv("MAGIC")))
98: magicfile = MAGIC;
99:
1.4 ! millert 100: while ((c = getopt(argc, argv, "vcdf:Lm:z")) != -1)
1.1 deraadt 101: switch (c) {
102: case 'v':
103: (void) fprintf(stdout, "%s-%d.%d\n", progname,
104: FILE_VERSION_MAJOR, patchlevel);
105: return 1;
106: case 'c':
107: ++check;
108: break;
109: case 'd':
110: ++debug;
111: break;
112: case 'f':
113: if (!app) {
114: ret = apprentice(magicfile, check);
115: if (check)
116: exit(ret);
117: app = 1;
118: }
119: unwrap(optarg);
120: ++didsomefiles;
121: break;
122: #ifdef S_IFLNK
123: case 'L':
124: ++lflag;
125: break;
126: #endif
127: case 'm':
128: magicfile = optarg;
129: break;
130: case 'z':
131: zflag++;
132: break;
133: case '?':
134: default:
135: errflg++;
136: break;
137: }
138:
139: if (errflg) {
140: (void) fprintf(stderr, USAGE, progname);
141: exit(2);
142: }
143:
144: if (!app) {
145: ret = apprentice(magicfile, check);
146: if (check)
147: exit(ret);
148: app = 1;
149: }
150:
151: if (optind == argc) {
152: if (!didsomefiles) {
153: (void)fprintf(stderr, USAGE, progname);
154: exit(2);
155: }
156: }
157: else {
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:
183: if ((f = fopen(fn, "r")) == NULL) {
184: error("Cannot open `%s' (%s).\n", fn, strerror(errno));
185: /*NOTREACHED*/
186: }
187:
188: while (fgets(buf, MAXPATHLEN, f) != NULL) {
189: cwid = strlen(buf) - 1;
190: if (cwid > wid)
191: wid = cwid;
192: }
193:
194: rewind(f);
195:
196: while (fgets(buf, MAXPATHLEN, f) != NULL) {
197: buf[strlen(buf)-1] = '\0';
198: process(buf, wid);
199: }
200:
201: (void) fclose(f);
202: }
203:
204:
205: /*
206: * process - process input file
207: */
208: void
209: process(inname, wid)
210: const char *inname;
211: int wid;
212: {
213: int fd = 0;
214: static const char stdname[] = "standard input";
215: unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
216: struct utimbuf utbuf;
217: struct stat sb;
218: int nbytes = 0; /* number of bytes read from a datafile */
219: char match = '\0';
220:
221: if (strcmp("-", inname) == 0) {
222: if (fstat(0, &sb)<0) {
223: error("cannot fstat `%s' (%s).\n", stdname,
224: strerror(errno));
225: /*NOTREACHED*/
226: }
227: inname = stdname;
228: }
229:
230: if (wid > 0)
231: (void) printf("%s:%*s ", inname,
232: (int) (wid - strlen(inname)), "");
233:
234: if (inname != stdname) {
235: /*
236: * first try judging the file based on its filesystem status
237: */
238: if (fsmagic(inname, &sb) != 0) {
239: putchar('\n');
240: return;
241: }
242:
243: if ((fd = open(inname, O_RDONLY)) < 0) {
244: /* We can't open it, but we were able to stat it. */
245: if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
246: if (sb.st_mode & 0111) ckfputs("executable, ", stdout);
247: ckfprintf(stdout, "can't read `%s' (%s).\n",
248: inname, strerror(errno));
249: return;
250: }
251: }
252:
253:
254: /*
255: * try looking at the first HOWMANY bytes
256: */
257: if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1) {
258: error("read failed (%s).\n", strerror(errno));
259: /*NOTREACHED*/
260: }
261:
262: if (nbytes == 0)
263: ckfputs("empty", stdout);
264: else {
265: buf[nbytes++] = '\0'; /* null-terminate it */
266: match = tryit(buf, nbytes, zflag);
267: }
268: #ifdef __ELF__
269: /*
270: * ELF executables have multiple section headers in arbitrary
271: * file locations and thus file(1) cannot determine it from easily.
272: * Instead we traverse thru all section headers until a symbol table
273: * one is found or else the binary is stripped.
274: * XXX: This will not work for binaries of a different byteorder.
275: * Should come up with a better fix.
276: */
277:
278: if (match == 's' && nbytes > sizeof (Elf32_Ehdr) &&
279: buf[EI_MAG0] == ELFMAG0 &&
280: buf[EI_MAG1] == ELFMAG1 &&
281: buf[EI_MAG2] == ELFMAG2 &&
282: buf[EI_MAG3] == ELFMAG3) {
283:
284: union {
285: long l;
286: char c[sizeof (long)];
287: } u;
288: Elf32_Ehdr elfhdr;
289: int stripped = 1;
290:
291: u.l = 1;
292: (void) memcpy(&elfhdr, buf, sizeof elfhdr);
293:
294: /*
295: * If the system byteorder does not equal the object byteorder
296: * then don't test.
297: */
298: if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) {
299: if (lseek(fd, elfhdr.e_shoff, SEEK_SET)<0)
300: error("lseek failed (%s).\n", strerror(errno));
301:
302: for ( ; elfhdr.e_shnum ; elfhdr.e_shnum--) {
303: if (read(fd, buf, elfhdr.e_shentsize)<0)
304: error("read failed (%s).\n", strerror(errno));
305: if (((Elf32_Shdr *)&buf)->sh_type == SHT_SYMTAB) {
306: stripped = 0;
307: break;
308: }
309: }
310: if (stripped)
311: (void) printf (", stripped");
312: }
313: }
314: #endif
315:
316: if (inname != stdname)
317: (void) close(fd);
318: (void) putchar('\n');
319: }
320:
321:
322: int
323: tryit(buf, nb, zflag)
324: unsigned char *buf;
325: int nb, zflag;
326: {
327: /* try compression stuff */
328: if (zflag && zmagic(buf, nb))
329: return 'z';
330:
331: /* try tests in /etc/magic (or surrogate magic file) */
332: if (softmagic(buf, nb))
333: return 's';
334:
335: /* try known keywords, check whether it is ASCII */
336: if (ascmagic(buf, nb))
337: return 'a';
338:
339: /* abandon hope, all ye who remain here */
340: ckfputs("data", stdout);
341: return '\0';
342: }