148260Sbostic /*- 248260Sbostic * Copyright (c) 1991 The Regents of the University of California. 348260Sbostic * All rights reserved. 448260Sbostic * 548260Sbostic * %sccs.include.proprietary.c% 648260Sbostic */ 748260Sbostic 812673Ssam #ifndef lint 948260Sbostic char copyright[] = 1048260Sbostic "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 1148260Sbostic All rights reserved.\n"; 1248260Sbostic #endif /* not lint */ 1348260Sbostic 1448260Sbostic #ifndef lint 15*60104Selan static char sccsid[] = "@(#)file.c 5.4 (Berkeley) 05/17/93"; 1648260Sbostic #endif /* not lint */ 1748260Sbostic 18613Sbill /* 19613Sbill * file - determine type of file 20613Sbill */ 21613Sbill 2217963Sserge #include <sys/param.h> 2313755Ssam #include <sys/stat.h> 2442419Sbostic #include <string.h> 25613Sbill #include <stdio.h> 26613Sbill #include <ctype.h> 27904Sbill #include <a.out.h> 2832251Sbostic 2950870Skarels #if defined(hp300) || defined(hp800) 3054024Sbostic #include <hp/hpux/hpux_exec.h> 3150870Skarels #endif 3232251Sbostic 3350870Skarels extern int errno; 34613Sbill int in; 35613Sbill int i = 0; 36*60104Selan 37*60104Selan #define BUFSIZE 4096 38*60104Selan 39*60104Selan char buf[BUFSIZE]; 40613Sbill char *troff[] = { /* new troff intermediate lang */ 41613Sbill "x","T","res","init","font","202","V0","p1",0}; 42613Sbill char *fort[] = { 43613Sbill "function","subroutine","common","dimension","block","integer", 44613Sbill "real","data","double",0}; 45613Sbill char *asc[] = { 46613Sbill "chmk","mov","tst","clr","jmp",0}; 47613Sbill char *c[] = { 48613Sbill "int","char","float","double","struct","extern",0}; 49613Sbill char *as[] = { 50613Sbill "globl","byte","align","text","data","comm",0}; 5120852Ssam char *sh[] = { 5220852Ssam "fi", "elif", "esac", "done", "export", 5320852Ssam "readonly", "trap", "PATH", "HOME", 0 }; 5420852Ssam char *csh[] = { 5520852Ssam "alias", "breaksw", "endsw", "foreach", "limit", "onintr", 5620852Ssam "repeat", "setenv", "source", "path", "home", 0 }; 57613Sbill int ifile; 58613Sbill 59613Sbill main(argc, argv) 60613Sbill char **argv; 61613Sbill { 62613Sbill FILE *fl; 63613Sbill register char *p; 6417963Sserge char ap[MAXPATHLEN + 1]; 65613Sbill 6617963Sserge if (argc < 2) { 6717963Sserge fprintf(stderr, "usage: %s file ...\n", argv[0]); 6817963Sserge exit(3); 6917963Sserge } 7017963Sserge 71613Sbill if (argc>1 && argv[1][0]=='-' && argv[1][1]=='f') { 72613Sbill if ((fl = fopen(argv[2], "r")) == NULL) { 7312101Smckusick perror(argv[2]); 74613Sbill exit(2); 75613Sbill } 7617963Sserge while ((p = fgets(ap, sizeof ap, fl)) != NULL) { 77613Sbill int l = strlen(p); 78613Sbill if (l>0) 79613Sbill p[l-1] = '\0'; 80613Sbill type(p); 81613Sbill if (ifile>=0) 82613Sbill close(ifile); 83613Sbill } 84613Sbill exit(1); 85613Sbill } 86613Sbill while(argc > 1) { 8747028Sbostic ifile = -1; 88613Sbill type(argv[1]); 89613Sbill fflush(stdout); 90613Sbill argc--; 91613Sbill argv++; 92613Sbill if (ifile >= 0) 93613Sbill close(ifile); 94613Sbill } 9517963Sserge exit(0); 96613Sbill } 97613Sbill 98613Sbill type(file) 99613Sbill char *file; 100613Sbill { 101613Sbill int j,nl; 102613Sbill char ch; 103613Sbill struct stat mbuf; 10417963Sserge char slink[MAXPATHLEN + 1]; 10550870Skarels struct exec *hdr; 10650870Skarels #if defined(hp300) || defined(hp800) 10750870Skarels int ishpux300 = 0; 10850870Skarels int ishpux800 = 0; 10950870Skarels #endif 110613Sbill 1116719Smckusick if (lstat(file, &mbuf) < 0) { 11242419Sbostic fprintf(stderr, "file: %s: %s\n", file, strerror(errno)); 113613Sbill return; 114613Sbill } 115613Sbill switch (mbuf.st_mode & S_IFMT) { 1166719Smckusick case S_IFLNK: 11747869Skarels printf("%s:\tsymbolic link", file); 11817963Sserge j = readlink(file, slink, sizeof slink - 1); 11917963Sserge if (j >= 0) { 12017963Sserge slink[j] = '\0'; 12117963Sserge printf(" to %s", slink); 12217963Sserge } 12317963Sserge printf("\n"); 1246719Smckusick return; 1256719Smckusick 126613Sbill case S_IFDIR: 12747869Skarels printf("%s:\t", file); 12817963Sserge if (mbuf.st_mode & S_ISVTX) 12917963Sserge printf("append-only "); 130613Sbill printf("directory\n"); 131613Sbill return; 132613Sbill 13317963Sserge case S_IFCHR: 134613Sbill case S_IFBLK: 13547869Skarels printf("%s:\t%s special (%d/%d)\n", file, 13625499Ssam (mbuf.st_mode&S_IFMT) == S_IFCHR ? "character" : "block", 13725499Ssam major(mbuf.st_rdev), minor(mbuf.st_rdev)); 13817963Sserge return; 139613Sbill 14017963Sserge case S_IFSOCK: 14147869Skarels printf("%s:\tsocket\n", file); 142613Sbill return; 143613Sbill } 144613Sbill 145613Sbill ifile = open(file, 0); 14650870Skarels if (ifile < 0) { 14742419Sbostic fprintf(stderr, "file: %s: %s\n", file, strerror(errno)); 148613Sbill return; 149613Sbill } 15047869Skarels printf("%s:\t", file); 151*60104Selan in = read(ifile, buf, BUFSIZE); 15250870Skarels if (in == 0) { 153613Sbill printf("empty\n"); 154613Sbill return; 155613Sbill } 15650870Skarels hdr = (struct exec *) buf; 15750870Skarels #ifdef MID_ZERO /* if we have a_mid field */ 15850870Skarels switch (hdr->a_mid) { 15950870Skarels case MID_SUN010: 16050870Skarels printf("SUN 68010/68020 "); 16150870Skarels break; 16250870Skarels case MID_SUN020: 16350870Skarels printf("SUN 68020 "); 16450870Skarels break; 16550870Skarels case MID_HP200: 16650870Skarels printf("HP200 "); 16750870Skarels break; 16850870Skarels case MID_HP300: 16950870Skarels printf("HP300 "); 17050870Skarels break; 17150870Skarels #if defined(hp300) || defined(hp800) 17250870Skarels case MID_HPUX: 17357473Shibler printf("HP-UX series [234]00 "); 17450870Skarels ishpux300 = 1; 17550870Skarels if (hdr->a_magic == 0406) { 17650870Skarels printf("relocatable object\n"); 17750870Skarels return; 17850870Skarels } 17950870Skarels break; 18050870Skarels case MID_HPUX800: 18150870Skarels printf("HP-UX series 800 "); 18250870Skarels ishpux800 = 1; 18350870Skarels if (hdr->a_magic == 0x106) { 18450870Skarels printf("relocatable object\n"); 18550870Skarels return; 18650870Skarels } 18750870Skarels break; 18850870Skarels #endif 18958575Sralph #ifdef MID_MIPSI 19058575Sralph case MID_MIPSI: 19158575Sralph printf("MIPS R3000 "); 19258575Sralph break; 19358575Sralph #endif 19458575Sralph #ifdef MID_MIPSII 19558575Sralph case MID_MIPSII: 19658575Sralph printf("MIPS R4000 "); 19758575Sralph break; 19858575Sralph #endif 19950870Skarels #if BYTE_ORDER == BIG_ENDIAN 20050870Skarels case ((OMAGIC & 0xff) << 8) | (OMAGIC >> 8): 20150870Skarels case ((NMAGIC & 0xff) << 8) | (NMAGIC >> 8): 20250870Skarels case ((ZMAGIC & 0xff) << 8) | (ZMAGIC >> 8): 20350870Skarels printf("byte-swapped (VAX/386) "); 20450870Skarels hdr->a_magic = ((hdr->a_mid & 0xff) << 8) | (hdr->a_mid >> 8); 20550870Skarels break; 20658575Sralph #endif 20750870Skarels } 20850870Skarels #endif /* MID_ZERO, a_mid */ 20950870Skarels switch (hdr->a_magic) { 210613Sbill 21150870Skarels case 0411: 21250870Skarels printf("jfr or pdp-11 unix 411 executable\n"); 21350870Skarels return; 21450870Skarels 21550870Skarels case ZMAGIC: 216613Sbill printf("demand paged "); 21750870Skarels /* FALLTHROUGH */ 218613Sbill 21950870Skarels case NMAGIC: 220613Sbill printf("pure "); 22150870Skarels /* FALLTHROUGH */ 222613Sbill 22350870Skarels case OMAGIC: 22417963Sserge if (mbuf.st_mode & S_ISUID) 22517963Sserge printf("set-uid "); 22617963Sserge if (mbuf.st_mode & S_ISGID) 22717963Sserge printf("set-gid "); 22817963Sserge if (mbuf.st_mode & S_ISVTX) 22917963Sserge printf("sticky "); 23050870Skarels if ((mbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 && 23150870Skarels (hdr->a_trsize || hdr->a_drsize)) { 23250870Skarels printf("relocatable object\n"); 23350870Skarels return; 23450870Skarels } 23557473Shibler #if defined(hp300) 23657473Shibler if (ishpux300) { 23757473Shibler if (((int *)buf)[2] & 0x40000000) 23857473Shibler printf("dynamically-linked "); 23957473Shibler } 24057473Shibler #endif 241613Sbill printf("executable"); 24250870Skarels #if defined(hp300) || defined(hp800) 24350870Skarels if (ishpux300) { 24450870Skarels if (((int *)buf)[9] != 0) 24550870Skarels printf(" not stripped"); 24650870Skarels } else if (ishpux800) { 24750870Skarels if (((int *)buf)[24] != 0) 24850870Skarels printf(" not stripped"); 24950870Skarels } else 25050870Skarels #endif 25150870Skarels if (hdr->a_syms != 0) 252613Sbill printf(" not stripped"); 253613Sbill printf("\n"); 25420852Ssam return; 25557473Shibler #if defined(hp300) 25657473Shibler case 0x10e: 25757473Shibler printf("shared library, version %d\n", ((short *)buf)[2]); 25857473Shibler return; 25957473Shibler #endif 26050870Skarels } 261613Sbill 26250870Skarels switch (*(int *)buf) { 263613Sbill case 0177555: 264613Sbill printf("very old archive\n"); 26520852Ssam return; 266613Sbill 267613Sbill case 0177545: 268613Sbill printf("old archive\n"); 26920852Ssam return; 270897Sbill 271897Sbill case 070707: 272897Sbill printf("cpio data\n"); 27320852Ssam return; 274613Sbill } 275613Sbill 27620852Ssam if (buf[0] == '#' && buf[1] == '!' && shellscript(buf+2, &mbuf)) 27720852Ssam return; 27824666Sserge if (buf[0] == '\037' && buf[1] == '\235') { 27924666Sserge if (buf[2]&0x80) 28024666Sserge printf("block "); 28124666Sserge printf("compressed %d bit code data\n", buf[2]&0x1f); 28224666Sserge return; 28324666Sserge } 28450870Skarels if (strncmp(buf, "!<arch>\n__.SYMDEF", 17) == 0 ) { 285613Sbill printf("archive random library\n"); 28620852Ssam return; 287613Sbill } 288613Sbill if (strncmp(buf, "!<arch>\n", 8)==0) { 289613Sbill printf("archive\n"); 29020852Ssam return; 291613Sbill } 2925900Sroot if (mbuf.st_size % 512 == 0) { /* it may be a PRESS file */ 2935900Sroot lseek(ifile, -512L, 2); /* last block */ 294*60104Selan if (read(ifile, buf, BUFSIZE) > 0 && *(short *)buf == 12138) { 2955900Sroot printf("PRESS file\n"); 29620852Ssam return; 2975900Sroot } 2985900Sroot } 299613Sbill i = 0; 300613Sbill if(ccom() == 0)goto notc; 301613Sbill while(buf[i] == '#'){ 302613Sbill j = i; 303613Sbill while(buf[i++] != '\n'){ 304613Sbill if(i - j > 255){ 305613Sbill printf("data\n"); 30620852Ssam return; 307613Sbill } 308613Sbill if(i >= in)goto notc; 309613Sbill } 310613Sbill if(ccom() == 0)goto notc; 311613Sbill } 312613Sbill check: 313613Sbill if(lookup(c) == 1){ 314613Sbill while((ch = buf[i++]) != ';' && ch != '{')if(i >= in)goto notc; 315613Sbill printf("c program text"); 316613Sbill goto outa; 317613Sbill } 318613Sbill nl = 0; 319613Sbill while(buf[i] != '('){ 320613Sbill if(buf[i] <= 0) 321613Sbill goto notas; 322613Sbill if(buf[i] == ';'){ 323613Sbill i++; 324613Sbill goto check; 325613Sbill } 326613Sbill if(buf[i++] == '\n') 327613Sbill if(nl++ > 6)goto notc; 328613Sbill if(i >= in)goto notc; 329613Sbill } 330613Sbill while(buf[i] != ')'){ 331613Sbill if(buf[i++] == '\n') 332613Sbill if(nl++ > 6)goto notc; 333613Sbill if(i >= in)goto notc; 334613Sbill } 335613Sbill while(buf[i] != '{'){ 336613Sbill if(buf[i++] == '\n') 337613Sbill if(nl++ > 6)goto notc; 338613Sbill if(i >= in)goto notc; 339613Sbill } 340613Sbill printf("c program text"); 341613Sbill goto outa; 342613Sbill notc: 343613Sbill i = 0; 344613Sbill while(buf[i] == 'c' || buf[i] == '#'){ 345613Sbill while(buf[i++] != '\n')if(i >= in)goto notfort; 346613Sbill } 347613Sbill if(lookup(fort) == 1){ 348613Sbill printf("fortran program text"); 349613Sbill goto outa; 350613Sbill } 351613Sbill notfort: 352613Sbill i=0; 353613Sbill if(ascom() == 0)goto notas; 354613Sbill j = i-1; 355613Sbill if(buf[i] == '.'){ 356613Sbill i++; 357613Sbill if(lookup(as) == 1){ 358613Sbill printf("assembler program text"); 359613Sbill goto outa; 360613Sbill } 361613Sbill else if(buf[j] == '\n' && isalpha(buf[j+2])){ 362613Sbill printf("roff, nroff, or eqn input text"); 363613Sbill goto outa; 364613Sbill } 365613Sbill } 366613Sbill while(lookup(asc) == 0){ 367613Sbill if(ascom() == 0)goto notas; 368613Sbill while(buf[i] != '\n' && buf[i++] != ':') 369613Sbill if(i >= in)goto notas; 370613Sbill while(buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\t')if(i++ >= in)goto notas; 371613Sbill j = i-1; 372613Sbill if(buf[i] == '.'){ 373613Sbill i++; 374613Sbill if(lookup(as) == 1){ 375613Sbill printf("assembler program text"); 376613Sbill goto outa; 377613Sbill } 378613Sbill else if(buf[j] == '\n' && isalpha(buf[j+2])){ 379613Sbill printf("roff, nroff, or eqn input text"); 380613Sbill goto outa; 381613Sbill } 382613Sbill } 383613Sbill } 384613Sbill printf("assembler program text"); 385613Sbill goto outa; 386613Sbill notas: 387613Sbill for(i=0; i < in; i++)if(buf[i]&0200){ 38820852Ssam if (buf[0]=='\100' && buf[1]=='\357') 389613Sbill printf("troff (CAT) output\n"); 39020852Ssam else 39120852Ssam printf("data\n"); 39220852Ssam return; 393613Sbill } 39417963Sserge if (mbuf.st_mode&((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6))) { 39517963Sserge if (mbuf.st_mode & S_ISUID) 39617963Sserge printf("set-uid "); 39717963Sserge if (mbuf.st_mode & S_ISGID) 39817963Sserge printf("set-gid "); 39917963Sserge if (mbuf.st_mode & S_ISVTX) 40017963Sserge printf("sticky "); 40120852Ssam if (shell(buf, in, sh)) 40220852Ssam printf("shell script"); 40320852Ssam else if (shell(buf, in, csh)) 40420852Ssam printf("c-shell script"); 40520852Ssam else 40620852Ssam printf("commands text"); 40717963Sserge } else if (troffint(buf, in)) 408613Sbill printf("troff intermediate output text"); 40920852Ssam else if (shell(buf, in, sh)) 41020852Ssam printf("shell commands"); 41120852Ssam else if (shell(buf, in, csh)) 41220852Ssam printf("c-shell commands"); 413613Sbill else if (english(buf, in)) 414613Sbill printf("English text"); 415613Sbill else 416613Sbill printf("ascii text"); 417613Sbill outa: 418613Sbill while(i < in) 419613Sbill if((buf[i++]&0377) > 127){ 420613Sbill printf(" with garbage\n"); 42120852Ssam return; 422613Sbill } 423613Sbill /* if next few lines in then read whole file looking for nulls ... 424*60104Selan while((in = read(ifile,buf,BUFSIZE)) > 0) 425613Sbill for(i = 0; i < in; i++) 426613Sbill if((buf[i]&0377) > 127){ 427613Sbill printf(" with garbage\n"); 42820852Ssam return; 429613Sbill } 430613Sbill /*.... */ 431613Sbill printf("\n"); 432613Sbill } 433613Sbill 434613Sbill troffint(bp, n) 435613Sbill char *bp; 436613Sbill int n; 437613Sbill { 438613Sbill int k; 439613Sbill 440613Sbill i = 0; 441613Sbill for (k = 0; k < 6; k++) { 442613Sbill if (lookup(troff) == 0) 443613Sbill return(0); 444613Sbill if (lookup(troff) == 0) 445613Sbill return(0); 446613Sbill while (i < n && buf[i] != '\n') 447613Sbill i++; 448613Sbill if (i++ >= n) 449613Sbill return(0); 450613Sbill } 451613Sbill return(1); 452613Sbill } 453613Sbill lookup(tab) 454613Sbill char *tab[]; 455613Sbill { 456613Sbill char r; 457613Sbill int k,j,l; 458613Sbill while(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n')i++; 459613Sbill for(j=0; tab[j] != 0; j++){ 460613Sbill l=0; 461613Sbill for(k=i; ((r=tab[j][l++]) == buf[k] && r != '\0');k++); 462613Sbill if(r == '\0') 463613Sbill if(buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\t' 464613Sbill || buf[k] == '{' || buf[k] == '/'){ 465613Sbill i=k; 466613Sbill return(1); 467613Sbill } 468613Sbill } 469613Sbill return(0); 470613Sbill } 471613Sbill ccom(){ 472613Sbill char cc; 473613Sbill while((cc = buf[i]) == ' ' || cc == '\t' || cc == '\n')if(i++ >= in)return(0); 474613Sbill if(buf[i] == '/' && buf[i+1] == '*'){ 475613Sbill i += 2; 476613Sbill while(buf[i] != '*' || buf[i+1] != '/'){ 477613Sbill if(buf[i] == '\\')i += 2; 478613Sbill else i++; 479613Sbill if(i >= in)return(0); 480613Sbill } 481613Sbill if((i += 2) >= in)return(0); 482613Sbill } 483613Sbill if(buf[i] == '\n')if(ccom() == 0)return(0); 484613Sbill return(1); 485613Sbill } 486613Sbill ascom(){ 487613Sbill while(buf[i] == '/'){ 488613Sbill i++; 489613Sbill while(buf[i++] != '\n')if(i >= in)return(0); 490613Sbill while(buf[i] == '\n')if(i++ >= in)return(0); 491613Sbill } 492613Sbill return(1); 493613Sbill } 494613Sbill 495613Sbill english (bp, n) 496613Sbill char *bp; 497613Sbill { 498613Sbill # define NASC 128 499613Sbill int ct[NASC], j, vow, freq, rare; 500613Sbill int badpun = 0, punct = 0; 501613Sbill if (n<50) return(0); /* no point in statistics on squibs */ 502613Sbill for(j=0; j<NASC; j++) 503613Sbill ct[j]=0; 504613Sbill for(j=0; j<n; j++) 505613Sbill { 50634099Sbostic if ((u_char)bp[j]<NASC) 507613Sbill ct[bp[j]|040]++; 508613Sbill switch (bp[j]) 509613Sbill { 510613Sbill case '.': 511613Sbill case ',': 512613Sbill case ')': 513613Sbill case '%': 514613Sbill case ';': 515613Sbill case ':': 516613Sbill case '?': 517613Sbill punct++; 518613Sbill if ( j < n-1 && 519613Sbill bp[j+1] != ' ' && 520613Sbill bp[j+1] != '\n') 521613Sbill badpun++; 522613Sbill } 523613Sbill } 524613Sbill if (badpun*5 > punct) 525613Sbill return(0); 526613Sbill vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 527613Sbill freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 528613Sbill rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 529613Sbill if (2*ct[';'] > ct['e']) return(0); 530613Sbill if ( (ct['>']+ct['<']+ct['/'])>ct['e']) return(0); /* shell file test */ 531613Sbill return (vow*5 >= n-ct[' '] && freq >= 10*rare); 532613Sbill } 53320852Ssam 53420852Ssam shellscript(buf, sb) 53520852Ssam char buf[]; 53620852Ssam struct stat *sb; 53720852Ssam { 53820852Ssam register char *tp; 53920852Ssam char *cp, *xp, *index(); 54020852Ssam 54120852Ssam cp = index(buf, '\n'); 54220852Ssam if (cp == 0 || cp - buf > in) 54320852Ssam return (0); 54420852Ssam for (tp = buf; tp != cp && isspace(*tp); tp++) 54520852Ssam if (!isascii(*tp)) 54620852Ssam return (0); 54720852Ssam for (xp = tp; tp != cp && !isspace(*tp); tp++) 54820852Ssam if (!isascii(*tp)) 54920852Ssam return (0); 55020852Ssam if (tp == xp) 55120852Ssam return (0); 55220852Ssam if (sb->st_mode & S_ISUID) 55320852Ssam printf("set-uid "); 55420852Ssam if (sb->st_mode & S_ISGID) 55520852Ssam printf("set-gid "); 55620852Ssam if (strncmp(xp, "/bin/sh", tp-xp) == 0) 55720852Ssam xp = "shell"; 55820852Ssam else if (strncmp(xp, "/bin/csh", tp-xp) == 0) 55920852Ssam xp = "c-shell"; 56020852Ssam else 56120852Ssam *tp = '\0'; 56220852Ssam printf("executable %s script\n", xp); 56320852Ssam return (1); 56420852Ssam } 56520852Ssam 56620852Ssam shell(bp, n, tab) 56720852Ssam char *bp; 56820852Ssam int n; 56920852Ssam char *tab[]; 57020852Ssam { 57120852Ssam 57220852Ssam i = 0; 57320852Ssam do { 57420852Ssam if (buf[i] == '#' || buf[i] == ':') 57520852Ssam while (i < n && buf[i] != '\n') 57620852Ssam i++; 57720852Ssam if (++i >= n) 57820852Ssam break; 57920852Ssam if (lookup(tab) == 1) 58020852Ssam return (1); 58120852Ssam } while (i < n); 58220852Ssam return (0); 58320852Ssam } 584