Annotation of src/usr.bin/file/file.c, Revision 1.1
1.1 ! deraadt 1: /*
! 2: * file - find type of a file or files - main program.
! 3: *
! 4: * Copyright (c) Ian F. Darwin, 1987.
! 5: * Written by Ian F. Darwin.
! 6: *
! 7: * This software is not subject to any license of the American Telephone
! 8: * and Telegraph Company or of the Regents of the University of California.
! 9: *
! 10: * Permission is granted to anyone to use this software for any purpose on
! 11: * any computer system, and to alter it and redistribute it freely, subject
! 12: * to the following restrictions:
! 13: *
! 14: * 1. The author is not responsible for the consequences of use of this
! 15: * software, no matter how awful, even if they arise from flaws in it.
! 16: *
! 17: * 2. The origin of this software must not be misrepresented, either by
! 18: * explicit claim or by omission. Since few users ever read sources,
! 19: * credits must appear in the documentation.
! 20: *
! 21: * 3. Altered versions must be plainly marked as such, and must not be
! 22: * misrepresented as being the original software. Since few users
! 23: * ever read sources, credits must appear in the documentation.
! 24: *
! 25: * 4. This notice may not be removed or altered.
! 26: */
! 27: #ifndef lint
! 28: static char *moduleid =
! 29: "@(#)$Id: file.c,v 1.7 1995/07/13 13:22:58 mycroft Exp $";
! 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
! 54: # define USAGE "Usage: %s [-vczL] [-f namefile] [-m magicfile] file...\n"
! 55: #else
! 56: # define USAGE "Usage: %s [-vcz] [-f namefile] [-m magicfile] file...\n"
! 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:
! 100: while ((c = getopt(argc, argv, "vcdf:Lm:z")) != EOF)
! 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: }