Annotation of src/usr.bin/file/file.c, Revision 1.5
1.5 ! millert 1: /* $OpenBSD: file.c,v 1.4 1997/01/15 23:42:26 millert Exp $ */
! 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.5 ! millert 30: static char *moduleid = "$OpenBSD: file.c,v 1.11 1997/01/28 00:49:40 christos 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() */
50:
1.5 ! millert 51: #include <netinet/in.h> /* for byte swapping */
1.1 deraadt 52:
53: #include "patchlevel.h"
54: #include "file.h"
55:
56: #ifdef S_IFLNK
1.2 deraadt 57: # define USAGE "Usage: %s [-vczL] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 58: #else
1.2 deraadt 59: # define USAGE "Usage: %s [-vcz] [-f namefile] [-m magicfiles] file...\n"
1.1 deraadt 60: #endif
61:
62: #ifndef MAGIC
63: # define MAGIC "/etc/magic"
64: #endif
65:
66: int /* Global command-line options */
67: debug = 0, /* debugging */
68: lflag = 0, /* follow Symlinks (BSD only) */
69: zflag = 0; /* follow (uncompress) compressed files */
70:
71: int /* Misc globals */
72: nmagic = 0; /* number of valid magic[]s */
73:
74: struct magic *magic; /* array of magic entries */
75:
76: char *magicfile; /* where magic be found */
77:
78: char *progname; /* used throughout */
79: int lineno; /* line number in the magic file */
80:
81:
1.5 ! millert 82: static void unwrap __P((char *fn));
! 83: #if 0
! 84: static int byteconv4 __P((int, int, int));
! 85: static short byteconv2 __P((int, int, int));
! 86: #endif
1.1 deraadt 87:
88: /*
89: * main - parse arguments and handle options
90: */
91: int
92: main(argc, argv)
93: int argc;
94: char *argv[];
95: {
96: int c;
97: int check = 0, didsomefiles = 0, errflg = 0, ret = 0, app = 0;
98:
99: if ((progname = strrchr(argv[0], '/')) != NULL)
100: progname++;
101: else
102: progname = argv[0];
103:
104: if (!(magicfile = getenv("MAGIC")))
105: magicfile = MAGIC;
106:
1.4 millert 107: while ((c = getopt(argc, argv, "vcdf:Lm:z")) != -1)
1.1 deraadt 108: switch (c) {
109: case 'v':
110: (void) fprintf(stdout, "%s-%d.%d\n", progname,
111: FILE_VERSION_MAJOR, patchlevel);
112: return 1;
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) {
147: (void) fprintf(stderr, USAGE, progname);
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) {
159: if (!didsomefiles) {
160: (void)fprintf(stderr, USAGE, progname);
161: exit(2);
162: }
163: }
164: else {
165: int i, wid, nw;
166: for (wid = 0, i = optind; i < argc; i++) {
167: nw = strlen(argv[i]);
168: if (nw > wid)
169: wid = nw;
170: }
171: for (; optind < argc; optind++)
172: process(argv[optind], wid);
173: }
174:
175: return 0;
176: }
177:
178:
179: /*
180: * unwrap -- read a file of filenames, do each one.
181: */
182: static void
183: unwrap(fn)
184: char *fn;
185: {
186: char buf[MAXPATHLEN];
187: FILE *f;
188: int wid = 0, cwid;
189:
1.5 ! millert 190: if (strcmp("-", fn) == 0) {
! 191: f = stdin;
! 192: wid = 1;
! 193: } else {
! 194: if ((f = fopen(fn, "r")) == NULL) {
! 195: error("Cannot open `%s' (%s).\n", fn, strerror(errno));
! 196: /*NOTREACHED*/
! 197: }
! 198:
! 199: while (fgets(buf, sizeof(buf), f) != NULL) {
! 200: cwid = strlen(buf) - 1;
! 201: if (cwid > wid)
! 202: wid = cwid;
! 203: }
1.1 deraadt 204:
1.5 ! millert 205: rewind(f);
1.1 deraadt 206: }
207:
1.5 ! millert 208: while (fgets(buf, sizeof(buf), f) != NULL) {
1.1 deraadt 209: buf[strlen(buf)-1] = '\0';
210: process(buf, wid);
211: }
212:
213: (void) fclose(f);
214: }
215:
216:
1.5 ! millert 217: #if 0
! 218: /*
! 219: * byteconv4
! 220: * Input:
! 221: * from 4 byte quantity to convert
! 222: * same whether to perform byte swapping
! 223: * big_endian whether we are a big endian host
! 224: */
! 225: static int
! 226: byteconv4(from, same, big_endian)
! 227: int from;
! 228: int same;
! 229: int big_endian;
! 230: {
! 231: if (same)
! 232: return from;
! 233: else if (big_endian) /* lsb -> msb conversion on msb */
! 234: {
! 235: union {
! 236: int i;
! 237: char c[4];
! 238: } retval, tmpval;
! 239:
! 240: tmpval.i = from;
! 241: retval.c[0] = tmpval.c[3];
! 242: retval.c[1] = tmpval.c[2];
! 243: retval.c[2] = tmpval.c[1];
! 244: retval.c[3] = tmpval.c[0];
! 245:
! 246: return retval.i;
! 247: }
! 248: else
! 249: return ntohl(from); /* msb -> lsb conversion on lsb */
! 250: }
! 251:
! 252: /*
! 253: * byteconv2
! 254: * Same as byteconv4, but for shorts
! 255: */
! 256: static short
! 257: byteconv2(from, same, big_endian)
! 258: int from;
! 259: int same;
! 260: int big_endian;
! 261: {
! 262: if (same)
! 263: return from;
! 264: else if (big_endian) /* lsb -> msb conversion on msb */
! 265: {
! 266: union {
! 267: short s;
! 268: char c[2];
! 269: } retval, tmpval;
! 270:
! 271: tmpval.s = (short) from;
! 272: retval.c[0] = tmpval.c[1];
! 273: retval.c[1] = tmpval.c[0];
! 274:
! 275: return retval.s;
! 276: }
! 277: else
! 278: return ntohs(from); /* msb -> lsb conversion on lsb */
! 279: }
! 280: #endif
! 281:
1.1 deraadt 282: /*
283: * process - process input file
284: */
285: void
286: process(inname, wid)
287: const char *inname;
288: int wid;
289: {
290: int fd = 0;
291: static const char stdname[] = "standard input";
292: unsigned char buf[HOWMANY+1]; /* one extra for terminating '\0' */
293: struct stat sb;
294: int nbytes = 0; /* number of bytes read from a datafile */
295: char match = '\0';
296:
297: if (strcmp("-", inname) == 0) {
298: if (fstat(0, &sb)<0) {
299: error("cannot fstat `%s' (%s).\n", stdname,
300: strerror(errno));
301: /*NOTREACHED*/
302: }
303: inname = stdname;
304: }
305:
306: if (wid > 0)
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. */
321: if (sb.st_mode & 0002) ckfputs("writeable, ", stdout);
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) {
334: error("read failed (%s).\n", strerror(errno));
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: }