1 /*-
2 * Copyright (c) 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1991, 1993, 1994\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)file.c 8.2 (Berkeley) 03/31/94";
16 #endif /* not lint */
17
18 /*
19 * file - determine type of file
20 */
21
22 #include <sys/param.h>
23 #include <sys/stat.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <a.out.h>
28
29 #if defined(hp300) || defined(hp800)
30 #include <hp/hpux/hpux_exec.h>
31 #endif
32
33 extern int errno;
34 int in;
35 int i = 0;
36
37 #define BUFSIZE 4096
38
39 char buf[BUFSIZE];
40 char *troff[] = { /* new troff intermediate lang */
41 "x","T","res","init","font","202","V0","p1",0};
42 char *fort[] = {
43 "function","subroutine","common","dimension","block","integer",
44 "real","data","double",0};
45 char *asc[] = {
46 "chmk","mov","tst","clr","jmp",0};
47 char *c[] = {
48 "int","char","float","double","struct","extern", "static",0};
49 char *as[] = {
50 "globl","byte","align","text","data","comm",0};
51 char *sh[] = {
52 "fi", "elif", "esac", "done", "export",
53 "readonly", "trap", "PATH", "HOME", 0 };
54 char *csh[] = {
55 "alias", "breaksw", "endsw", "foreach", "limit", "onintr",
56 "repeat", "setenv", "source", "path", "home", 0 };
57 int ifile;
58
59 int (*statfcn) __P((const char *, struct stat *));
60
main(argc,argv)61 main(argc, argv)
62 char **argv;
63 {
64 FILE *fl;
65 register char *p;
66 char ap[MAXPATHLEN + 1];
67
68 if (argc < 2) {
69 fprintf(stderr, "usage: %s file ...\n", argv[0]);
70 exit(3);
71 }
72
73 if (argc>1 && argv[1][0]=='-' && argv[1][1]=='h') {
74 statfcn = lstat;
75 --argc;
76 ++argv;
77 } else
78 statfcn = stat;
79
80 if (argc>1 && argv[1][0]=='-' && argv[1][1]=='f') {
81 if ((fl = fopen(argv[2], "r")) == NULL) {
82 perror(argv[2]);
83 exit(2);
84 }
85 while ((p = fgets(ap, sizeof ap, fl)) != NULL) {
86 int l = strlen(p);
87 if (l>0)
88 p[l-1] = '\0';
89 type(p);
90 if (ifile>=0)
91 close(ifile);
92 }
93 exit(1);
94 }
95 while(argc > 1) {
96 ifile = -1;
97 type(argv[1]);
98 fflush(stdout);
99 argc--;
100 argv++;
101 if (ifile >= 0)
102 close(ifile);
103 }
104 exit(0);
105 }
106
type(file)107 type(file)
108 char *file;
109 {
110 int j,nl;
111 char ch;
112 struct stat mbuf;
113 char slink[MAXPATHLEN + 1];
114 struct exec *hdr;
115 #if defined(hp300) || defined(hp800)
116 int ishpux300 = 0;
117 int ishpux800 = 0;
118 #endif
119
120 if (statfcn(file, &mbuf) < 0 &&
121 (statfcn == lstat || lstat(file, &mbuf))) {
122 fprintf(stderr, "file: %s: %s\n", file, strerror(errno));
123 return;
124 }
125 switch (mbuf.st_mode & S_IFMT) {
126 case S_IFLNK:
127 printf("%s:\tsymbolic link", file);
128 j = readlink(file, slink, sizeof slink - 1);
129 if (j >= 0) {
130 slink[j] = '\0';
131 printf(" to %s", slink);
132 }
133 printf("\n");
134 return;
135
136 case S_IFDIR:
137 printf("%s:\t", file);
138 if (mbuf.st_mode & S_ISVTX)
139 printf("append-only ");
140 printf("directory\n");
141 return;
142
143 case S_IFCHR:
144 case S_IFBLK:
145 printf("%s:\t%s special (%d/%d)\n", file,
146 (mbuf.st_mode&S_IFMT) == S_IFCHR ? "character" : "block",
147 major(mbuf.st_rdev), minor(mbuf.st_rdev));
148 return;
149
150 case S_IFSOCK:
151 printf("%s:\tsocket\n", file);
152 return;
153 }
154
155 ifile = open(file, 0);
156 if (ifile < 0) {
157 fprintf(stderr, "file: %s: %s\n", file, strerror(errno));
158 return;
159 }
160 printf("%s:\t", file);
161 in = read(ifile, buf, BUFSIZE);
162 if (in == 0) {
163 printf("empty\n");
164 return;
165 }
166 hdr = (struct exec *) buf;
167 #ifdef MID_ZERO /* if we have a_mid field */
168 switch (hdr->a_mid) {
169 case MID_SUN010:
170 printf("SUN 68010/68020 ");
171 break;
172 case MID_SUN020:
173 printf("SUN 68020 ");
174 break;
175 case MID_HP200:
176 printf("HP200 ");
177 break;
178 case MID_HP300:
179 printf("HP300 ");
180 break;
181 #if defined(hp300) || defined(hp800)
182 case MID_HPUX:
183 printf("HP-UX series [234]00 ");
184 ishpux300 = 1;
185 if (hdr->a_magic == 0406) {
186 printf("relocatable object\n");
187 return;
188 }
189 break;
190 case MID_HPUX800:
191 printf("HP-UX series 800 ");
192 ishpux800 = 1;
193 if (hdr->a_magic == 0x106) {
194 printf("relocatable object\n");
195 return;
196 }
197 break;
198 #endif
199 #ifdef MID_MIPSI
200 case MID_MIPSI:
201 printf("MIPS R3000 ");
202 break;
203 #endif
204 #ifdef MID_MIPSII
205 case MID_MIPSII:
206 printf("MIPS R4000 ");
207 break;
208 #endif
209 #if BYTE_ORDER == BIG_ENDIAN
210 case ((OMAGIC & 0xff) << 8) | (OMAGIC >> 8):
211 case ((NMAGIC & 0xff) << 8) | (NMAGIC >> 8):
212 case ((ZMAGIC & 0xff) << 8) | (ZMAGIC >> 8):
213 printf("byte-swapped (VAX/386) ");
214 hdr->a_magic = ((hdr->a_mid & 0xff) << 8) | (hdr->a_mid >> 8);
215 break;
216 #endif
217 }
218 #endif /* MID_ZERO, a_mid */
219 switch (hdr->a_magic) {
220
221 case 0411:
222 printf("jfr or pdp-11 unix 411 executable\n");
223 return;
224
225 case ZMAGIC:
226 printf("demand paged ");
227 /* FALLTHROUGH */
228
229 case NMAGIC:
230 printf("pure ");
231 /* FALLTHROUGH */
232
233 case OMAGIC:
234 if (mbuf.st_mode & S_ISUID)
235 printf("set-uid ");
236 if (mbuf.st_mode & S_ISGID)
237 printf("set-gid ");
238 if (mbuf.st_mode & S_ISVTX)
239 printf("sticky ");
240 if ((mbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 &&
241 (hdr->a_trsize || hdr->a_drsize)) {
242 printf("relocatable object\n");
243 return;
244 }
245 #if defined(hp300)
246 if (ishpux300) {
247 if (((int *)buf)[2] & 0x40000000)
248 printf("dynamically-linked ");
249 }
250 #endif
251 printf("executable");
252 #if defined(hp300) || defined(hp800)
253 if (ishpux300) {
254 if (((int *)buf)[9] != 0)
255 printf(" not stripped");
256 } else if (ishpux800) {
257 if (((int *)buf)[24] != 0)
258 printf(" not stripped");
259 } else
260 #endif
261 if (hdr->a_syms != 0)
262 printf(" not stripped");
263 printf("\n");
264 return;
265 #if defined(hp300)
266 case 0x10e:
267 printf("shared library, version %d\n", ((short *)buf)[2]);
268 return;
269 #endif
270 }
271
272 switch (*(int *)buf) {
273 case 0177555:
274 printf("very old archive\n");
275 return;
276
277 case 0177545:
278 printf("old archive\n");
279 return;
280
281 case 070707:
282 printf("cpio data\n");
283 return;
284 }
285
286 if (buf[0] == '#' && buf[1] == '!' && shellscript(buf+2, &mbuf))
287 return;
288 if (buf[0] == '\037' && buf[1] == '\235') {
289 if (buf[2]&0x80)
290 printf("block ");
291 printf("compressed %d bit code data\n", buf[2]&0x1f);
292 return;
293 }
294 if (strncmp(buf, "!<arch>\n__.SYMDEF", 17) == 0 ) {
295 printf("archive random library\n");
296 return;
297 }
298 if (strncmp(buf, "!<arch>\n", 8)==0) {
299 printf("archive\n");
300 return;
301 }
302 if (mbuf.st_size % 512 == 0) { /* it may be a PRESS file */
303 lseek(ifile, -512L, 2); /* last block */
304 if (read(ifile, buf, BUFSIZE) > 0 && *(short *)buf == 12138) {
305 printf("PRESS file\n");
306 return;
307 }
308 }
309 i = 0;
310 if(ccom() == 0)goto notc;
311 while(buf[i] == '#'){
312 j = i;
313 while(buf[i++] != '\n'){
314 if(i - j > 255){
315 printf("data\n");
316 return;
317 }
318 if(i >= in)goto notc;
319 }
320 if(ccom() == 0)goto notc;
321 }
322 check:
323 if(lookup(c) == 1){
324 while((ch = buf[i++]) != ';' && ch != '{')if(i >= in)goto notc;
325 printf("c program text");
326 goto outa;
327 }
328 nl = 0;
329 while(buf[i] != '('){
330 if(buf[i] <= 0)
331 goto notas;
332 if(buf[i] == ';'){
333 i++;
334 goto check;
335 }
336 if(buf[i++] == '\n')
337 if(nl++ > 6)goto notc;
338 if(i >= in)goto notc;
339 }
340 while(buf[i] != ')'){
341 if(buf[i++] == '\n')
342 if(nl++ > 6)goto notc;
343 if(i >= in)goto notc;
344 }
345 while(buf[i] != '{'){
346 if(buf[i++] == '\n')
347 if(nl++ > 6)goto notc;
348 if(i >= in)goto notc;
349 }
350 printf("c program text");
351 goto outa;
352 notc:
353 i = 0;
354 while(buf[i] == 'c' || buf[i] == '#'){
355 while(buf[i++] != '\n')if(i >= in)goto notfort;
356 }
357 if(lookup(fort) == 1){
358 printf("fortran program text");
359 goto outa;
360 }
361 notfort:
362 i=0;
363 if(ascom() == 0)goto notas;
364 j = i-1;
365 if(buf[i] == '.'){
366 i++;
367 if(lookup(as) == 1){
368 printf("assembler program text");
369 goto outa;
370 }
371 else if(buf[j] == '\n' && isalpha(buf[j+2])){
372 printf("roff, nroff, or eqn input text");
373 goto outa;
374 }
375 }
376 while(lookup(asc) == 0){
377 if(ascom() == 0)goto notas;
378 while(buf[i] != '\n' && buf[i++] != ':')
379 if(i >= in)goto notas;
380 while(buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\t')if(i++ >= in)goto notas;
381 j = i-1;
382 if(buf[i] == '.'){
383 i++;
384 if(lookup(as) == 1){
385 printf("assembler program text");
386 goto outa;
387 }
388 else if(buf[j] == '\n' && isalpha(buf[j+2])){
389 printf("roff, nroff, or eqn input text");
390 goto outa;
391 }
392 }
393 }
394 printf("assembler program text");
395 goto outa;
396 notas:
397 for(i=0; i < in; i++)if(buf[i]&0200){
398 if (buf[0]=='\100' && buf[1]=='\357')
399 printf("troff (CAT) output\n");
400 else
401 printf("data\n");
402 return;
403 }
404 if (mbuf.st_mode&((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6))) {
405 if (mbuf.st_mode & S_ISUID)
406 printf("set-uid ");
407 if (mbuf.st_mode & S_ISGID)
408 printf("set-gid ");
409 if (mbuf.st_mode & S_ISVTX)
410 printf("sticky ");
411 if (shell(buf, in, sh))
412 printf("shell script");
413 else if (shell(buf, in, csh))
414 printf("c-shell script");
415 else
416 printf("commands text");
417 } else if (troffint(buf, in))
418 printf("troff intermediate output text");
419 else if (shell(buf, in, sh))
420 printf("shell commands");
421 else if (shell(buf, in, csh))
422 printf("c-shell commands");
423 else if (english(buf, in))
424 printf("English text");
425 else
426 printf("ascii text");
427 outa:
428 while(i < in)
429 if((buf[i++]&0377) > 127){
430 printf(" with garbage\n");
431 return;
432 }
433 /* if next few lines in then read whole file looking for nulls ...
434 while((in = read(ifile,buf,BUFSIZE)) > 0)
435 for(i = 0; i < in; i++)
436 if((buf[i]&0377) > 127){
437 printf(" with garbage\n");
438 return;
439 }
440 /*.... */
441 printf("\n");
442 }
443
troffint(bp,n)444 troffint(bp, n)
445 char *bp;
446 int n;
447 {
448 int k;
449
450 i = 0;
451 for (k = 0; k < 6; k++) {
452 if (lookup(troff) == 0)
453 return(0);
454 if (lookup(troff) == 0)
455 return(0);
456 while (i < n && buf[i] != '\n')
457 i++;
458 if (i++ >= n)
459 return(0);
460 }
461 return(1);
462 }
lookup(tab)463 lookup(tab)
464 char *tab[];
465 {
466 char r;
467 int k,j,l;
468 while(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n')i++;
469 for(j=0; tab[j] != 0; j++){
470 l=0;
471 for(k=i; ((r=tab[j][l++]) == buf[k] && r != '\0');k++);
472 if(r == '\0')
473 if(buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\t'
474 || buf[k] == '{' || buf[k] == '/'){
475 i=k;
476 return(1);
477 }
478 }
479 return(0);
480 }
ccom()481 ccom(){
482 char cc;
483 while((cc = buf[i]) == ' ' || cc == '\t' || cc == '\n')if(i++ >= in)return(0);
484 if(buf[i] == '/' && buf[i+1] == '*'){
485 i += 2;
486 while(buf[i] != '*' || buf[i+1] != '/'){
487 if(buf[i] == '\\')i += 2;
488 else i++;
489 if(i >= in)return(0);
490 }
491 if((i += 2) >= in)return(0);
492 }
493 if(buf[i] == '\n')if(ccom() == 0)return(0);
494 return(1);
495 }
ascom()496 ascom(){
497 while(buf[i] == '/'){
498 i++;
499 while(buf[i++] != '\n')if(i >= in)return(0);
500 while(buf[i] == '\n')if(i++ >= in)return(0);
501 }
502 return(1);
503 }
504
english(bp,n)505 english (bp, n)
506 char *bp;
507 {
508 # define NASC 128
509 int ct[NASC], j, vow, freq, rare;
510 int badpun = 0, punct = 0;
511 if (n<50) return(0); /* no point in statistics on squibs */
512 for(j=0; j<NASC; j++)
513 ct[j]=0;
514 for(j=0; j<n; j++)
515 {
516 if ((u_char)bp[j]<NASC)
517 ct[bp[j]|040]++;
518 switch (bp[j])
519 {
520 case '.':
521 case ',':
522 case ')':
523 case '%':
524 case ';':
525 case ':':
526 case '?':
527 punct++;
528 if ( j < n-1 &&
529 bp[j+1] != ' ' &&
530 bp[j+1] != '\n')
531 badpun++;
532 }
533 }
534 if (badpun*5 > punct)
535 return(0);
536 vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u'];
537 freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n'];
538 rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z'];
539 if (2*ct[';'] > ct['e']) return(0);
540 if ( (ct['>']+ct['<']+ct['/'])>ct['e']) return(0); /* shell file test */
541 return (vow*5 >= n-ct[' '] && freq >= 10*rare);
542 }
543
shellscript(buf,sb)544 shellscript(buf, sb)
545 char buf[];
546 struct stat *sb;
547 {
548 register char *tp;
549 char *cp, *xp, *index();
550
551 cp = index(buf, '\n');
552 if (cp == 0 || cp - buf > in)
553 return (0);
554 for (tp = buf; tp != cp && isspace(*tp); tp++)
555 if (!isascii(*tp))
556 return (0);
557 for (xp = tp; tp != cp && !isspace(*tp); tp++)
558 if (!isascii(*tp))
559 return (0);
560 if (tp == xp)
561 return (0);
562 if (sb->st_mode & S_ISUID)
563 printf("set-uid ");
564 if (sb->st_mode & S_ISGID)
565 printf("set-gid ");
566 if (strncmp(xp, "/bin/sh", tp-xp) == 0)
567 xp = "shell";
568 else if (strncmp(xp, "/bin/csh", tp-xp) == 0)
569 xp = "c-shell";
570 else
571 *tp = '\0';
572 printf("executable %s script\n", xp);
573 return (1);
574 }
575
shell(bp,n,tab)576 shell(bp, n, tab)
577 char *bp;
578 int n;
579 char *tab[];
580 {
581
582 i = 0;
583 do {
584 if (buf[i] == '#' || buf[i] == ':')
585 while (i < n && buf[i] != '\n')
586 i++;
587 if (++i >= n)
588 break;
589 if (lookup(tab) == 1)
590 return (1);
591 } while (i < n);
592 return (0);
593 }
594