update for 4.3
[unix-history] / usr / src / usr.bin / file / file.c
CommitLineData
34aa0635 1#ifndef lint
d1e27000 2static char sccsid[] = "@(#)file.c 4.10 (Berkeley) %G%";
34aa0635 3#endif
fd2fc6c6
BJ
4/*
5 * file - determine type of file
6 */
7
5f9c2dd3 8#include <sys/param.h>
56140c8b 9#include <sys/stat.h>
fd2fc6c6
BJ
10#include <stdio.h>
11#include <ctype.h>
75ea79ff 12#include <a.out.h>
136b085b 13int errno;
5f9c2dd3 14int sys_nerr;
136b085b 15char *sys_errlist[];
fd2fc6c6
BJ
16int in;
17int i = 0;
18char buf[BUFSIZ];
19char *troff[] = { /* new troff intermediate lang */
20 "x","T","res","init","font","202","V0","p1",0};
21char *fort[] = {
22 "function","subroutine","common","dimension","block","integer",
23 "real","data","double",0};
24char *asc[] = {
25 "chmk","mov","tst","clr","jmp",0};
26char *c[] = {
27 "int","char","float","double","struct","extern",0};
28char *as[] = {
29 "globl","byte","align","text","data","comm",0};
d1e27000
SL
30char *sh[] = {
31 "fi", "elif", "esac", "done", "export",
32 "readonly", "trap", "PATH", "HOME", 0 };
33char *csh[] = {
34 "alias", "breaksw", "endsw", "foreach", "limit", "onintr",
35 "repeat", "setenv", "source", "path", "home", 0 };
fd2fc6c6
BJ
36int ifile;
37
38main(argc, argv)
39char **argv;
40{
41 FILE *fl;
42 register char *p;
5f9c2dd3 43 char ap[MAXPATHLEN + 1];
fd2fc6c6
BJ
44 extern char _sobuf[];
45
5f9c2dd3
S
46 if (argc < 2) {
47 fprintf(stderr, "usage: %s file ...\n", argv[0]);
48 exit(3);
49 }
50
fd2fc6c6
BJ
51 if (argc>1 && argv[1][0]=='-' && argv[1][1]=='f') {
52 if ((fl = fopen(argv[2], "r")) == NULL) {
136b085b 53 perror(argv[2]);
fd2fc6c6
BJ
54 exit(2);
55 }
5f9c2dd3 56 while ((p = fgets(ap, sizeof ap, fl)) != NULL) {
fd2fc6c6
BJ
57 int l = strlen(p);
58 if (l>0)
59 p[l-1] = '\0';
60 printf("%s: ", p);
61 type(p);
62 if (ifile>=0)
63 close(ifile);
64 }
65 exit(1);
66 }
67 while(argc > 1) {
68 printf("%s: ", argv[1]);
69 type(argv[1]);
70 fflush(stdout);
71 argc--;
72 argv++;
73 if (ifile >= 0)
74 close(ifile);
75 }
5f9c2dd3 76 exit(0);
fd2fc6c6
BJ
77}
78
79type(file)
80char *file;
81{
82 int j,nl;
83 char ch;
84 struct stat mbuf;
5f9c2dd3 85 char slink[MAXPATHLEN + 1];
fd2fc6c6
BJ
86
87 ifile = -1;
2db3d63d 88 if (lstat(file, &mbuf) < 0) {
5f9c2dd3
S
89 printf("%s\n",
90 (unsigned)errno < sys_nerr? sys_errlist[errno]: "Cannot stat");
fd2fc6c6
BJ
91 return;
92 }
93 switch (mbuf.st_mode & S_IFMT) {
94
2db3d63d 95 case S_IFLNK:
5f9c2dd3
S
96 printf("symbolic link");
97 j = readlink(file, slink, sizeof slink - 1);
98 if (j >= 0) {
99 slink[j] = '\0';
100 printf(" to %s", slink);
101 }
102 printf("\n");
fd2fc6c6
BJ
103 return;
104
2db3d63d 105 case S_IFDIR:
5f9c2dd3
S
106 if (mbuf.st_mode & S_ISVTX)
107 printf("append-only ");
2db3d63d 108 printf("directory\n");
fd2fc6c6
BJ
109 return;
110
5f9c2dd3 111 case S_IFCHR:
fd2fc6c6 112 case S_IFBLK:
5f9c2dd3
S
113 printf("%s special (%d/%d)\n",
114 mbuf.st_mode&S_IFMT == S_IFCHR ? "character" : "block",
115 major(mbuf.st_rdev), minor(mbuf.st_rdev));
116 return;
fd2fc6c6 117
5f9c2dd3
S
118 case S_IFSOCK:
119 printf("socket\n");
fd2fc6c6
BJ
120 return;
121 }
122
123 ifile = open(file, 0);
124 if(ifile < 0) {
5f9c2dd3
S
125 printf("%s\n",
126 (unsigned)errno < sys_nerr? sys_errlist[errno]: "Cannot read");
fd2fc6c6
BJ
127 return;
128 }
129 in = read(ifile, buf, BUFSIZ);
130 if(in == 0){
131 printf("empty\n");
132 return;
133 }
134 switch(*(int *)buf) {
135
136 case 0413:
137 printf("demand paged ");
138
139 case 0410:
140 printf("pure ");
141 goto exec;
142
143 case 0411:
144 printf("jfr or pdp-11 unix 411 executable\n");
145 return;
146
147 case 0407:
148exec:
5f9c2dd3
S
149 if (mbuf.st_mode & S_ISUID)
150 printf("set-uid ");
151 if (mbuf.st_mode & S_ISGID)
152 printf("set-gid ");
153 if (mbuf.st_mode & S_ISVTX)
154 printf("sticky ");
fd2fc6c6
BJ
155 printf("executable");
156 if(((int *)buf)[4] != 0) {
157 printf(" not stripped");
158 if(oldo(buf))
159 printf(" (old format symbol table)");
160 }
161 printf("\n");
d1e27000 162 return;
fd2fc6c6
BJ
163
164 case 0177555:
165 printf("very old archive\n");
d1e27000 166 return;
fd2fc6c6
BJ
167
168 case 0177545:
169 printf("old archive\n");
d1e27000 170 return;
c083f459
BJ
171
172 case 070707:
173 printf("cpio data\n");
d1e27000 174 return;
fd2fc6c6
BJ
175 }
176
d1e27000
SL
177 if (buf[0] == '#' && buf[1] == '!' && shellscript(buf+2, &mbuf))
178 return;
fd2fc6c6
BJ
179 if(strncmp(buf, "!<arch>\n__.SYMDEF", 17) == 0 ) {
180 printf("archive random library\n");
d1e27000 181 return;
fd2fc6c6
BJ
182 }
183 if (strncmp(buf, "!<arch>\n", 8)==0) {
184 printf("archive\n");
d1e27000 185 return;
fd2fc6c6 186 }
47aeb93c
BJ
187 if (mbuf.st_size % 512 == 0) { /* it may be a PRESS file */
188 lseek(ifile, -512L, 2); /* last block */
d1e27000 189 if (read(ifile, buf, BUFSIZ) > 0 && *(short *)buf == 12138) {
47aeb93c 190 printf("PRESS file\n");
d1e27000 191 return;
47aeb93c
BJ
192 }
193 }
fd2fc6c6
BJ
194 i = 0;
195 if(ccom() == 0)goto notc;
196 while(buf[i] == '#'){
197 j = i;
198 while(buf[i++] != '\n'){
199 if(i - j > 255){
200 printf("data\n");
d1e27000 201 return;
fd2fc6c6
BJ
202 }
203 if(i >= in)goto notc;
204 }
205 if(ccom() == 0)goto notc;
206 }
207check:
208 if(lookup(c) == 1){
209 while((ch = buf[i++]) != ';' && ch != '{')if(i >= in)goto notc;
210 printf("c program text");
211 goto outa;
212 }
213 nl = 0;
214 while(buf[i] != '('){
215 if(buf[i] <= 0)
216 goto notas;
217 if(buf[i] == ';'){
218 i++;
219 goto check;
220 }
221 if(buf[i++] == '\n')
222 if(nl++ > 6)goto notc;
223 if(i >= in)goto notc;
224 }
225 while(buf[i] != ')'){
226 if(buf[i++] == '\n')
227 if(nl++ > 6)goto notc;
228 if(i >= in)goto notc;
229 }
230 while(buf[i] != '{'){
231 if(buf[i++] == '\n')
232 if(nl++ > 6)goto notc;
233 if(i >= in)goto notc;
234 }
235 printf("c program text");
236 goto outa;
237notc:
238 i = 0;
239 while(buf[i] == 'c' || buf[i] == '#'){
240 while(buf[i++] != '\n')if(i >= in)goto notfort;
241 }
242 if(lookup(fort) == 1){
243 printf("fortran program text");
244 goto outa;
245 }
246notfort:
247 i=0;
248 if(ascom() == 0)goto notas;
249 j = i-1;
250 if(buf[i] == '.'){
251 i++;
252 if(lookup(as) == 1){
253 printf("assembler program text");
254 goto outa;
255 }
256 else if(buf[j] == '\n' && isalpha(buf[j+2])){
257 printf("roff, nroff, or eqn input text");
258 goto outa;
259 }
260 }
261 while(lookup(asc) == 0){
262 if(ascom() == 0)goto notas;
263 while(buf[i] != '\n' && buf[i++] != ':')
264 if(i >= in)goto notas;
265 while(buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\t')if(i++ >= in)goto notas;
266 j = i-1;
267 if(buf[i] == '.'){
268 i++;
269 if(lookup(as) == 1){
270 printf("assembler program text");
271 goto outa;
272 }
273 else if(buf[j] == '\n' && isalpha(buf[j+2])){
274 printf("roff, nroff, or eqn input text");
275 goto outa;
276 }
277 }
278 }
279 printf("assembler program text");
280 goto outa;
281notas:
282 for(i=0; i < in; i++)if(buf[i]&0200){
d1e27000 283 if (buf[0]=='\100' && buf[1]=='\357')
fd2fc6c6 284 printf("troff (CAT) output\n");
d1e27000
SL
285 else
286 printf("data\n");
287 return;
fd2fc6c6 288 }
5f9c2dd3
S
289 if (mbuf.st_mode&((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6))) {
290 if (mbuf.st_mode & S_ISUID)
291 printf("set-uid ");
292 if (mbuf.st_mode & S_ISGID)
293 printf("set-gid ");
294 if (mbuf.st_mode & S_ISVTX)
295 printf("sticky ");
d1e27000
SL
296 if (shell(buf, in, sh))
297 printf("shell script");
298 else if (shell(buf, in, csh))
299 printf("c-shell script");
300 else
301 printf("commands text");
5f9c2dd3 302 } else if (troffint(buf, in))
fd2fc6c6 303 printf("troff intermediate output text");
d1e27000
SL
304 else if (shell(buf, in, sh))
305 printf("shell commands");
306 else if (shell(buf, in, csh))
307 printf("c-shell commands");
fd2fc6c6
BJ
308 else if (english(buf, in))
309 printf("English text");
310 else
311 printf("ascii text");
312outa:
313 while(i < in)
314 if((buf[i++]&0377) > 127){
315 printf(" with garbage\n");
d1e27000 316 return;
fd2fc6c6
BJ
317 }
318 /* if next few lines in then read whole file looking for nulls ...
319 while((in = read(ifile,buf,BUFSIZ)) > 0)
320 for(i = 0; i < in; i++)
321 if((buf[i]&0377) > 127){
322 printf(" with garbage\n");
d1e27000 323 return;
fd2fc6c6
BJ
324 }
325 /*.... */
326 printf("\n");
fd2fc6c6
BJ
327}
328
329oldo(cp)
330char *cp;
331{
332 struct exec ex;
333 struct stat stb;
334
335 ex = *(struct exec *)cp;
336 if (fstat(ifile, &stb) < 0)
337 return(0);
338 if (N_STROFF(ex)+sizeof(off_t) > stb.st_size)
339 return (1);
340 return (0);
341}
342
343
344
345troffint(bp, n)
346char *bp;
347int n;
348{
349 int k;
350
351 i = 0;
352 for (k = 0; k < 6; k++) {
353 if (lookup(troff) == 0)
354 return(0);
355 if (lookup(troff) == 0)
356 return(0);
357 while (i < n && buf[i] != '\n')
358 i++;
359 if (i++ >= n)
360 return(0);
361 }
362 return(1);
363}
364lookup(tab)
365char *tab[];
366{
367 char r;
368 int k,j,l;
369 while(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n')i++;
370 for(j=0; tab[j] != 0; j++){
371 l=0;
372 for(k=i; ((r=tab[j][l++]) == buf[k] && r != '\0');k++);
373 if(r == '\0')
374 if(buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\t'
375 || buf[k] == '{' || buf[k] == '/'){
376 i=k;
377 return(1);
378 }
379 }
380 return(0);
381}
382ccom(){
383 char cc;
384 while((cc = buf[i]) == ' ' || cc == '\t' || cc == '\n')if(i++ >= in)return(0);
385 if(buf[i] == '/' && buf[i+1] == '*'){
386 i += 2;
387 while(buf[i] != '*' || buf[i+1] != '/'){
388 if(buf[i] == '\\')i += 2;
389 else i++;
390 if(i >= in)return(0);
391 }
392 if((i += 2) >= in)return(0);
393 }
394 if(buf[i] == '\n')if(ccom() == 0)return(0);
395 return(1);
396}
397ascom(){
398 while(buf[i] == '/'){
399 i++;
400 while(buf[i++] != '\n')if(i >= in)return(0);
401 while(buf[i] == '\n')if(i++ >= in)return(0);
402 }
403 return(1);
404}
405
406english (bp, n)
407char *bp;
408{
409# define NASC 128
410 int ct[NASC], j, vow, freq, rare;
411 int badpun = 0, punct = 0;
412 if (n<50) return(0); /* no point in statistics on squibs */
413 for(j=0; j<NASC; j++)
414 ct[j]=0;
415 for(j=0; j<n; j++)
416 {
417 if (bp[j]<NASC)
418 ct[bp[j]|040]++;
419 switch (bp[j])
420 {
421 case '.':
422 case ',':
423 case ')':
424 case '%':
425 case ';':
426 case ':':
427 case '?':
428 punct++;
429 if ( j < n-1 &&
430 bp[j+1] != ' ' &&
431 bp[j+1] != '\n')
432 badpun++;
433 }
434 }
435 if (badpun*5 > punct)
436 return(0);
437 vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u'];
438 freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n'];
439 rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z'];
440 if (2*ct[';'] > ct['e']) return(0);
441 if ( (ct['>']+ct['<']+ct['/'])>ct['e']) return(0); /* shell file test */
442 return (vow*5 >= n-ct[' '] && freq >= 10*rare);
443}
d1e27000
SL
444
445shellscript(buf, sb)
446 char buf[];
447 struct stat *sb;
448{
449 register char *tp;
450 char *cp, *xp, *index();
451
452 cp = index(buf, '\n');
453 if (cp == 0 || cp - buf > in)
454 return (0);
455 for (tp = buf; tp != cp && isspace(*tp); tp++)
456 if (!isascii(*tp))
457 return (0);
458 for (xp = tp; tp != cp && !isspace(*tp); tp++)
459 if (!isascii(*tp))
460 return (0);
461 if (tp == xp)
462 return (0);
463 if (sb->st_mode & S_ISUID)
464 printf("set-uid ");
465 if (sb->st_mode & S_ISGID)
466 printf("set-gid ");
467 if (strncmp(xp, "/bin/sh", tp-xp) == 0)
468 xp = "shell";
469 else if (strncmp(xp, "/bin/csh", tp-xp) == 0)
470 xp = "c-shell";
471 else
472 *tp = '\0';
473 printf("executable %s script\n", xp);
474 return (1);
475}
476
477shell(bp, n, tab)
478 char *bp;
479 int n;
480 char *tab[];
481{
482
483 i = 0;
484 do {
485 if (buf[i] == '#' || buf[i] == ':')
486 while (i < n && buf[i] != '\n')
487 i++;
488 if (++i >= n)
489 break;
490 if (lookup(tab) == 1)
491 return (1);
492 } while (i < n);
493 return (0);
494}