xref: /original-bsd/usr.bin/file/file.c (revision 24f1d79f)
1 static	char sccsid[] = "@(#)file.c	4.4 (Berkeley) 4.4";
2 /*
3  * file - determine type of file
4  */
5 
6 #include <pagsiz.h>
7 #include <sys/types.h>
8 #include <stat.h>
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <a.out.h>
12 int in;
13 int i  = 0;
14 char buf[BUFSIZ];
15 char *troff[] = {	/* new troff intermediate lang */
16 	"x","T","res","init","font","202","V0","p1",0};
17 char *fort[] = {
18 	"function","subroutine","common","dimension","block","integer",
19 	"real","data","double",0};
20 char *asc[] = {
21 	"chmk","mov","tst","clr","jmp",0};
22 char *c[] = {
23 	"int","char","float","double","struct","extern",0};
24 char *as[] = {
25 	"globl","byte","align","text","data","comm",0};
26 int	ifile;
27 
28 main(argc, argv)
29 char **argv;
30 {
31 	FILE *fl;
32 	register char *p;
33 	char ap[128];
34 	extern char _sobuf[];
35 
36 	if (argc>1 && argv[1][0]=='-' && argv[1][1]=='f') {
37 		if ((fl = fopen(argv[2], "r")) == NULL) {
38 			printf("Can't open %s\n", argv[2]);
39 			exit(2);
40 		}
41 		while ((p = fgets(ap, 128, fl)) != NULL) {
42 			int l = strlen(p);
43 			if (l>0)
44 				p[l-1] = '\0';
45 			printf("%s:	", p);
46 			type(p);
47 			if (ifile>=0)
48 				close(ifile);
49 		}
50 		exit(1);
51 	}
52 	while(argc > 1) {
53 		printf("%s:	", argv[1]);
54 		type(argv[1]);
55 		fflush(stdout);
56 		argc--;
57 		argv++;
58 		if (ifile >= 0)
59 			close(ifile);
60 	}
61 }
62 
63 type(file)
64 char *file;
65 {
66 	int j,nl;
67 	char ch;
68 	struct stat mbuf;
69 
70 	ifile = -1;
71 	if (lstat(file, &mbuf) < 0) {
72 		printf("cannot stat\n");
73 		return;
74 	}
75 	switch (mbuf.st_mode & S_IFMT) {
76 
77 	case S_IFCHR:
78 		printf("character");
79 		goto spcl;
80 
81 	case S_IFLNK:
82 		printf("symbolic link\n");
83 		return;
84 
85 	case S_IFDIR:
86 		printf("directory\n");
87 		return;
88 
89 	case S_IFBLK:
90 		printf("block");
91 
92 spcl:
93 		printf(" special (%d/%d)\n", major(mbuf.st_rdev), minor(mbuf.st_rdev));
94 		return;
95 	}
96 
97 	ifile = open(file, 0);
98 	if(ifile < 0) {
99 		printf("cannot open\n");
100 		return;
101 	}
102 	in = read(ifile, buf, BUFSIZ);
103 	if(in == 0){
104 		printf("empty\n");
105 		return;
106 	}
107 	switch(*(int *)buf) {
108 
109 	case 0413:
110 		printf("demand paged ");
111 
112 	case 0410:
113 		printf("pure ");
114 		goto exec;
115 
116 	case 0411:
117 		printf("jfr or pdp-11 unix 411 executable\n");
118 		return;
119 
120 	case 0407:
121 exec:
122 		printf("executable");
123 		if(((int *)buf)[4] != 0) {
124 			printf(" not stripped");
125 			if(oldo(buf))
126 				printf(" (old format symbol table)");
127 		}
128 		printf("\n");
129 		goto out;
130 
131 	case 0177555:
132 		printf("very old archive\n");
133 		goto out;
134 
135 	case 0177545:
136 		printf("old archive\n");
137 		goto out;
138 
139 	case 070707:
140 		printf("cpio data\n");
141 		goto out;
142 	}
143 
144 	if(strncmp(buf, "!<arch>\n__.SYMDEF", 17) == 0 ) {
145 		printf("archive random library\n");
146 		goto out;
147 	}
148 	if (strncmp(buf, "!<arch>\n", 8)==0) {
149 		printf("archive\n");
150 		goto out;
151 	}
152 	if (mbuf.st_size % 512 == 0) {	/* it may be a PRESS file */
153 		lseek(ifile, -512L, 2);	/* last block */
154 		if (read(ifile, buf, BUFSIZ) > 0
155 		 && *(short int *)buf == 12138) {
156 			printf("PRESS file\n");
157 			goto out;
158 		}
159 	}
160 	i = 0;
161 	if(ccom() == 0)goto notc;
162 	while(buf[i] == '#'){
163 		j = i;
164 		while(buf[i++] != '\n'){
165 			if(i - j > 255){
166 				printf("data\n");
167 				goto out;
168 			}
169 			if(i >= in)goto notc;
170 		}
171 		if(ccom() == 0)goto notc;
172 	}
173 check:
174 	if(lookup(c) == 1){
175 		while((ch = buf[i++]) != ';' && ch != '{')if(i >= in)goto notc;
176 		printf("c program text");
177 		goto outa;
178 	}
179 	nl = 0;
180 	while(buf[i] != '('){
181 		if(buf[i] <= 0)
182 			goto notas;
183 		if(buf[i] == ';'){
184 			i++;
185 			goto check;
186 		}
187 		if(buf[i++] == '\n')
188 			if(nl++ > 6)goto notc;
189 		if(i >= in)goto notc;
190 	}
191 	while(buf[i] != ')'){
192 		if(buf[i++] == '\n')
193 			if(nl++ > 6)goto notc;
194 		if(i >= in)goto notc;
195 	}
196 	while(buf[i] != '{'){
197 		if(buf[i++] == '\n')
198 			if(nl++ > 6)goto notc;
199 		if(i >= in)goto notc;
200 	}
201 	printf("c program text");
202 	goto outa;
203 notc:
204 	i = 0;
205 	while(buf[i] == 'c' || buf[i] == '#'){
206 		while(buf[i++] != '\n')if(i >= in)goto notfort;
207 	}
208 	if(lookup(fort) == 1){
209 		printf("fortran program text");
210 		goto outa;
211 	}
212 notfort:
213 	i=0;
214 	if(ascom() == 0)goto notas;
215 	j = i-1;
216 	if(buf[i] == '.'){
217 		i++;
218 		if(lookup(as) == 1){
219 			printf("assembler program text");
220 			goto outa;
221 		}
222 		else if(buf[j] == '\n' && isalpha(buf[j+2])){
223 			printf("roff, nroff, or eqn input text");
224 			goto outa;
225 		}
226 	}
227 	while(lookup(asc) == 0){
228 		if(ascom() == 0)goto notas;
229 		while(buf[i] != '\n' && buf[i++] != ':')
230 			if(i >= in)goto notas;
231 		while(buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\t')if(i++ >= in)goto notas;
232 		j = i-1;
233 		if(buf[i] == '.'){
234 			i++;
235 			if(lookup(as) == 1){
236 				printf("assembler program text");
237 				goto outa;
238 			}
239 			else if(buf[j] == '\n' && isalpha(buf[j+2])){
240 				printf("roff, nroff, or eqn input text");
241 				goto outa;
242 			}
243 		}
244 	}
245 	printf("assembler program text");
246 	goto outa;
247 notas:
248 	for(i=0; i < in; i++)if(buf[i]&0200){
249 		if (buf[0]=='\100' && buf[1]=='\357') {
250 			printf("troff (CAT) output\n");
251 			goto out;
252 		}
253 		printf("data\n");
254 		goto out;
255 	}
256 	if (mbuf.st_mode&((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6)))
257 		printf("commands text");
258 	else if (troffint(buf, in))
259 		printf("troff intermediate output text");
260 	else if (english(buf, in))
261 		printf("English text");
262 	else
263 		printf("ascii text");
264 outa:
265 	while(i < in)
266 		if((buf[i++]&0377) > 127){
267 			printf(" with garbage\n");
268 			goto out;
269 		}
270 	/* if next few lines in then read whole file looking for nulls ...
271 		while((in = read(ifile,buf,BUFSIZ)) > 0)
272 			for(i = 0; i < in; i++)
273 				if((buf[i]&0377) > 127){
274 					printf(" with garbage\n");
275 					goto out;
276 				}
277 		/*.... */
278 	printf("\n");
279 out:;
280 }
281 
282 oldo(cp)
283 char *cp;
284 {
285 	struct exec ex;
286 	struct stat stb;
287 
288 	ex = *(struct exec *)cp;
289 	if (fstat(ifile, &stb) < 0)
290 		return(0);
291 	if (N_STROFF(ex)+sizeof(off_t) > stb.st_size)
292 		return (1);
293 	return (0);
294 }
295 
296 
297 
298 troffint(bp, n)
299 char *bp;
300 int n;
301 {
302 	int k;
303 
304 	i = 0;
305 	for (k = 0; k < 6; k++) {
306 		if (lookup(troff) == 0)
307 			return(0);
308 		if (lookup(troff) == 0)
309 			return(0);
310 		while (i < n && buf[i] != '\n')
311 			i++;
312 		if (i++ >= n)
313 			return(0);
314 	}
315 	return(1);
316 }
317 lookup(tab)
318 char *tab[];
319 {
320 	char r;
321 	int k,j,l;
322 	while(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n')i++;
323 	for(j=0; tab[j] != 0; j++){
324 		l=0;
325 		for(k=i; ((r=tab[j][l++]) == buf[k] && r != '\0');k++);
326 		if(r == '\0')
327 			if(buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\t'
328 			    || buf[k] == '{' || buf[k] == '/'){
329 				i=k;
330 				return(1);
331 			}
332 	}
333 	return(0);
334 }
335 ccom(){
336 	char cc;
337 	while((cc = buf[i]) == ' ' || cc == '\t' || cc == '\n')if(i++ >= in)return(0);
338 	if(buf[i] == '/' && buf[i+1] == '*'){
339 		i += 2;
340 		while(buf[i] != '*' || buf[i+1] != '/'){
341 			if(buf[i] == '\\')i += 2;
342 			else i++;
343 			if(i >= in)return(0);
344 		}
345 		if((i += 2) >= in)return(0);
346 	}
347 	if(buf[i] == '\n')if(ccom() == 0)return(0);
348 	return(1);
349 }
350 ascom(){
351 	while(buf[i] == '/'){
352 		i++;
353 		while(buf[i++] != '\n')if(i >= in)return(0);
354 		while(buf[i] == '\n')if(i++ >= in)return(0);
355 	}
356 	return(1);
357 }
358 
359 english (bp, n)
360 char *bp;
361 {
362 # define NASC 128
363 	int ct[NASC], j, vow, freq, rare;
364 	int badpun = 0, punct = 0;
365 	if (n<50) return(0); /* no point in statistics on squibs */
366 	for(j=0; j<NASC; j++)
367 		ct[j]=0;
368 	for(j=0; j<n; j++)
369 	{
370 		if (bp[j]<NASC)
371 			ct[bp[j]|040]++;
372 		switch (bp[j])
373 		{
374 		case '.':
375 		case ',':
376 		case ')':
377 		case '%':
378 		case ';':
379 		case ':':
380 		case '?':
381 			punct++;
382 			if ( j < n-1 &&
383 			    bp[j+1] != ' ' &&
384 			    bp[j+1] != '\n')
385 				badpun++;
386 		}
387 	}
388 	if (badpun*5 > punct)
389 		return(0);
390 	vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u'];
391 	freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n'];
392 	rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z'];
393 	if (2*ct[';'] > ct['e']) return(0);
394 	if ( (ct['>']+ct['<']+ct['/'])>ct['e']) return(0); /* shell file test */
395 	return (vow*5 >= n-ct[' '] && freq >= 10*rare);
396 }
397