|
|
1.1 root 1: char _version[] = "Version 1.5";
2: /*
3: * Look at a file and try to
4: * figure out its type. Knows about the various
5: * flavours of filesystem entries, object files of various
6: * types, C programs, input to one of the various flavours
7: * of text formatter, etc.
8: */
9: #include <stdio.h>
10: #include <sys/coherent.h>
11: #include <ctype.h>
12: #include <sys/stat.h>
13: #include <sys/uproc.h>
14: #include <n.out.h>
15: #include <coff.h>
16: #include <canon.h>
17: #include <ar.h>
18: #include <arcoff.h>
19: #include <sys/core.h>
20:
21: /* UNIX archive magic numbers */
22: #define COFFARMAG "!<arch>\n"
23: #define COFFARMAG_RAN "!<arch>\n/"
24: #define UARMAG 0177545 /* UNIX v7 archives */
25: #define OUARMAG 0177555 /* UNIX v6 and previous archives */
26:
27: #define TYPE_LEN 120
28:
29: #define COMPRESSED 0x9D1F /* Output of "compress(1)" command. */
30:
31: #define EXEC (S_IEXEC|(S_IEXEC<<3)|(S_IEXEC<<6))
32:
33: /*
34: * Tar header.
35: */
36: struct th_info {
37: char th_name[100],
38: th_mode[8],
39: th_uid[8],
40: th_gid[8],
41: th_size[12],
42: th_mtime[12],
43: th_check[8],
44: th_islink,
45: th_link[100],
46: th_pad[255];
47: };
48:
49: /*
50: * The first BUFSIZ bytes of the
51: * file in question are read into this
52: * union. It contains members for accessing
53: * the possible file structures.
54: */
55:
56: union iobuf
57: {
58: char u_buf[BUFSIZ]; /* General data */
59: struct ldheader u_lout; /* L.out object file header */
60: struct filehdr u_coff; /* COFF object file header */
61: int u_armag; /* Archive number */
62: struct th_info u_tar; /* Tar header */
63: struct ch_info u_core; /* Core header */
64: };
65:
66: UPROC uProc;
67:
68: union iobuf iobuf;
69: char *file();
70: char *textclass();
71: char *objclass();
72: char *coffclass();
73: char *dirtype();
74: char *mtype();
75: char *coffmtype();
76: char *strcat();
77:
78: main(argc, argv)
79: char *argv[];
80: {
81: struct stat sb;
82: register char *p;
83: register int i;
84: register int estat;
85:
86: if (argc < 2) {
87: fprintf(stderr, "Usage: file name ...\n");
88: exit(1);
89: }
90: estat = 0;
91: for (i=1; i<argc; i++) {
92: p = argv[i];
93: if (stat(p, &sb) < 0) {
94: fprintf(stderr, "file: %s: not accessible\n", p);
95: estat = 1;
96: continue;
97: }
98: printf("%s: %s\n", p, file(&sb, p));
99: }
100: exit(estat);
101: }
102:
103: /*
104: * Routine to guess filetype
105: */
106: char *
107: file(sbp, fn)
108: struct stat *sbp;
109: char *fn;
110: {
111: static char buf[50];
112: unsigned short magic;
113: register int nb;
114: char type[TYPE_LEN];
115: register int fd = -1;
116:
117: if ((sbp->st_mode&S_IFMT) != S_IFREG) {
118: switch (sbp->st_mode & S_IFMT) {
119: case S_IFDIR:
120: return (dirtype(fn));
121:
122: case S_IFBLK:
123: sprintf(buf, "block special file %d/%d",
124: major(sbp->st_rdev), minor(sbp->st_rdev));
125: return (buf);
126:
127: case S_IFCHR:
128: sprintf(buf, "character special file %d/%d",
129: major(sbp->st_rdev), minor(sbp->st_rdev));
130: return (buf);
131:
132: case S_IFMPB:
133: return ("block multiplexor file");
134:
135: case S_IFMPC:
136: return ("character multiplexor file");
137:
138: case S_IFPIP:
139: return ("named pipe");
140:
141: default:
142: return ("invalid filetype");
143: }
144: }
145: if ((fd = open(fn, 0)) < 0)
146: return ("unreadable");
147: if ((nb = read(fd, (char *) &iobuf, sizeof(iobuf))) < 0) {
148: extern int errno;
149: printf("nb: %d, errno: %d ", nb, errno );
150: close(fd);
151: return ("read error");
152: }
153:
154: /* file of length zero? */
155: if (nb == 0) {
156: close(fd);
157: return ("empty");
158: }
159:
160: /* l.out executable? */
161: if (nb >= sizeof(struct ldheader)) {
162: magic = iobuf.u_lout.l_magic;
163: canint(magic);
164: if (magic == L_MAGIC) {
165: canint(iobuf.u_lout.l_flag);
166: canint(iobuf.u_lout.l_machine);
167: close(fd);
168: return (objclass(fd, &iobuf.u_lout));
169: }
170: }
171:
172: /* COFF executable? */
173: if (nb >= sizeof(struct filehdr)) {
174: magic = iobuf.u_coff.f_magic;
175: if (ISCOFF(magic)) {
176: close(fd);
177: return (coffclass(&iobuf.u_coff));
178: }
179: }
180:
181: /* COFF archive? */
182: if (nb >= strlen(COFFARMAG_RAN)) {
183: if (strncmp(COFFARMAG_RAN, iobuf.u_buf,
184: strlen(COFFARMAG_RAN)) == 0) {
185: close(fd);
186: return("COFF archive (ranlib)");
187: }
188: if ( strncmp(COFFARMAG, iobuf.u_buf, strlen(COFFARMAG)) == 0) {
189: close(fd);
190: return("COFF archive");
191: }
192: }
193:
194: /* {v7 tar} archive? */
195: if (nb >= sizeof(struct th_info)) {
196: if ( tar_path(iobuf.u_tar.th_name, 100) &&
197: tar_oct(iobuf.u_tar.th_mode, 8) &&
198: tar_dec(iobuf.u_tar.th_uid, 8) &&
199: tar_dec(iobuf.u_tar.th_gid, 8) &&
200: tar_dec(iobuf.u_tar.th_size, 12) &&
201: tar_dec(iobuf.u_tar.th_mtime, 12) &&
202: strlen(iobuf.u_tar.th_pad) < 8 ) {
203:
204: type[0] ='\0';
205: if ( '\0' != iobuf.u_tar.th_pad[0]) {
206: strcpy(type, iobuf.u_tar.th_pad);
207: } else {
208: strcpy(type, "v7 tar");
209: }
210:
211: strcat(type, " archive");
212: close(fd);
213: return(type);
214: } /* if looks like a tar header. */
215: }
216:
217: /* core file? */
218: if (nb >= sizeof(struct ch_info)) {
219: struct ch_info * cip = & iobuf.u_core;
220: int offset = cip->ch_info_len + cip->ch_uproc_offset;
221: int lsought, readed;
222:
223: magic = cip->ch_magic;
224: if (magic != CORE_MAGIC)
225: ; /* bad magic for core file */
226: else if (offset != (lsought = lseek(fd, offset, 0)))
227: ; /* can't seek far enough to find UPROC */
228: else if (sizeof(UPROC) !=
229: (readed = read(fd, &uProc, sizeof(UPROC))))
230: ; /* can't read UPROC */
231: else {
232: sprintf(type, "core file from \"%.10s\" uproc (v%04X)",
233: uProc.u_comm, uProc.u_version);
234: close(fd);
235: return(type);
236: }
237: }
238:
239: /* Archive or compress'ed file? */
240: if (nb >= sizeof (short)) {
241: magic = iobuf.u_armag;
242: canint(magic);
243: if (magic == ARMAG) {
244: close(fd);
245: return ("l.out archive");
246: }
247: if (magic == UARMAG) {
248: close(fd);
249: return ("seventh edition archive");
250: }
251: if (magic == OUARMAG) {
252: close(fd);
253: return ("sixth edition archive");
254: }
255: if (magic == COMPRESSED){
256: sprintf(type, "%d bit compressed file",
257: (int) (0x7f & iobuf.u_buf[2]));
258: close(fd);
259: return(type);
260: }
261: }
262:
263: if (hasnonascii((unsigned char *) &iobuf, nb)) {
264: close(fd);
265: return ("binary data");
266: }
267: if (sbp->st_mode & EXEC) {
268: if (strncmp(iobuf.u_buf, "#!", 2) == 0) {
269: sprintf(type, "%s script",
270: strtok(&(iobuf.u_buf[2]), " \t\n"));
271: close(fd);
272: return(type);
273: } else {
274: close(fd);
275: return ("commands");
276: }
277: }
278: close(fd);
279: return textclass((unsigned char *) &iobuf, nb);
280: }
281:
282: /*
283: * Return the type of the directory.
284: * Currently, only "s.*" is recognised as SCCS directory.
285: */
286: char *
287: dirtype(dn)
288: register char *dn;
289: {
290: register char *cp;
291:
292: for (cp = dn; *cp; cp++)
293: ;
294: while (cp > dn)
295: if (*--cp == '/') {
296: cp++;
297: break;
298: }
299: if (cp[0]=='s' && cp[1]=='.')
300: return ("SCCS directory");
301:
302: if (strcmp(cp, "RCS") == 0)
303: return ("RCS directory");
304:
305: return ("directory");
306: }
307:
308: /*
309: * Return true if there ar characters
310: * in the buffer that do not look like good
311: * ascii characters.
312: * This routine knows that ascii is a seven
313: * bit code.
314: */
315: hasnonascii(bp, nb)
316: register unsigned char *bp;
317: register nb;
318: {
319: while (nb--) {
320: if (!isascii(*bp))
321: return (1);
322: if (!(isprint(*bp) || isspace(*bp) || *bp=='\b' || *bp=='\a'))
323: return (1);
324: bp++;
325: }
326: return (0);
327: }
328:
329: /*
330: * Classify the first `nb'
331: * bytes of a text file.
332: */
333: char *
334: textclass(bp, nb)
335: register unsigned char *bp;
336: register nb;
337: {
338: register int c;
339: int nlf = 1;
340: int nlbrace;
341: int nrbrace;
342: int nsharps;
343: int nsemi;
344: int xmail;
345: char *sbp = bp;
346:
347: nlbrace = 0;
348: nrbrace = 0;
349: nsharps = 0;
350: nsemi = 0;
351: xmail = 0;
352: while (nb--) {
353: c = *bp++;
354: if (c=='.' && strncmp(bp, "globl", 5)==0)
355: return ("assembler");
356: if (nlf) {
357: if (c == '.')
358: return ("nroff, tbl or eqn input");
359: else if (c == ':')
360: return ("commands");
361: else if (c == '#')
362: ++nsharps;
363: else if (c=='%')
364: if (*bp=='%' || *bp=='{' || *bp=='}')
365: return ("yacc or lex input");
366: }
367: if (c == '{')
368: ++nlbrace;
369: else if (c == '}')
370: ++nrbrace;
371: if (c == '\n') {
372: nlf = 1;
373: if (bp[-2] == ';')
374: nsemi++;
375: if (((bp-sbp) % 22) == 0) {
376: if (bp[-2]==' ' || bp[-2]=='!')
377: xmail++;
378: } else
379: xmail = 0;
380: } else
381: nlf = 0;
382: }
383: if (xmail)
384: return ("xmail encoded text");
385: if ((nsharps || nsemi) && (nlbrace || nrbrace))
386: return ("C program");
387: return ("probably text");
388: }
389:
390: /*
391: * Figure out the type of an l.out
392: * object file. Tag it with the machine
393: * id if not for the machine upon which the
394: * command is running.
395: */
396: char *
397: objclass(fd, lhp)
398: register struct ldheader *lhp;
399: {
400: static char type[TYPE_LEN];
401: register char *mch;
402: struct ldsym lds;
403: register fsize_t stbase;
404: register i;
405:
406: type[0] = '\0';
407: if ((lhp->l_flag&LF_32) != 0)
408: strcat(type, "32 bit ");
409: if ((lhp->l_flag&LF_SLIB) != 0)
410: strcat(type, "shared library ");
411: if ((lhp->l_flag&LF_SLREF) != 0)
412: strcat(type, "libref ");
413: if ((lhp->l_flag&LF_SHR) != 0)
414: strcat(type, "shared ");
415: if ((lhp->l_flag&LF_SEP) != 0)
416: strcat(type, "separate ");
417: if ((lhp->l_flag&LF_KER) != 0) {
418: register unsigned ssize;
419:
420: ssize = sizeof (lds);
421: if ((lhp->l_flag & LF_32) == 0) {
422: stbase = sizeof(*lhp) - 2*sizeof(int);
423: ssize -= sizeof (int);
424: } else {
425: canshort(lhp->l_tbase);
426: stbase = lhp->l_tbase;
427: }
428: for (i=L_SHRI; i<L_SYM; ++i)
429: if (i!=L_BSSI && i!=L_BSSD) {
430: cansize(lhp->l_ssize[i]);
431: stbase += lhp->l_ssize[i];
432: }
433: lseek(fd, stbase, 0);
434: cansize(lhp->l_ssize[L_SYM]);
435: while (lhp->l_ssize[L_SYM] != 0) {
436: if (read(fd, &lds, ssize) != ssize)
437: break;
438: canshort(lds.ls_type);
439: if (strncmp(lds.ls_id, "conftab_", NCPLN) == 0
440: && (lds.ls_type&LR_SEG) != L_REF)
441: break;
442: lhp->l_ssize[L_SYM] -= ssize;
443: }
444: strcat(type, lhp->l_ssize[L_SYM]==0?"kernel ":"driver ");
445: }
446: strcat(type, "executable");
447: if ((lhp->l_flag&LF_NRB) == 0)
448: strcat(type, " with relocation");
449: if ((mch = mtype(lhp->l_machine)) == NULL)
450: mch = "Unknown machine type";
451: sprintf(type, "%s (%s)", type, mch);
452: return (type);
453: }
454:
455: /*
456: * Figure out the type of a coff
457: * object file. Tag it with the machine
458: * id if not for the machine upon which the
459: * command is running.
460: */
461: char *
462: coffclass(chp)
463: register struct filehdr *chp;
464: {
465: static char type[TYPE_LEN];
466: register char *mch;
467:
468: sprintf(type, "COFF ");
469: if ((chp->f_flags&F_MINMAL) != 0)
470: strcat(type, "minimal ");
471: #ifdef COFF_H_FIXED
472: if ((chp->f_flags&F_UPDATE) != 0)
473: strcat(type, "update ");
474: if ((chp->f_flags&F_SWABD) != 0)
475: strcat(type, "swapped bytes ");
476: if ((chp->f_flags&F_PATCH) != 0)
477: strcat(type, "patch ");
478: if ((chp->f_flags&F_NODF) != 0)
479: strcat(type, "no decision ");
480: #else /* COFF_H_FIXED */
481: if ((chp->f_flags&F_AR32WR) == 0)
482: strcat(type, "non i80x86 byte order ");
483: #endif /* COFF_H_FIXED */
484: if ((chp->f_flags&F_EXEC) != 0){
485: if ((chp->f_flags&F_LSYMS) != 0)
486: strcat(type, "stripped ");
487: strcat(type, "executable ");
488: } else {
489: strcat(type, "object ");
490: if ((chp->f_flags&F_RELFLG) != 0)
491: strcat(type, "stripped relocation ");
492: if ((chp->f_flags&F_LSYMS) != 0)
493: strcat(type, "stripped local symbols ");
494: }
495:
496: if ((mch = coffmtype(chp->f_magic)) == NULL)
497: mch = "Unknown machine type";
498: sprintf(type, "%s(%s) ", type, mch);
499:
500: return (type);
501: }
502:
503:
504: /*
505: * Identify a COFF executable.
506: */
507: char *
508: coffmtype(magic)
509: unsigned short magic;
510: {
511: switch ((unsigned) magic) {
512:
513: #ifdef COFF_H_FIXED
514: case IAPX16:
515: case IAPX16TV:
516: case IAPX20:
517: case IAPX20TV:
518: return("iAPX");
519:
520: case B16MAGIC:
521: case BTVMAGIC:
522: return("Intel Basic-16");
523:
524: case X86MAGIC:
525: case XTVMAGIC:
526: return("Intel x86");
527:
528: case I286SMAGIC:
529: return("Intel 286");
530:
531: case I386MAGIC:
532: return("Intel 386");
533:
534: case N3BMAGIC:
535: case NTVMAGIC:
536: return("New 3B");
537:
538: case WE32MAGIC:
539: case RBOMAGIC:
540: case MTVMAGIC:
541: return("MAC-32, 3515, 3B5");
542:
543: case VAXWRMAGIC:
544: case VAXROMAGIC:
545: return("VAX 11/780 or /750");
546:
547: case 0401:
548: case 0405:
549: case 0407:
550: case 0410:
551: case 0411:
552: case 0437:
553: return("pdp11");
554:
555: case MC68MAGIC:
556: case MC68TVMAGIC:
557: case M68MAGIC:
558: case M68TVMAGIC:
559: return("Motorola 680xx");
560:
561: /* case I286LMAGIC: */
562: case MC68KPGMAGIC:
563: return("UNIX PC or iAPX 286");
564:
565: case U370WRMAGIC:
566: case U370ROMAGIC:
567: return("IBM 370");
568:
569: case AMDWRMAGIC:
570: case AMDROMAGIC:
571: return("Amdahl 470/580");
572:
573: #else /* COFF_H_FIXED */
574: case C_386_MAGIC:
575: return("Intel 386");
576: #endif /* COFF_H_FIXED */
577:
578: default:
579: return(NULL);
580:
581: }
582: } /* coffmtype() */
583:
584: /*
585: * Decide if character array 'str' of length 'len' is an acceptable tar
586: * octal field. Returns TRUE if it is acceptable, FALSE otherwise.
587: */
588: int
589: tar_oct(str, len)
590: char *str;
591: int len;
592: {
593: for (; len > 0; --len, ++str) {
594: if (*str != '\0' && *str != ' ' &&
595: !('0' <= *str && *str <= '7')) {
596: break;
597: }
598: }
599:
600: return(0 == len);
601: } /* tar_oct() */
602:
603: /*
604: * Decide if character array 'str' of length 'len' is an acceptable tar
605: * decimal field. Returns TRUE if it is acceptable, FALSE otherwise.
606: */
607: int
608: tar_dec(str, len)
609: char *str;
610: int len;
611: {
612: for (; len > 0; --len, ++str) {
613: if (*str != '\0' && *str != ' ' &&
614: !isdigit(*str)) {
615: break;
616: }
617: }
618:
619: return(0 == len);
620: } /* tar_dec() */
621:
622: /*
623: * Decide if character array 'str' of length 'len' is an acceptable tar
624: * path type field. Returns TRUE if it is acceptable, FALSE otherwise.
625: */
626: int
627: tar_path(str, len)
628: char *str;
629: int len;
630: {
631: for (; len > 0; --len, ++str) {
632: if (*str != '\0' && *str != ' ' &&
633: !isprint(*str)) {
634: break;
635: }
636: }
637:
638: return(0 == len);
639: } /* tar_path() */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.