Annotation of coherent/d/bin/file.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.