/* file - report on file type. Author: Andy Tanenbaum */ #include <blocksize.h> #include <ar.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <minix/config.h> #if (CHIP == M68000) #define A_OUT 0x410 /* magic number for executables */ #define A_OUT_SPLIT 0x420 /* magic number for executables split I/D */ #define A_OUT_SEC 0x301 /* second check for executables */ #define OBJECT 0x102 /* minix/st object */ #else #define A_OUT 001401 /* magic number for executables */ #define SPLIT 002040 /* second word on split I/D binaries */ #endif #define XBITS 00111 /* rwXrwXrwX (x bits in the mode) */ #define ENGLISH 25 /* cutoff for determining if text is Eng. */ char buf[BLOCK_SIZE]; main(argc, argv) int argc; char *argv[]; { /* This program uses some heuristics to try to guess about a file type by * looking at its contents. */ int i; if (argc < 2) usage(); for (i = 1; i < argc; i++) file(argv[i]); } file(name) char *name; { int i, fd, n, magic, second, mode, nonascii, special, funnypct, etaoins; int symbols; long engpct; char c; struct stat st_buf; printf("%s: ", name); /* Open the file, stat it, and read in 1 block. */ fd = open(name, O_RDONLY); if (fd < 0) { printf("cannot open\n"); return; } n = fstat(fd, &st_buf); if (n < 0) { printf("cannot stat\n"); close(fd); return; } mode = st_buf.st_mode; /* Check for directories and special files. */ if ((mode & S_IFMT) == S_IFDIR) { printf("directory\n"); close(fd); return; } if ((mode & S_IFMT) == S_IFCHR) { printf("character special file\n"); close(fd); return; } if ((mode & S_IFMT) == S_IFBLK) { printf("block special file\n"); close(fd); return; } n = read(fd, buf, BLOCK_SIZE); if (n < 0) { printf("cannot read\n"); close(fd); return; } /* Check to see if file is an archive. */ #if (CHIP == M68000) magic = (buf[0] << 8) | (buf[1] & 0377); if (magic == 026377) { #else magic = (buf[1] << 8) | (buf[0] & 0377); if (magic == ARMAG) { #endif printf("archive\n"); close(fd); return; } #if (CHIP == M68000) /* Check to see if file is an object file. */ if (magic == OBJECT) { printf("MINIX/ST object file\n"); close(fd); return; } #endif /* Check to see if file is an executable binary. */ #if (CHIP != M68000) if (magic == A_OUT) { /* File is executable. Check for split I/D. */ printf("MINIX/PC executable"); second = (buf[3] << 8) | (buf[2] & 0377); if (second == SPLIT) printf(" separate I & D space"); else printf(" combined I & D space"); #else if (magic == A_OUT || magic == A_OUT_SPLIT) { /* File is executable. Check for split I/D. */ printf("MINIX/ST executable"); second = (buf[2] << 8) | (buf[3] & 0377); if (second == A_OUT_SEC) { if (magic == A_OUT_SPLIT) printf(" separate I & D space"); else printf(" combined I & D space"); } #endif symbols = buf[28] | buf[29] | buf[30] | buf[31]; if (symbols != 0) printf(" not stripped\n"); else printf(" stripped\n"); close(fd); return; } /* Check to see if file is a shell script. */ if (mode & XBITS) { /* Not a binary, but executable. Probably a shell script. */ printf("shell script\n"); close(fd); return; } /* Check for ASCII data and certain punctuation. */ nonascii = 0; special = 0; etaoins = 0; for (i = 0; i < n; i++) { c = buf[i]; if (c & 0200) nonascii++; if (c == ';' || c == '{' || c == '}' || c == '#') special++; if (c == '*' || c == '<' || c == '>' || c == '/') special++; if (c >= 'A' && c <= 'Z') c = c - 'A' + 'a'; if (c == 'e' || c == 't' || c == 'a' || c == 'o') etaoins++; if (c == 'i' || c == 'n' || c == 's') etaoins++; } if (nonascii == 0) { /* File only contains ASCII characters. Continue processing. */ funnypct = 100 * special / n; engpct = 100L * (long) etaoins / n; if (funnypct > 1) { printf("C program\n"); } else { if (engpct > (long) ENGLISH) printf("English text\n"); else printf("ASCII text\n", engpct); } close(fd); return; } /* Give up. Call it data. */ printf("data\n"); close(fd); return; } usage() { printf("Usage: file name ...\n"); exit(1); }