source: trunk/minix/commands/simple/file.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 6.4 KB
RevLine 
[9]1/* file - report on file type. Author: Andy Tanenbaum */
2/* Magic number detection changed to look-up table 08-Jan-91 - ajm */
3
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <stdio.h>
10
11#define BLOCK_SIZE 1024
12
13#define XBITS 00111 /* rwXrwXrwX (x bits in the mode) */
14#define ENGLISH 25 /* cutoff for determining if text is Eng. */
15unsigned char buf[BLOCK_SIZE];
16
17struct info {
18 int execflag; /* 1 == ack executable, 2 == gnu executable,
19 * 3 == core */
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 */
23} table[] = {
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,
31 "ACK object archive",
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,
39 "ACK object file",
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,
59 "core file",
60};
61
62int tabsize = sizeof(table) / sizeof(struct info);
63int L_flag;
64
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));
69
70int main(argc, argv)
71int argc;
72char *argv[];
73{
74/* This program uses some heuristics to try to guess about a file type by
75 * looking at its contents.
76 */
77 int c, i;
78
79 L_flag= 0;
80 while ((c= getopt(argc, argv, "L?")) != -1)
81 {
82 switch(c)
83 {
84 case 'L':
85 L_flag= 1;
86 break;
87 case '?':
88 usage();
89 default:
90 fprintf(stderr, "file: panic getopt failed\n");
91 exit(1);
92 }
93 }
94 if (optind >= argc) usage();
95 for (i = optind; i < argc; i++) file(argv[i]);
96 return(0);
97}
98
99void file(name)
100char *name;
101{
102 int i, fd, n, mode, nonascii, special, funnypct, etaoins;
103 int j;
104 long engpct;
105 int c;
106 struct stat st_buf;
107
108 printf("%s: ", name);
109
110#ifdef S_IFLNK
111 if (!L_flag)
112 n = lstat(name, &st_buf);
113 else
114 n = stat(name, &st_buf);
115#else
116 n = stat(name, &st_buf);
117#endif
118 if (n < 0) {
119 printf("cannot stat\n");
120 return;
121 }
122 mode = st_buf.st_mode;
123
124 /* Check for directories and special files. */
125 if (S_ISDIR(mode)) {
126 printf("directory\n");
127 return;
128 }
129 if (S_ISCHR(mode)) {
130 printf("character special file\n");
131 return;
132 }
133 if (S_ISBLK(mode)) {
134 printf("block special file\n");
135 return;
136 }
137 if (S_ISFIFO(mode)) {
138 printf("named pipe\n");
139 return;
140 }
141#ifdef S_IFLNK
142 if (S_ISLNK(mode)) {
143 n= readlink(name, (char *)buf, BLOCK_SIZE);
144 if (n == -1)
145 printf("cannot readlink\n");
146 else
147 printf("symbolic link to %.*s\n", n, buf);
148 return;
149 }
150#endif
151 if (!S_ISREG(mode)) {
152 printf("strange file type %5o\n", mode);
153 return;
154 }
155
156 /* Open the file, stat it, and read in 1 block. */
157 fd = open(name, O_RDONLY);
158 if (fd < 0) {
159 printf("cannot open\n");
160 return;
161 }
162 n = read(fd, (char *)buf, BLOCK_SIZE);
163 if (n < 0) {
164 printf("cannot read\n");
165 close(fd);
166 return;
167 }
168 if (n == 0) { /* must check this, for loop will fail otherwise !! */
169 printf("empty file\n");
170 close(fd);
171 return;
172 }
173
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])
177 break;
178 if (j == 4) {
179 printf("%s", table[i].description);
180 do_strip(table[i].execflag);
181 close(fd);
182 return;
183 }
184 }
185
186
187 /* Check to see if file is a shell script. */
188 if (mode & XBITS) {
189 /* Not a binary, but executable. Probably a shell script. */
190 printf("shell script\n");
191 close(fd);
192 return;
193 }
194
195 /* Check for ASCII data and certain punctuation. */
196 nonascii = 0;
197 special = 0;
198 etaoins = 0;
199 for (i = 0; i < n; i++) {
200 c = buf[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++;
207 }
208
209 if (nonascii == 0) {
210 /* File only contains ASCII characters. Continue processing. */
211 funnypct = 100 * special / n;
212 engpct = 100L * (long) etaoins / n;
213 if (funnypct > 1) {
214 printf("C program\n");
215 } else {
216 if (engpct > (long) ENGLISH)
217 printf("English text\n");
218 else
219 printf("ASCII text\n");
220 }
221 close(fd);
222 return;
223 }
224
225 /* Give up. Call it data. */
226 printf("data\n");
227 close(fd);
228 return;
229}
230
231void do_strip(type)
232int type;
233{
234 if (type == 1) { /* Non-GNU executable */
235 if (buf[2] & 1)
236 printf(", UZP");
237 if (buf[2] & 2)
238 printf(", PAL");
239 if (buf[2] & 4)
240 printf(", NSYM");
241 if (buf[2] & 0x20)
242 printf(", sep I&D");
243 else
244 printf(", comm I&D");
245 if (( buf[28] | buf[29] | buf[30] | buf[31]) != 0)
246 printf(" not stripped\n");
247 else
248 printf(" stripped\n");
249 return;
250 }
251
252 if (type == 2) { /* GNU format executable */
253 if ((buf[16] | buf[17] | buf[18] | buf[19]) != 0)
254 printf(" not stripped\n");
255 else
256 printf(" stripped\n");
257 return;
258 }
259
260 if (type == 3) { /* Core file in <sys/core.h> format */
261 switch(buf[36] & 0xff)
262 {
263 case 1: printf(" of i86 executable"); break;
264 case 2: printf(" of i386 executable"); break;
265 default:printf(" of unknown executable"); break;
266 }
267 printf(" '%.32s'\n", buf+4);
268 return;
269 }
270
271 printf("\n"); /* Not an executable file */
272 }
273
274void usage()
275{
276 printf("Usage: file [-L] name ...\n");
277 exit(1);
278}
Note: See TracBrowser for help on using the repository browser.