112673Ssam #ifndef lint 2*34099Sbostic static char sccsid[] = "@(#)file.c 4.14 (Berkeley) 04/24/88"; 312673Ssam #endif 4613Sbill /* 5613Sbill * file - determine type of file 6613Sbill */ 7613Sbill 817963Sserge #include <sys/param.h> 913755Ssam #include <sys/stat.h> 10613Sbill #include <stdio.h> 11613Sbill #include <ctype.h> 12904Sbill #include <a.out.h> 1332251Sbostic 1432251Sbostic extern int errno; 1532251Sbostic extern int sys_nerr; 1632251Sbostic extern char *sys_errlist[]; 1732251Sbostic 18613Sbill int in; 19613Sbill int i = 0; 20613Sbill char buf[BUFSIZ]; 21613Sbill char *troff[] = { /* new troff intermediate lang */ 22613Sbill "x","T","res","init","font","202","V0","p1",0}; 23613Sbill char *fort[] = { 24613Sbill "function","subroutine","common","dimension","block","integer", 25613Sbill "real","data","double",0}; 26613Sbill char *asc[] = { 27613Sbill "chmk","mov","tst","clr","jmp",0}; 28613Sbill char *c[] = { 29613Sbill "int","char","float","double","struct","extern",0}; 30613Sbill char *as[] = { 31613Sbill "globl","byte","align","text","data","comm",0}; 3220852Ssam char *sh[] = { 3320852Ssam "fi", "elif", "esac", "done", "export", 3420852Ssam "readonly", "trap", "PATH", "HOME", 0 }; 3520852Ssam char *csh[] = { 3620852Ssam "alias", "breaksw", "endsw", "foreach", "limit", "onintr", 3720852Ssam "repeat", "setenv", "source", "path", "home", 0 }; 38613Sbill int ifile; 39613Sbill 40613Sbill main(argc, argv) 41613Sbill char **argv; 42613Sbill { 43613Sbill FILE *fl; 44613Sbill register char *p; 4517963Sserge char ap[MAXPATHLEN + 1]; 46613Sbill extern char _sobuf[]; 47613Sbill 4817963Sserge if (argc < 2) { 4917963Sserge fprintf(stderr, "usage: %s file ...\n", argv[0]); 5017963Sserge exit(3); 5117963Sserge } 5217963Sserge 53613Sbill if (argc>1 && argv[1][0]=='-' && argv[1][1]=='f') { 54613Sbill if ((fl = fopen(argv[2], "r")) == NULL) { 5512101Smckusick perror(argv[2]); 56613Sbill exit(2); 57613Sbill } 5817963Sserge while ((p = fgets(ap, sizeof ap, fl)) != NULL) { 59613Sbill int l = strlen(p); 60613Sbill if (l>0) 61613Sbill p[l-1] = '\0'; 62613Sbill printf("%s: ", p); 63613Sbill type(p); 64613Sbill if (ifile>=0) 65613Sbill close(ifile); 66613Sbill } 67613Sbill exit(1); 68613Sbill } 69613Sbill while(argc > 1) { 70613Sbill printf("%s: ", argv[1]); 71613Sbill type(argv[1]); 72613Sbill fflush(stdout); 73613Sbill argc--; 74613Sbill argv++; 75613Sbill if (ifile >= 0) 76613Sbill close(ifile); 77613Sbill } 7817963Sserge exit(0); 79613Sbill } 80613Sbill 81613Sbill type(file) 82613Sbill char *file; 83613Sbill { 84613Sbill int j,nl; 85613Sbill char ch; 86613Sbill struct stat mbuf; 8717963Sserge char slink[MAXPATHLEN + 1]; 88613Sbill 89613Sbill ifile = -1; 906719Smckusick if (lstat(file, &mbuf) < 0) { 9117963Sserge printf("%s\n", 9217963Sserge (unsigned)errno < sys_nerr? sys_errlist[errno]: "Cannot stat"); 93613Sbill return; 94613Sbill } 95613Sbill switch (mbuf.st_mode & S_IFMT) { 96613Sbill 976719Smckusick case S_IFLNK: 9817963Sserge printf("symbolic link"); 9917963Sserge j = readlink(file, slink, sizeof slink - 1); 10017963Sserge if (j >= 0) { 10117963Sserge slink[j] = '\0'; 10217963Sserge printf(" to %s", slink); 10317963Sserge } 10417963Sserge printf("\n"); 1056719Smckusick return; 1066719Smckusick 107613Sbill case S_IFDIR: 10817963Sserge if (mbuf.st_mode & S_ISVTX) 10917963Sserge printf("append-only "); 110613Sbill printf("directory\n"); 111613Sbill return; 112613Sbill 11317963Sserge case S_IFCHR: 114613Sbill case S_IFBLK: 11517963Sserge printf("%s special (%d/%d)\n", 11625499Ssam (mbuf.st_mode&S_IFMT) == S_IFCHR ? "character" : "block", 11725499Ssam major(mbuf.st_rdev), minor(mbuf.st_rdev)); 11817963Sserge return; 119613Sbill 12017963Sserge case S_IFSOCK: 12117963Sserge printf("socket\n"); 122613Sbill return; 123613Sbill } 124613Sbill 125613Sbill ifile = open(file, 0); 126613Sbill if(ifile < 0) { 12717963Sserge printf("%s\n", 12817963Sserge (unsigned)errno < sys_nerr? sys_errlist[errno]: "Cannot read"); 129613Sbill return; 130613Sbill } 131613Sbill in = read(ifile, buf, BUFSIZ); 132613Sbill if(in == 0){ 133613Sbill printf("empty\n"); 134613Sbill return; 135613Sbill } 136613Sbill switch(*(int *)buf) { 137613Sbill 138613Sbill case 0413: 139613Sbill printf("demand paged "); 140613Sbill 141613Sbill case 0410: 142613Sbill printf("pure "); 143613Sbill goto exec; 144613Sbill 145613Sbill case 0411: 146613Sbill printf("jfr or pdp-11 unix 411 executable\n"); 147613Sbill return; 148613Sbill 149613Sbill case 0407: 150613Sbill exec: 15117963Sserge if (mbuf.st_mode & S_ISUID) 15217963Sserge printf("set-uid "); 15317963Sserge if (mbuf.st_mode & S_ISGID) 15417963Sserge printf("set-gid "); 15517963Sserge if (mbuf.st_mode & S_ISVTX) 15617963Sserge printf("sticky "); 157613Sbill printf("executable"); 158613Sbill if(((int *)buf)[4] != 0) { 159613Sbill printf(" not stripped"); 160613Sbill if(oldo(buf)) 161613Sbill printf(" (old format symbol table)"); 162613Sbill } 163613Sbill printf("\n"); 16420852Ssam return; 165613Sbill 166613Sbill case 0177555: 167613Sbill printf("very old archive\n"); 16820852Ssam return; 169613Sbill 170613Sbill case 0177545: 171613Sbill printf("old archive\n"); 17220852Ssam return; 173897Sbill 174897Sbill case 070707: 175897Sbill printf("cpio data\n"); 17620852Ssam return; 177613Sbill } 178613Sbill 17920852Ssam if (buf[0] == '#' && buf[1] == '!' && shellscript(buf+2, &mbuf)) 18020852Ssam return; 18124666Sserge if (buf[0] == '\037' && buf[1] == '\235') { 18224666Sserge if (buf[2]&0x80) 18324666Sserge printf("block "); 18424666Sserge printf("compressed %d bit code data\n", buf[2]&0x1f); 18524666Sserge return; 18624666Sserge } 187613Sbill if(strncmp(buf, "!<arch>\n__.SYMDEF", 17) == 0 ) { 188613Sbill printf("archive random library\n"); 18920852Ssam return; 190613Sbill } 191613Sbill if (strncmp(buf, "!<arch>\n", 8)==0) { 192613Sbill printf("archive\n"); 19320852Ssam return; 194613Sbill } 1955900Sroot if (mbuf.st_size % 512 == 0) { /* it may be a PRESS file */ 1965900Sroot lseek(ifile, -512L, 2); /* last block */ 19720852Ssam if (read(ifile, buf, BUFSIZ) > 0 && *(short *)buf == 12138) { 1985900Sroot printf("PRESS file\n"); 19920852Ssam return; 2005900Sroot } 2015900Sroot } 202613Sbill i = 0; 203613Sbill if(ccom() == 0)goto notc; 204613Sbill while(buf[i] == '#'){ 205613Sbill j = i; 206613Sbill while(buf[i++] != '\n'){ 207613Sbill if(i - j > 255){ 208613Sbill printf("data\n"); 20920852Ssam return; 210613Sbill } 211613Sbill if(i >= in)goto notc; 212613Sbill } 213613Sbill if(ccom() == 0)goto notc; 214613Sbill } 215613Sbill check: 216613Sbill if(lookup(c) == 1){ 217613Sbill while((ch = buf[i++]) != ';' && ch != '{')if(i >= in)goto notc; 218613Sbill printf("c program text"); 219613Sbill goto outa; 220613Sbill } 221613Sbill nl = 0; 222613Sbill while(buf[i] != '('){ 223613Sbill if(buf[i] <= 0) 224613Sbill goto notas; 225613Sbill if(buf[i] == ';'){ 226613Sbill i++; 227613Sbill goto check; 228613Sbill } 229613Sbill if(buf[i++] == '\n') 230613Sbill if(nl++ > 6)goto notc; 231613Sbill if(i >= in)goto notc; 232613Sbill } 233613Sbill while(buf[i] != ')'){ 234613Sbill if(buf[i++] == '\n') 235613Sbill if(nl++ > 6)goto notc; 236613Sbill if(i >= in)goto notc; 237613Sbill } 238613Sbill while(buf[i] != '{'){ 239613Sbill if(buf[i++] == '\n') 240613Sbill if(nl++ > 6)goto notc; 241613Sbill if(i >= in)goto notc; 242613Sbill } 243613Sbill printf("c program text"); 244613Sbill goto outa; 245613Sbill notc: 246613Sbill i = 0; 247613Sbill while(buf[i] == 'c' || buf[i] == '#'){ 248613Sbill while(buf[i++] != '\n')if(i >= in)goto notfort; 249613Sbill } 250613Sbill if(lookup(fort) == 1){ 251613Sbill printf("fortran program text"); 252613Sbill goto outa; 253613Sbill } 254613Sbill notfort: 255613Sbill i=0; 256613Sbill if(ascom() == 0)goto notas; 257613Sbill j = i-1; 258613Sbill if(buf[i] == '.'){ 259613Sbill i++; 260613Sbill if(lookup(as) == 1){ 261613Sbill printf("assembler program text"); 262613Sbill goto outa; 263613Sbill } 264613Sbill else if(buf[j] == '\n' && isalpha(buf[j+2])){ 265613Sbill printf("roff, nroff, or eqn input text"); 266613Sbill goto outa; 267613Sbill } 268613Sbill } 269613Sbill while(lookup(asc) == 0){ 270613Sbill if(ascom() == 0)goto notas; 271613Sbill while(buf[i] != '\n' && buf[i++] != ':') 272613Sbill if(i >= in)goto notas; 273613Sbill while(buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\t')if(i++ >= in)goto notas; 274613Sbill j = i-1; 275613Sbill if(buf[i] == '.'){ 276613Sbill i++; 277613Sbill if(lookup(as) == 1){ 278613Sbill printf("assembler program text"); 279613Sbill goto outa; 280613Sbill } 281613Sbill else if(buf[j] == '\n' && isalpha(buf[j+2])){ 282613Sbill printf("roff, nroff, or eqn input text"); 283613Sbill goto outa; 284613Sbill } 285613Sbill } 286613Sbill } 287613Sbill printf("assembler program text"); 288613Sbill goto outa; 289613Sbill notas: 290613Sbill for(i=0; i < in; i++)if(buf[i]&0200){ 29120852Ssam if (buf[0]=='\100' && buf[1]=='\357') 292613Sbill printf("troff (CAT) output\n"); 29320852Ssam else 29420852Ssam printf("data\n"); 29520852Ssam return; 296613Sbill } 29717963Sserge if (mbuf.st_mode&((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6))) { 29817963Sserge if (mbuf.st_mode & S_ISUID) 29917963Sserge printf("set-uid "); 30017963Sserge if (mbuf.st_mode & S_ISGID) 30117963Sserge printf("set-gid "); 30217963Sserge if (mbuf.st_mode & S_ISVTX) 30317963Sserge printf("sticky "); 30420852Ssam if (shell(buf, in, sh)) 30520852Ssam printf("shell script"); 30620852Ssam else if (shell(buf, in, csh)) 30720852Ssam printf("c-shell script"); 30820852Ssam else 30920852Ssam printf("commands text"); 31017963Sserge } else if (troffint(buf, in)) 311613Sbill printf("troff intermediate output text"); 31220852Ssam else if (shell(buf, in, sh)) 31320852Ssam printf("shell commands"); 31420852Ssam else if (shell(buf, in, csh)) 31520852Ssam printf("c-shell commands"); 316613Sbill else if (english(buf, in)) 317613Sbill printf("English text"); 318613Sbill else 319613Sbill printf("ascii text"); 320613Sbill outa: 321613Sbill while(i < in) 322613Sbill if((buf[i++]&0377) > 127){ 323613Sbill printf(" with garbage\n"); 32420852Ssam return; 325613Sbill } 326613Sbill /* if next few lines in then read whole file looking for nulls ... 327613Sbill while((in = read(ifile,buf,BUFSIZ)) > 0) 328613Sbill for(i = 0; i < in; i++) 329613Sbill if((buf[i]&0377) > 127){ 330613Sbill printf(" with garbage\n"); 33120852Ssam return; 332613Sbill } 333613Sbill /*.... */ 334613Sbill printf("\n"); 335613Sbill } 336613Sbill 337613Sbill oldo(cp) 338613Sbill char *cp; 339613Sbill { 340613Sbill struct exec ex; 341613Sbill struct stat stb; 342613Sbill 343613Sbill ex = *(struct exec *)cp; 344613Sbill if (fstat(ifile, &stb) < 0) 345613Sbill return(0); 346613Sbill if (N_STROFF(ex)+sizeof(off_t) > stb.st_size) 347613Sbill return (1); 348613Sbill return (0); 349613Sbill } 350613Sbill 351613Sbill 352613Sbill 353613Sbill troffint(bp, n) 354613Sbill char *bp; 355613Sbill int n; 356613Sbill { 357613Sbill int k; 358613Sbill 359613Sbill i = 0; 360613Sbill for (k = 0; k < 6; k++) { 361613Sbill if (lookup(troff) == 0) 362613Sbill return(0); 363613Sbill if (lookup(troff) == 0) 364613Sbill return(0); 365613Sbill while (i < n && buf[i] != '\n') 366613Sbill i++; 367613Sbill if (i++ >= n) 368613Sbill return(0); 369613Sbill } 370613Sbill return(1); 371613Sbill } 372613Sbill lookup(tab) 373613Sbill char *tab[]; 374613Sbill { 375613Sbill char r; 376613Sbill int k,j,l; 377613Sbill while(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n')i++; 378613Sbill for(j=0; tab[j] != 0; j++){ 379613Sbill l=0; 380613Sbill for(k=i; ((r=tab[j][l++]) == buf[k] && r != '\0');k++); 381613Sbill if(r == '\0') 382613Sbill if(buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\t' 383613Sbill || buf[k] == '{' || buf[k] == '/'){ 384613Sbill i=k; 385613Sbill return(1); 386613Sbill } 387613Sbill } 388613Sbill return(0); 389613Sbill } 390613Sbill ccom(){ 391613Sbill char cc; 392613Sbill while((cc = buf[i]) == ' ' || cc == '\t' || cc == '\n')if(i++ >= in)return(0); 393613Sbill if(buf[i] == '/' && buf[i+1] == '*'){ 394613Sbill i += 2; 395613Sbill while(buf[i] != '*' || buf[i+1] != '/'){ 396613Sbill if(buf[i] == '\\')i += 2; 397613Sbill else i++; 398613Sbill if(i >= in)return(0); 399613Sbill } 400613Sbill if((i += 2) >= in)return(0); 401613Sbill } 402613Sbill if(buf[i] == '\n')if(ccom() == 0)return(0); 403613Sbill return(1); 404613Sbill } 405613Sbill ascom(){ 406613Sbill while(buf[i] == '/'){ 407613Sbill i++; 408613Sbill while(buf[i++] != '\n')if(i >= in)return(0); 409613Sbill while(buf[i] == '\n')if(i++ >= in)return(0); 410613Sbill } 411613Sbill return(1); 412613Sbill } 413613Sbill 414613Sbill english (bp, n) 415613Sbill char *bp; 416613Sbill { 417613Sbill # define NASC 128 418613Sbill int ct[NASC], j, vow, freq, rare; 419613Sbill int badpun = 0, punct = 0; 420613Sbill if (n<50) return(0); /* no point in statistics on squibs */ 421613Sbill for(j=0; j<NASC; j++) 422613Sbill ct[j]=0; 423613Sbill for(j=0; j<n; j++) 424613Sbill { 425*34099Sbostic if ((u_char)bp[j]<NASC) 426613Sbill ct[bp[j]|040]++; 427613Sbill switch (bp[j]) 428613Sbill { 429613Sbill case '.': 430613Sbill case ',': 431613Sbill case ')': 432613Sbill case '%': 433613Sbill case ';': 434613Sbill case ':': 435613Sbill case '?': 436613Sbill punct++; 437613Sbill if ( j < n-1 && 438613Sbill bp[j+1] != ' ' && 439613Sbill bp[j+1] != '\n') 440613Sbill badpun++; 441613Sbill } 442613Sbill } 443613Sbill if (badpun*5 > punct) 444613Sbill return(0); 445613Sbill vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 446613Sbill freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 447613Sbill rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 448613Sbill if (2*ct[';'] > ct['e']) return(0); 449613Sbill if ( (ct['>']+ct['<']+ct['/'])>ct['e']) return(0); /* shell file test */ 450613Sbill return (vow*5 >= n-ct[' '] && freq >= 10*rare); 451613Sbill } 45220852Ssam 45320852Ssam shellscript(buf, sb) 45420852Ssam char buf[]; 45520852Ssam struct stat *sb; 45620852Ssam { 45720852Ssam register char *tp; 45820852Ssam char *cp, *xp, *index(); 45920852Ssam 46020852Ssam cp = index(buf, '\n'); 46120852Ssam if (cp == 0 || cp - buf > in) 46220852Ssam return (0); 46320852Ssam for (tp = buf; tp != cp && isspace(*tp); tp++) 46420852Ssam if (!isascii(*tp)) 46520852Ssam return (0); 46620852Ssam for (xp = tp; tp != cp && !isspace(*tp); tp++) 46720852Ssam if (!isascii(*tp)) 46820852Ssam return (0); 46920852Ssam if (tp == xp) 47020852Ssam return (0); 47120852Ssam if (sb->st_mode & S_ISUID) 47220852Ssam printf("set-uid "); 47320852Ssam if (sb->st_mode & S_ISGID) 47420852Ssam printf("set-gid "); 47520852Ssam if (strncmp(xp, "/bin/sh", tp-xp) == 0) 47620852Ssam xp = "shell"; 47720852Ssam else if (strncmp(xp, "/bin/csh", tp-xp) == 0) 47820852Ssam xp = "c-shell"; 47920852Ssam else 48020852Ssam *tp = '\0'; 48120852Ssam printf("executable %s script\n", xp); 48220852Ssam return (1); 48320852Ssam } 48420852Ssam 48520852Ssam shell(bp, n, tab) 48620852Ssam char *bp; 48720852Ssam int n; 48820852Ssam char *tab[]; 48920852Ssam { 49020852Ssam 49120852Ssam i = 0; 49220852Ssam do { 49320852Ssam if (buf[i] == '#' || buf[i] == ':') 49420852Ssam while (i < n && buf[i] != '\n') 49520852Ssam i++; 49620852Ssam if (++i >= n) 49720852Ssam break; 49820852Ssam if (lookup(tab) == 1) 49920852Ssam return (1); 50020852Ssam } while (i < n); 50120852Ssam return (0); 50220852Ssam } 503