1 /* file - report on file type. Author: Andy Tanenbaum */
2 /* Magic number detection changed to look-up table 08-Jan-91 - ajm */
11 #define BLOCK_SIZE 1024
13 #define XBITS 00111 /* rwXrwXrwX (x bits in the mode) */
14 #define ENGLISH 25 /* cutoff for determining if text is Eng. */
15 unsigned char buf
[BLOCK_SIZE
];
18 int execflag
; /* 1 == ack executable, 2 == gnu executable,
20 unsigned char magic
[4]; /* First four bytes of the magic number */
21 unsigned char mask
[4]; /* Mask to apply when matching */
22 char *description
; /* What it means */
24 0x00, 0x1f, 0x9d, 0x8d, 0x00, 0xff, 0xff, 0xff, 0x00,
25 "13-bit compressed file",
26 0x00, 0x1f, 0x9d, 0x90, 0x00, 0xff, 0xff, 0xff, 0x00,
27 "16-bit compressed file",
28 0x00, 0x65, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
29 "MINIX-PC bcc archive",
30 0x00, 0x2c, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
32 0x00, 0x65, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
33 "MINIX-PC ack archive",
34 0x00, 0x47, 0x6e, 0x75, 0x20, 0xff, 0xff, 0xff, 0xff,
35 "MINIX-68k gnu archive",
36 0x00, 0x21, 0x3c, 0x61, 0x72, 0xff, 0xff, 0xff, 0xff,
37 "MINIX-PC gnu archive",
38 0x00, 0x01, 0x02, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
40 0x00, 0xa3, 0x86, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
41 "MINIX-PC bcc object file",
42 0x00, 0x00, 0x00, 0x01, 0x07, 0xff, 0xff, 0xff, 0xff,
43 "MINIX-68k gnu object file",
44 0x00, 0x07, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
45 "MINIX-PC gnu object file",
46 0x01, 0x01, 0x03, 0x00, 0x04, 0xff, 0xff, 0x00, 0xff,
47 "MINIX-PC 16-bit executable",
48 0x01, 0x01, 0x03, 0x00, 0x10, 0xff, 0xff, 0x00, 0xff,
49 "MINIX-PC 32-bit executable",
50 0x01, 0x04, 0x10, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff,
51 "MINIX-68k old style executable",
52 0x01, 0x01, 0x03, 0x10, 0x0b, 0xff, 0xff, 0xff, 0xff,
53 "MINIX-68k new style executable",
54 0x02, 0x0b, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
55 "MINIX-PC 32-bit gnu executable combined I & D space",
56 0x02, 0x00, 0x00, 0x0b, 0x01, 0xff, 0xff, 0xff, 0xff,
57 "MINIX-68k gnu executable",
58 0x03, 0x82, 0x12, 0xC4, 0xC0, 0xff, 0xff, 0xff, 0xff,
62 int tabsize
= sizeof(table
) / sizeof(struct info
);
65 _PROTOTYPE(int main
, (int argc
, char **argv
));
66 _PROTOTYPE(void file
, (char *name
));
67 _PROTOTYPE(void do_strip
, (int type
));
68 _PROTOTYPE(void usage
, (void));
74 /* This program uses some heuristics to try to guess about a file type by
75 * looking at its contents.
80 while ((c
= getopt(argc
, argv
, "L?")) != -1)
90 fprintf(stderr
, "file: panic getopt failed\n");
94 if (optind
>= argc
) usage();
95 for (i
= optind
; i
< argc
; i
++) file(argv
[i
]);
102 int i
, fd
, n
, mode
, nonascii
, special
, funnypct
, etaoins
;
108 printf("%s: ", name
);
112 n
= lstat(name
, &st_buf
);
114 n
= stat(name
, &st_buf
);
116 n
= stat(name
, &st_buf
);
119 printf("cannot stat\n");
122 mode
= st_buf
.st_mode
;
124 /* Check for directories and special files. */
126 printf("directory\n");
130 printf("character special file\n");
134 printf("block special file\n");
137 if (S_ISFIFO(mode
)) {
138 printf("named pipe\n");
143 n
= readlink(name
, (char *)buf
, BLOCK_SIZE
);
145 printf("cannot readlink\n");
147 printf("symbolic link to %.*s\n", n
, buf
);
151 if (!S_ISREG(mode
)) {
152 printf("strange file type %5o\n", mode
);
156 /* Open the file, stat it, and read in 1 block. */
157 fd
= open(name
, O_RDONLY
);
159 printf("cannot open\n");
162 n
= read(fd
, (char *)buf
, BLOCK_SIZE
);
164 printf("cannot read\n");
168 if (n
== 0) { /* must check this, for loop will fail otherwise !! */
169 printf("empty file\n");
174 for (i
= 0; i
< tabsize
; i
++) {
175 for (j
= 0; j
< 4; j
++)
176 if ((buf
[j
] & table
[i
].mask
[j
]) != table
[i
].magic
[j
])
179 printf("%s", table
[i
].description
);
180 do_strip(table
[i
].execflag
);
187 /* Check to see if file is a shell script. */
189 /* Not a binary, but executable. Probably a shell script. */
190 printf("shell script\n");
195 /* Check for ASCII data and certain punctuation. */
199 for (i
= 0; i
< n
; i
++) {
201 if (c
& 0200) nonascii
++;
202 if (c
== ';' || c
== '{' || c
== '}' || c
== '#') special
++;
203 if (c
== '*' || c
== '<' || c
== '>' || c
== '/') special
++;
204 if (c
>= 'A' && c
<= 'Z') c
= c
- 'A' + 'a';
205 if (c
== 'e' || c
== 't' || c
== 'a' || c
== 'o') etaoins
++;
206 if (c
== 'i' || c
== 'n' || c
== 's') etaoins
++;
210 /* File only contains ASCII characters. Continue processing. */
211 funnypct
= 100 * special
/ n
;
212 engpct
= 100L * (long) etaoins
/ n
;
214 printf("C program\n");
216 if (engpct
> (long) ENGLISH
)
217 printf("English text\n");
219 printf("ASCII text\n");
225 /* Give up. Call it data. */
234 if (type
== 1) { /* Non-GNU executable */
244 printf(", comm I&D");
245 if (( buf
[28] | buf
[29] | buf
[30] | buf
[31]) != 0)
246 printf(" not stripped\n");
248 printf(" stripped\n");
252 if (type
== 2) { /* GNU format executable */
253 if ((buf
[16] | buf
[17] | buf
[18] | buf
[19]) != 0)
254 printf(" not stripped\n");
256 printf(" stripped\n");
260 if (type
== 3) { /* Core file in <sys/core.h> format */
261 switch(buf
[36] & 0xff)
263 case 1: printf(" of i86 executable"); break;
264 case 2: printf(" of i386 executable"); break;
265 default:printf(" of unknown executable"); break;
267 printf(" '%.32s'\n", buf
+4);
271 printf("\n"); /* Not an executable file */
276 printf("Usage: file [-L] name ...\n");