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*50870Skarels static char sccsid[] = "@(#)file.c 4.21 (Berkeley) 08/20/91"; 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 29*50870Skarels #if defined(hp300) || defined(hp800) 30*50870Skarels #include <hp300/hpux/hpux_exec.h> 31*50870Skarels #endif 3232251Sbostic 33*50870Skarels extern int errno; 34613Sbill int in; 35613Sbill int i = 0; 36613Sbill char buf[BUFSIZ]; 37613Sbill char *troff[] = { /* new troff intermediate lang */ 38613Sbill "x","T","res","init","font","202","V0","p1",0}; 39613Sbill char *fort[] = { 40613Sbill "function","subroutine","common","dimension","block","integer", 41613Sbill "real","data","double",0}; 42613Sbill char *asc[] = { 43613Sbill "chmk","mov","tst","clr","jmp",0}; 44613Sbill char *c[] = { 45613Sbill "int","char","float","double","struct","extern",0}; 46613Sbill char *as[] = { 47613Sbill "globl","byte","align","text","data","comm",0}; 4820852Ssam char *sh[] = { 4920852Ssam "fi", "elif", "esac", "done", "export", 5020852Ssam "readonly", "trap", "PATH", "HOME", 0 }; 5120852Ssam char *csh[] = { 5220852Ssam "alias", "breaksw", "endsw", "foreach", "limit", "onintr", 5320852Ssam "repeat", "setenv", "source", "path", "home", 0 }; 54613Sbill int ifile; 55613Sbill 56613Sbill main(argc, argv) 57613Sbill char **argv; 58613Sbill { 59613Sbill FILE *fl; 60613Sbill register char *p; 6117963Sserge char ap[MAXPATHLEN + 1]; 62613Sbill 6317963Sserge if (argc < 2) { 6417963Sserge fprintf(stderr, "usage: %s file ...\n", argv[0]); 6517963Sserge exit(3); 6617963Sserge } 6717963Sserge 68613Sbill if (argc>1 && argv[1][0]=='-' && argv[1][1]=='f') { 69613Sbill if ((fl = fopen(argv[2], "r")) == NULL) { 7012101Smckusick perror(argv[2]); 71613Sbill exit(2); 72613Sbill } 7317963Sserge while ((p = fgets(ap, sizeof ap, fl)) != NULL) { 74613Sbill int l = strlen(p); 75613Sbill if (l>0) 76613Sbill p[l-1] = '\0'; 77613Sbill type(p); 78613Sbill if (ifile>=0) 79613Sbill close(ifile); 80613Sbill } 81613Sbill exit(1); 82613Sbill } 83613Sbill while(argc > 1) { 8447028Sbostic ifile = -1; 85613Sbill type(argv[1]); 86613Sbill fflush(stdout); 87613Sbill argc--; 88613Sbill argv++; 89613Sbill if (ifile >= 0) 90613Sbill close(ifile); 91613Sbill } 9217963Sserge exit(0); 93613Sbill } 94613Sbill 95613Sbill type(file) 96613Sbill char *file; 97613Sbill { 98613Sbill int j,nl; 99613Sbill char ch; 100613Sbill struct stat mbuf; 10117963Sserge char slink[MAXPATHLEN + 1]; 102*50870Skarels struct exec *hdr; 103*50870Skarels #if defined(hp300) || defined(hp800) 104*50870Skarels int ishpux300 = 0; 105*50870Skarels int ishpux800 = 0; 106*50870Skarels #endif 107613Sbill 1086719Smckusick if (lstat(file, &mbuf) < 0) { 10942419Sbostic fprintf(stderr, "file: %s: %s\n", file, strerror(errno)); 110613Sbill return; 111613Sbill } 112613Sbill switch (mbuf.st_mode & S_IFMT) { 1136719Smckusick case S_IFLNK: 11447869Skarels printf("%s:\tsymbolic link", file); 11517963Sserge j = readlink(file, slink, sizeof slink - 1); 11617963Sserge if (j >= 0) { 11717963Sserge slink[j] = '\0'; 11817963Sserge printf(" to %s", slink); 11917963Sserge } 12017963Sserge printf("\n"); 1216719Smckusick return; 1226719Smckusick 123613Sbill case S_IFDIR: 12447869Skarels printf("%s:\t", file); 12517963Sserge if (mbuf.st_mode & S_ISVTX) 12617963Sserge printf("append-only "); 127613Sbill printf("directory\n"); 128613Sbill return; 129613Sbill 13017963Sserge case S_IFCHR: 131613Sbill case S_IFBLK: 13247869Skarels printf("%s:\t%s special (%d/%d)\n", file, 13325499Ssam (mbuf.st_mode&S_IFMT) == S_IFCHR ? "character" : "block", 13425499Ssam major(mbuf.st_rdev), minor(mbuf.st_rdev)); 13517963Sserge return; 136613Sbill 13717963Sserge case S_IFSOCK: 13847869Skarels printf("%s:\tsocket\n", file); 139613Sbill return; 140613Sbill } 141613Sbill 142613Sbill ifile = open(file, 0); 143*50870Skarels if (ifile < 0) { 14442419Sbostic fprintf(stderr, "file: %s: %s\n", file, strerror(errno)); 145613Sbill return; 146613Sbill } 14747869Skarels printf("%s:\t", file); 148613Sbill in = read(ifile, buf, BUFSIZ); 149*50870Skarels if (in == 0) { 150613Sbill printf("empty\n"); 151613Sbill return; 152613Sbill } 153*50870Skarels hdr = (struct exec *) buf; 154*50870Skarels #ifdef MID_ZERO /* if we have a_mid field */ 155*50870Skarels switch (hdr->a_mid) { 156*50870Skarels case MID_SUN010: 157*50870Skarels printf("SUN 68010/68020 "); 158*50870Skarels break; 159*50870Skarels case MID_SUN020: 160*50870Skarels printf("SUN 68020 "); 161*50870Skarels break; 162*50870Skarels case MID_HP200: 163*50870Skarels printf("HP200 "); 164*50870Skarels break; 165*50870Skarels case MID_HP300: 166*50870Skarels printf("HP300 "); 167*50870Skarels break; 168*50870Skarels #if defined(hp300) || defined(hp800) 169*50870Skarels case MID_HPUX: 170*50870Skarels if (((struct hpux_exec *)buf)->ha_version == BSDVNUM) 171*50870Skarels printf("BSD generated "); 172*50870Skarels printf("HP-UX series 200/300 "); 173*50870Skarels ishpux300 = 1; 174*50870Skarels if (hdr->a_magic == 0406) { 175*50870Skarels printf("relocatable object\n"); 176*50870Skarels return; 177*50870Skarels } 178*50870Skarels break; 179*50870Skarels case MID_HPUX800: 180*50870Skarels printf("HP-UX series 800 "); 181*50870Skarels ishpux800 = 1; 182*50870Skarels if (hdr->a_magic == 0x106) { 183*50870Skarels printf("relocatable object\n"); 184*50870Skarels return; 185*50870Skarels } 186*50870Skarels break; 187*50870Skarels #endif 188*50870Skarels #if BYTE_ORDER == BIG_ENDIAN 189*50870Skarels case ((OMAGIC & 0xff) << 8) | (OMAGIC >> 8): 190*50870Skarels case ((NMAGIC & 0xff) << 8) | (NMAGIC >> 8): 191*50870Skarels case ((ZMAGIC & 0xff) << 8) | (ZMAGIC >> 8): 192*50870Skarels printf("byte-swapped (VAX/386) "); 193*50870Skarels hdr->a_magic = ((hdr->a_mid & 0xff) << 8) | (hdr->a_mid >> 8); 194*50870Skarels break; 195*50870Skarels } 196*50870Skarels #endif 197*50870Skarels #endif /* MID_ZERO, a_mid */ 198*50870Skarels switch (hdr->a_magic) { 199613Sbill 200*50870Skarels case 0411: 201*50870Skarels printf("jfr or pdp-11 unix 411 executable\n"); 202*50870Skarels return; 203*50870Skarels 204*50870Skarels case ZMAGIC: 205613Sbill printf("demand paged "); 206*50870Skarels /* FALLTHROUGH */ 207613Sbill 208*50870Skarels case NMAGIC: 209613Sbill printf("pure "); 210*50870Skarels /* FALLTHROUGH */ 211613Sbill 212*50870Skarels case OMAGIC: 21317963Sserge if (mbuf.st_mode & S_ISUID) 21417963Sserge printf("set-uid "); 21517963Sserge if (mbuf.st_mode & S_ISGID) 21617963Sserge printf("set-gid "); 21717963Sserge if (mbuf.st_mode & S_ISVTX) 21817963Sserge printf("sticky "); 219*50870Skarels if ((mbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 && 220*50870Skarels (hdr->a_trsize || hdr->a_drsize)) { 221*50870Skarels printf("relocatable object\n"); 222*50870Skarels return; 223*50870Skarels } 224613Sbill printf("executable"); 225*50870Skarels #if defined(hp300) || defined(hp800) 226*50870Skarels if (ishpux300) { 227*50870Skarels if (((int *)buf)[9] != 0) 228*50870Skarels printf(" not stripped"); 229*50870Skarels } else if (ishpux800) { 230*50870Skarels if (((int *)buf)[24] != 0) 231*50870Skarels printf(" not stripped"); 232*50870Skarels } else 233*50870Skarels #endif 234*50870Skarels if (hdr->a_syms != 0) 235613Sbill printf(" not stripped"); 236613Sbill printf("\n"); 23720852Ssam return; 238*50870Skarels } 239613Sbill 240*50870Skarels switch (*(int *)buf) { 241613Sbill case 0177555: 242613Sbill printf("very old archive\n"); 24320852Ssam return; 244613Sbill 245613Sbill case 0177545: 246613Sbill printf("old archive\n"); 24720852Ssam return; 248897Sbill 249897Sbill case 070707: 250897Sbill printf("cpio data\n"); 25120852Ssam return; 252613Sbill } 253613Sbill 25420852Ssam if (buf[0] == '#' && buf[1] == '!' && shellscript(buf+2, &mbuf)) 25520852Ssam return; 25624666Sserge if (buf[0] == '\037' && buf[1] == '\235') { 25724666Sserge if (buf[2]&0x80) 25824666Sserge printf("block "); 25924666Sserge printf("compressed %d bit code data\n", buf[2]&0x1f); 26024666Sserge return; 26124666Sserge } 262*50870Skarels if (strncmp(buf, "!<arch>\n__.SYMDEF", 17) == 0 ) { 263613Sbill printf("archive random library\n"); 26420852Ssam return; 265613Sbill } 266613Sbill if (strncmp(buf, "!<arch>\n", 8)==0) { 267613Sbill printf("archive\n"); 26820852Ssam return; 269613Sbill } 2705900Sroot if (mbuf.st_size % 512 == 0) { /* it may be a PRESS file */ 2715900Sroot lseek(ifile, -512L, 2); /* last block */ 27220852Ssam if (read(ifile, buf, BUFSIZ) > 0 && *(short *)buf == 12138) { 2735900Sroot printf("PRESS file\n"); 27420852Ssam return; 2755900Sroot } 2765900Sroot } 277613Sbill i = 0; 278613Sbill if(ccom() == 0)goto notc; 279613Sbill while(buf[i] == '#'){ 280613Sbill j = i; 281613Sbill while(buf[i++] != '\n'){ 282613Sbill if(i - j > 255){ 283613Sbill printf("data\n"); 28420852Ssam return; 285613Sbill } 286613Sbill if(i >= in)goto notc; 287613Sbill } 288613Sbill if(ccom() == 0)goto notc; 289613Sbill } 290613Sbill check: 291613Sbill if(lookup(c) == 1){ 292613Sbill while((ch = buf[i++]) != ';' && ch != '{')if(i >= in)goto notc; 293613Sbill printf("c program text"); 294613Sbill goto outa; 295613Sbill } 296613Sbill nl = 0; 297613Sbill while(buf[i] != '('){ 298613Sbill if(buf[i] <= 0) 299613Sbill goto notas; 300613Sbill if(buf[i] == ';'){ 301613Sbill i++; 302613Sbill goto check; 303613Sbill } 304613Sbill if(buf[i++] == '\n') 305613Sbill if(nl++ > 6)goto notc; 306613Sbill if(i >= in)goto notc; 307613Sbill } 308613Sbill while(buf[i] != ')'){ 309613Sbill if(buf[i++] == '\n') 310613Sbill if(nl++ > 6)goto notc; 311613Sbill if(i >= in)goto notc; 312613Sbill } 313613Sbill while(buf[i] != '{'){ 314613Sbill if(buf[i++] == '\n') 315613Sbill if(nl++ > 6)goto notc; 316613Sbill if(i >= in)goto notc; 317613Sbill } 318613Sbill printf("c program text"); 319613Sbill goto outa; 320613Sbill notc: 321613Sbill i = 0; 322613Sbill while(buf[i] == 'c' || buf[i] == '#'){ 323613Sbill while(buf[i++] != '\n')if(i >= in)goto notfort; 324613Sbill } 325613Sbill if(lookup(fort) == 1){ 326613Sbill printf("fortran program text"); 327613Sbill goto outa; 328613Sbill } 329613Sbill notfort: 330613Sbill i=0; 331613Sbill if(ascom() == 0)goto notas; 332613Sbill j = i-1; 333613Sbill if(buf[i] == '.'){ 334613Sbill i++; 335613Sbill if(lookup(as) == 1){ 336613Sbill printf("assembler program text"); 337613Sbill goto outa; 338613Sbill } 339613Sbill else if(buf[j] == '\n' && isalpha(buf[j+2])){ 340613Sbill printf("roff, nroff, or eqn input text"); 341613Sbill goto outa; 342613Sbill } 343613Sbill } 344613Sbill while(lookup(asc) == 0){ 345613Sbill if(ascom() == 0)goto notas; 346613Sbill while(buf[i] != '\n' && buf[i++] != ':') 347613Sbill if(i >= in)goto notas; 348613Sbill while(buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\t')if(i++ >= in)goto notas; 349613Sbill j = i-1; 350613Sbill if(buf[i] == '.'){ 351613Sbill i++; 352613Sbill if(lookup(as) == 1){ 353613Sbill printf("assembler program text"); 354613Sbill goto outa; 355613Sbill } 356613Sbill else if(buf[j] == '\n' && isalpha(buf[j+2])){ 357613Sbill printf("roff, nroff, or eqn input text"); 358613Sbill goto outa; 359613Sbill } 360613Sbill } 361613Sbill } 362613Sbill printf("assembler program text"); 363613Sbill goto outa; 364613Sbill notas: 365613Sbill for(i=0; i < in; i++)if(buf[i]&0200){ 36620852Ssam if (buf[0]=='\100' && buf[1]=='\357') 367613Sbill printf("troff (CAT) output\n"); 36820852Ssam else 36920852Ssam printf("data\n"); 37020852Ssam return; 371613Sbill } 37217963Sserge if (mbuf.st_mode&((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6))) { 37317963Sserge if (mbuf.st_mode & S_ISUID) 37417963Sserge printf("set-uid "); 37517963Sserge if (mbuf.st_mode & S_ISGID) 37617963Sserge printf("set-gid "); 37717963Sserge if (mbuf.st_mode & S_ISVTX) 37817963Sserge printf("sticky "); 37920852Ssam if (shell(buf, in, sh)) 38020852Ssam printf("shell script"); 38120852Ssam else if (shell(buf, in, csh)) 38220852Ssam printf("c-shell script"); 38320852Ssam else 38420852Ssam printf("commands text"); 38517963Sserge } else if (troffint(buf, in)) 386613Sbill printf("troff intermediate output text"); 38720852Ssam else if (shell(buf, in, sh)) 38820852Ssam printf("shell commands"); 38920852Ssam else if (shell(buf, in, csh)) 39020852Ssam printf("c-shell commands"); 391613Sbill else if (english(buf, in)) 392613Sbill printf("English text"); 393613Sbill else 394613Sbill printf("ascii text"); 395613Sbill outa: 396613Sbill while(i < in) 397613Sbill if((buf[i++]&0377) > 127){ 398613Sbill printf(" with garbage\n"); 39920852Ssam return; 400613Sbill } 401613Sbill /* if next few lines in then read whole file looking for nulls ... 402613Sbill while((in = read(ifile,buf,BUFSIZ)) > 0) 403613Sbill for(i = 0; i < in; i++) 404613Sbill if((buf[i]&0377) > 127){ 405613Sbill printf(" with garbage\n"); 40620852Ssam return; 407613Sbill } 408613Sbill /*.... */ 409613Sbill printf("\n"); 410613Sbill } 411613Sbill 412613Sbill troffint(bp, n) 413613Sbill char *bp; 414613Sbill int n; 415613Sbill { 416613Sbill int k; 417613Sbill 418613Sbill i = 0; 419613Sbill for (k = 0; k < 6; k++) { 420613Sbill if (lookup(troff) == 0) 421613Sbill return(0); 422613Sbill if (lookup(troff) == 0) 423613Sbill return(0); 424613Sbill while (i < n && buf[i] != '\n') 425613Sbill i++; 426613Sbill if (i++ >= n) 427613Sbill return(0); 428613Sbill } 429613Sbill return(1); 430613Sbill } 431613Sbill lookup(tab) 432613Sbill char *tab[]; 433613Sbill { 434613Sbill char r; 435613Sbill int k,j,l; 436613Sbill while(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n')i++; 437613Sbill for(j=0; tab[j] != 0; j++){ 438613Sbill l=0; 439613Sbill for(k=i; ((r=tab[j][l++]) == buf[k] && r != '\0');k++); 440613Sbill if(r == '\0') 441613Sbill if(buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\t' 442613Sbill || buf[k] == '{' || buf[k] == '/'){ 443613Sbill i=k; 444613Sbill return(1); 445613Sbill } 446613Sbill } 447613Sbill return(0); 448613Sbill } 449613Sbill ccom(){ 450613Sbill char cc; 451613Sbill while((cc = buf[i]) == ' ' || cc == '\t' || cc == '\n')if(i++ >= in)return(0); 452613Sbill if(buf[i] == '/' && buf[i+1] == '*'){ 453613Sbill i += 2; 454613Sbill while(buf[i] != '*' || buf[i+1] != '/'){ 455613Sbill if(buf[i] == '\\')i += 2; 456613Sbill else i++; 457613Sbill if(i >= in)return(0); 458613Sbill } 459613Sbill if((i += 2) >= in)return(0); 460613Sbill } 461613Sbill if(buf[i] == '\n')if(ccom() == 0)return(0); 462613Sbill return(1); 463613Sbill } 464613Sbill ascom(){ 465613Sbill while(buf[i] == '/'){ 466613Sbill i++; 467613Sbill while(buf[i++] != '\n')if(i >= in)return(0); 468613Sbill while(buf[i] == '\n')if(i++ >= in)return(0); 469613Sbill } 470613Sbill return(1); 471613Sbill } 472613Sbill 473613Sbill english (bp, n) 474613Sbill char *bp; 475613Sbill { 476613Sbill # define NASC 128 477613Sbill int ct[NASC], j, vow, freq, rare; 478613Sbill int badpun = 0, punct = 0; 479613Sbill if (n<50) return(0); /* no point in statistics on squibs */ 480613Sbill for(j=0; j<NASC; j++) 481613Sbill ct[j]=0; 482613Sbill for(j=0; j<n; j++) 483613Sbill { 48434099Sbostic if ((u_char)bp[j]<NASC) 485613Sbill ct[bp[j]|040]++; 486613Sbill switch (bp[j]) 487613Sbill { 488613Sbill case '.': 489613Sbill case ',': 490613Sbill case ')': 491613Sbill case '%': 492613Sbill case ';': 493613Sbill case ':': 494613Sbill case '?': 495613Sbill punct++; 496613Sbill if ( j < n-1 && 497613Sbill bp[j+1] != ' ' && 498613Sbill bp[j+1] != '\n') 499613Sbill badpun++; 500613Sbill } 501613Sbill } 502613Sbill if (badpun*5 > punct) 503613Sbill return(0); 504613Sbill vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 505613Sbill freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 506613Sbill rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 507613Sbill if (2*ct[';'] > ct['e']) return(0); 508613Sbill if ( (ct['>']+ct['<']+ct['/'])>ct['e']) return(0); /* shell file test */ 509613Sbill return (vow*5 >= n-ct[' '] && freq >= 10*rare); 510613Sbill } 51120852Ssam 51220852Ssam shellscript(buf, sb) 51320852Ssam char buf[]; 51420852Ssam struct stat *sb; 51520852Ssam { 51620852Ssam register char *tp; 51720852Ssam char *cp, *xp, *index(); 51820852Ssam 51920852Ssam cp = index(buf, '\n'); 52020852Ssam if (cp == 0 || cp - buf > in) 52120852Ssam return (0); 52220852Ssam for (tp = buf; tp != cp && isspace(*tp); tp++) 52320852Ssam if (!isascii(*tp)) 52420852Ssam return (0); 52520852Ssam for (xp = tp; tp != cp && !isspace(*tp); tp++) 52620852Ssam if (!isascii(*tp)) 52720852Ssam return (0); 52820852Ssam if (tp == xp) 52920852Ssam return (0); 53020852Ssam if (sb->st_mode & S_ISUID) 53120852Ssam printf("set-uid "); 53220852Ssam if (sb->st_mode & S_ISGID) 53320852Ssam printf("set-gid "); 53420852Ssam if (strncmp(xp, "/bin/sh", tp-xp) == 0) 53520852Ssam xp = "shell"; 53620852Ssam else if (strncmp(xp, "/bin/csh", tp-xp) == 0) 53720852Ssam xp = "c-shell"; 53820852Ssam else 53920852Ssam *tp = '\0'; 54020852Ssam printf("executable %s script\n", xp); 54120852Ssam return (1); 54220852Ssam } 54320852Ssam 54420852Ssam shell(bp, n, tab) 54520852Ssam char *bp; 54620852Ssam int n; 54720852Ssam char *tab[]; 54820852Ssam { 54920852Ssam 55020852Ssam i = 0; 55120852Ssam do { 55220852Ssam if (buf[i] == '#' || buf[i] == ':') 55320852Ssam while (i < n && buf[i] != '\n') 55420852Ssam i++; 55520852Ssam if (++i >= n) 55620852Ssam break; 55720852Ssam if (lookup(tab) == 1) 55820852Ssam return (1); 55920852Ssam } while (i < n); 56020852Ssam return (0); 56120852Ssam } 562