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