1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1991, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)file.c 8.1 (Berkeley) 06/06/93"; 16 #endif /* not lint */ 17 18 /* 19 * file - determine type of file 20 */ 21 22 #include <sys/param.h> 23 #include <sys/stat.h> 24 #include <string.h> 25 #include <stdio.h> 26 #include <ctype.h> 27 #include <a.out.h> 28 29 #if defined(hp300) || defined(hp800) 30 #include <hp/hpux/hpux_exec.h> 31 #endif 32 33 extern int errno; 34 int in; 35 int i = 0; 36 37 #define BUFSIZE 4096 38 39 char buf[BUFSIZE]; 40 char *troff[] = { /* new troff intermediate lang */ 41 "x","T","res","init","font","202","V0","p1",0}; 42 char *fort[] = { 43 "function","subroutine","common","dimension","block","integer", 44 "real","data","double",0}; 45 char *asc[] = { 46 "chmk","mov","tst","clr","jmp",0}; 47 char *c[] = { 48 "int","char","float","double","struct","extern", "static",0}; 49 char *as[] = { 50 "globl","byte","align","text","data","comm",0}; 51 char *sh[] = { 52 "fi", "elif", "esac", "done", "export", 53 "readonly", "trap", "PATH", "HOME", 0 }; 54 char *csh[] = { 55 "alias", "breaksw", "endsw", "foreach", "limit", "onintr", 56 "repeat", "setenv", "source", "path", "home", 0 }; 57 int ifile; 58 59 main(argc, argv) 60 char **argv; 61 { 62 FILE *fl; 63 register char *p; 64 char ap[MAXPATHLEN + 1]; 65 66 if (argc < 2) { 67 fprintf(stderr, "usage: %s file ...\n", argv[0]); 68 exit(3); 69 } 70 71 if (argc>1 && argv[1][0]=='-' && argv[1][1]=='f') { 72 if ((fl = fopen(argv[2], "r")) == NULL) { 73 perror(argv[2]); 74 exit(2); 75 } 76 while ((p = fgets(ap, sizeof ap, fl)) != NULL) { 77 int l = strlen(p); 78 if (l>0) 79 p[l-1] = '\0'; 80 type(p); 81 if (ifile>=0) 82 close(ifile); 83 } 84 exit(1); 85 } 86 while(argc > 1) { 87 ifile = -1; 88 type(argv[1]); 89 fflush(stdout); 90 argc--; 91 argv++; 92 if (ifile >= 0) 93 close(ifile); 94 } 95 exit(0); 96 } 97 98 type(file) 99 char *file; 100 { 101 int j,nl; 102 char ch; 103 struct stat mbuf; 104 char slink[MAXPATHLEN + 1]; 105 struct exec *hdr; 106 #if defined(hp300) || defined(hp800) 107 int ishpux300 = 0; 108 int ishpux800 = 0; 109 #endif 110 111 if (lstat(file, &mbuf) < 0) { 112 fprintf(stderr, "file: %s: %s\n", file, strerror(errno)); 113 return; 114 } 115 switch (mbuf.st_mode & S_IFMT) { 116 case S_IFLNK: 117 printf("%s:\tsymbolic link", file); 118 j = readlink(file, slink, sizeof slink - 1); 119 if (j >= 0) { 120 slink[j] = '\0'; 121 printf(" to %s", slink); 122 } 123 printf("\n"); 124 return; 125 126 case S_IFDIR: 127 printf("%s:\t", file); 128 if (mbuf.st_mode & S_ISVTX) 129 printf("append-only "); 130 printf("directory\n"); 131 return; 132 133 case S_IFCHR: 134 case S_IFBLK: 135 printf("%s:\t%s special (%d/%d)\n", file, 136 (mbuf.st_mode&S_IFMT) == S_IFCHR ? "character" : "block", 137 major(mbuf.st_rdev), minor(mbuf.st_rdev)); 138 return; 139 140 case S_IFSOCK: 141 printf("%s:\tsocket\n", file); 142 return; 143 } 144 145 ifile = open(file, 0); 146 if (ifile < 0) { 147 fprintf(stderr, "file: %s: %s\n", file, strerror(errno)); 148 return; 149 } 150 printf("%s:\t", file); 151 in = read(ifile, buf, BUFSIZE); 152 if (in == 0) { 153 printf("empty\n"); 154 return; 155 } 156 hdr = (struct exec *) buf; 157 #ifdef MID_ZERO /* if we have a_mid field */ 158 switch (hdr->a_mid) { 159 case MID_SUN010: 160 printf("SUN 68010/68020 "); 161 break; 162 case MID_SUN020: 163 printf("SUN 68020 "); 164 break; 165 case MID_HP200: 166 printf("HP200 "); 167 break; 168 case MID_HP300: 169 printf("HP300 "); 170 break; 171 #if defined(hp300) || defined(hp800) 172 case MID_HPUX: 173 printf("HP-UX series [234]00 "); 174 ishpux300 = 1; 175 if (hdr->a_magic == 0406) { 176 printf("relocatable object\n"); 177 return; 178 } 179 break; 180 case MID_HPUX800: 181 printf("HP-UX series 800 "); 182 ishpux800 = 1; 183 if (hdr->a_magic == 0x106) { 184 printf("relocatable object\n"); 185 return; 186 } 187 break; 188 #endif 189 #ifdef MID_MIPSI 190 case MID_MIPSI: 191 printf("MIPS R3000 "); 192 break; 193 #endif 194 #ifdef MID_MIPSII 195 case MID_MIPSII: 196 printf("MIPS R4000 "); 197 break; 198 #endif 199 #if BYTE_ORDER == BIG_ENDIAN 200 case ((OMAGIC & 0xff) << 8) | (OMAGIC >> 8): 201 case ((NMAGIC & 0xff) << 8) | (NMAGIC >> 8): 202 case ((ZMAGIC & 0xff) << 8) | (ZMAGIC >> 8): 203 printf("byte-swapped (VAX/386) "); 204 hdr->a_magic = ((hdr->a_mid & 0xff) << 8) | (hdr->a_mid >> 8); 205 break; 206 #endif 207 } 208 #endif /* MID_ZERO, a_mid */ 209 switch (hdr->a_magic) { 210 211 case 0411: 212 printf("jfr or pdp-11 unix 411 executable\n"); 213 return; 214 215 case ZMAGIC: 216 printf("demand paged "); 217 /* FALLTHROUGH */ 218 219 case NMAGIC: 220 printf("pure "); 221 /* FALLTHROUGH */ 222 223 case OMAGIC: 224 if (mbuf.st_mode & S_ISUID) 225 printf("set-uid "); 226 if (mbuf.st_mode & S_ISGID) 227 printf("set-gid "); 228 if (mbuf.st_mode & S_ISVTX) 229 printf("sticky "); 230 if ((mbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0 && 231 (hdr->a_trsize || hdr->a_drsize)) { 232 printf("relocatable object\n"); 233 return; 234 } 235 #if defined(hp300) 236 if (ishpux300) { 237 if (((int *)buf)[2] & 0x40000000) 238 printf("dynamically-linked "); 239 } 240 #endif 241 printf("executable"); 242 #if defined(hp300) || defined(hp800) 243 if (ishpux300) { 244 if (((int *)buf)[9] != 0) 245 printf(" not stripped"); 246 } else if (ishpux800) { 247 if (((int *)buf)[24] != 0) 248 printf(" not stripped"); 249 } else 250 #endif 251 if (hdr->a_syms != 0) 252 printf(" not stripped"); 253 printf("\n"); 254 return; 255 #if defined(hp300) 256 case 0x10e: 257 printf("shared library, version %d\n", ((short *)buf)[2]); 258 return; 259 #endif 260 } 261 262 switch (*(int *)buf) { 263 case 0177555: 264 printf("very old archive\n"); 265 return; 266 267 case 0177545: 268 printf("old archive\n"); 269 return; 270 271 case 070707: 272 printf("cpio data\n"); 273 return; 274 } 275 276 if (buf[0] == '#' && buf[1] == '!' && shellscript(buf+2, &mbuf)) 277 return; 278 if (buf[0] == '\037' && buf[1] == '\235') { 279 if (buf[2]&0x80) 280 printf("block "); 281 printf("compressed %d bit code data\n", buf[2]&0x1f); 282 return; 283 } 284 if (strncmp(buf, "!<arch>\n__.SYMDEF", 17) == 0 ) { 285 printf("archive random library\n"); 286 return; 287 } 288 if (strncmp(buf, "!<arch>\n", 8)==0) { 289 printf("archive\n"); 290 return; 291 } 292 if (mbuf.st_size % 512 == 0) { /* it may be a PRESS file */ 293 lseek(ifile, -512L, 2); /* last block */ 294 if (read(ifile, buf, BUFSIZE) > 0 && *(short *)buf == 12138) { 295 printf("PRESS file\n"); 296 return; 297 } 298 } 299 i = 0; 300 if(ccom() == 0)goto notc; 301 while(buf[i] == '#'){ 302 j = i; 303 while(buf[i++] != '\n'){ 304 if(i - j > 255){ 305 printf("data\n"); 306 return; 307 } 308 if(i >= in)goto notc; 309 } 310 if(ccom() == 0)goto notc; 311 } 312 check: 313 if(lookup(c) == 1){ 314 while((ch = buf[i++]) != ';' && ch != '{')if(i >= in)goto notc; 315 printf("c program text"); 316 goto outa; 317 } 318 nl = 0; 319 while(buf[i] != '('){ 320 if(buf[i] <= 0) 321 goto notas; 322 if(buf[i] == ';'){ 323 i++; 324 goto check; 325 } 326 if(buf[i++] == '\n') 327 if(nl++ > 6)goto notc; 328 if(i >= in)goto notc; 329 } 330 while(buf[i] != ')'){ 331 if(buf[i++] == '\n') 332 if(nl++ > 6)goto notc; 333 if(i >= in)goto notc; 334 } 335 while(buf[i] != '{'){ 336 if(buf[i++] == '\n') 337 if(nl++ > 6)goto notc; 338 if(i >= in)goto notc; 339 } 340 printf("c program text"); 341 goto outa; 342 notc: 343 i = 0; 344 while(buf[i] == 'c' || buf[i] == '#'){ 345 while(buf[i++] != '\n')if(i >= in)goto notfort; 346 } 347 if(lookup(fort) == 1){ 348 printf("fortran program text"); 349 goto outa; 350 } 351 notfort: 352 i=0; 353 if(ascom() == 0)goto notas; 354 j = i-1; 355 if(buf[i] == '.'){ 356 i++; 357 if(lookup(as) == 1){ 358 printf("assembler program text"); 359 goto outa; 360 } 361 else if(buf[j] == '\n' && isalpha(buf[j+2])){ 362 printf("roff, nroff, or eqn input text"); 363 goto outa; 364 } 365 } 366 while(lookup(asc) == 0){ 367 if(ascom() == 0)goto notas; 368 while(buf[i] != '\n' && buf[i++] != ':') 369 if(i >= in)goto notas; 370 while(buf[i] == '\n' || buf[i] == ' ' || buf[i] == '\t')if(i++ >= in)goto notas; 371 j = i-1; 372 if(buf[i] == '.'){ 373 i++; 374 if(lookup(as) == 1){ 375 printf("assembler program text"); 376 goto outa; 377 } 378 else if(buf[j] == '\n' && isalpha(buf[j+2])){ 379 printf("roff, nroff, or eqn input text"); 380 goto outa; 381 } 382 } 383 } 384 printf("assembler program text"); 385 goto outa; 386 notas: 387 for(i=0; i < in; i++)if(buf[i]&0200){ 388 if (buf[0]=='\100' && buf[1]=='\357') 389 printf("troff (CAT) output\n"); 390 else 391 printf("data\n"); 392 return; 393 } 394 if (mbuf.st_mode&((S_IEXEC)|(S_IEXEC>>3)|(S_IEXEC>>6))) { 395 if (mbuf.st_mode & S_ISUID) 396 printf("set-uid "); 397 if (mbuf.st_mode & S_ISGID) 398 printf("set-gid "); 399 if (mbuf.st_mode & S_ISVTX) 400 printf("sticky "); 401 if (shell(buf, in, sh)) 402 printf("shell script"); 403 else if (shell(buf, in, csh)) 404 printf("c-shell script"); 405 else 406 printf("commands text"); 407 } else if (troffint(buf, in)) 408 printf("troff intermediate output text"); 409 else if (shell(buf, in, sh)) 410 printf("shell commands"); 411 else if (shell(buf, in, csh)) 412 printf("c-shell commands"); 413 else if (english(buf, in)) 414 printf("English text"); 415 else 416 printf("ascii text"); 417 outa: 418 while(i < in) 419 if((buf[i++]&0377) > 127){ 420 printf(" with garbage\n"); 421 return; 422 } 423 /* if next few lines in then read whole file looking for nulls ... 424 while((in = read(ifile,buf,BUFSIZE)) > 0) 425 for(i = 0; i < in; i++) 426 if((buf[i]&0377) > 127){ 427 printf(" with garbage\n"); 428 return; 429 } 430 /*.... */ 431 printf("\n"); 432 } 433 434 troffint(bp, n) 435 char *bp; 436 int n; 437 { 438 int k; 439 440 i = 0; 441 for (k = 0; k < 6; k++) { 442 if (lookup(troff) == 0) 443 return(0); 444 if (lookup(troff) == 0) 445 return(0); 446 while (i < n && buf[i] != '\n') 447 i++; 448 if (i++ >= n) 449 return(0); 450 } 451 return(1); 452 } 453 lookup(tab) 454 char *tab[]; 455 { 456 char r; 457 int k,j,l; 458 while(buf[i] == ' ' || buf[i] == '\t' || buf[i] == '\n')i++; 459 for(j=0; tab[j] != 0; j++){ 460 l=0; 461 for(k=i; ((r=tab[j][l++]) == buf[k] && r != '\0');k++); 462 if(r == '\0') 463 if(buf[k] == ' ' || buf[k] == '\n' || buf[k] == '\t' 464 || buf[k] == '{' || buf[k] == '/'){ 465 i=k; 466 return(1); 467 } 468 } 469 return(0); 470 } 471 ccom(){ 472 char cc; 473 while((cc = buf[i]) == ' ' || cc == '\t' || cc == '\n')if(i++ >= in)return(0); 474 if(buf[i] == '/' && buf[i+1] == '*'){ 475 i += 2; 476 while(buf[i] != '*' || buf[i+1] != '/'){ 477 if(buf[i] == '\\')i += 2; 478 else i++; 479 if(i >= in)return(0); 480 } 481 if((i += 2) >= in)return(0); 482 } 483 if(buf[i] == '\n')if(ccom() == 0)return(0); 484 return(1); 485 } 486 ascom(){ 487 while(buf[i] == '/'){ 488 i++; 489 while(buf[i++] != '\n')if(i >= in)return(0); 490 while(buf[i] == '\n')if(i++ >= in)return(0); 491 } 492 return(1); 493 } 494 495 english (bp, n) 496 char *bp; 497 { 498 # define NASC 128 499 int ct[NASC], j, vow, freq, rare; 500 int badpun = 0, punct = 0; 501 if (n<50) return(0); /* no point in statistics on squibs */ 502 for(j=0; j<NASC; j++) 503 ct[j]=0; 504 for(j=0; j<n; j++) 505 { 506 if ((u_char)bp[j]<NASC) 507 ct[bp[j]|040]++; 508 switch (bp[j]) 509 { 510 case '.': 511 case ',': 512 case ')': 513 case '%': 514 case ';': 515 case ':': 516 case '?': 517 punct++; 518 if ( j < n-1 && 519 bp[j+1] != ' ' && 520 bp[j+1] != '\n') 521 badpun++; 522 } 523 } 524 if (badpun*5 > punct) 525 return(0); 526 vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 527 freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 528 rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 529 if (2*ct[';'] > ct['e']) return(0); 530 if ( (ct['>']+ct['<']+ct['/'])>ct['e']) return(0); /* shell file test */ 531 return (vow*5 >= n-ct[' '] && freq >= 10*rare); 532 } 533 534 shellscript(buf, sb) 535 char buf[]; 536 struct stat *sb; 537 { 538 register char *tp; 539 char *cp, *xp, *index(); 540 541 cp = index(buf, '\n'); 542 if (cp == 0 || cp - buf > in) 543 return (0); 544 for (tp = buf; tp != cp && isspace(*tp); tp++) 545 if (!isascii(*tp)) 546 return (0); 547 for (xp = tp; tp != cp && !isspace(*tp); tp++) 548 if (!isascii(*tp)) 549 return (0); 550 if (tp == xp) 551 return (0); 552 if (sb->st_mode & S_ISUID) 553 printf("set-uid "); 554 if (sb->st_mode & S_ISGID) 555 printf("set-gid "); 556 if (strncmp(xp, "/bin/sh", tp-xp) == 0) 557 xp = "shell"; 558 else if (strncmp(xp, "/bin/csh", tp-xp) == 0) 559 xp = "c-shell"; 560 else 561 *tp = '\0'; 562 printf("executable %s script\n", xp); 563 return (1); 564 } 565 566 shell(bp, n, tab) 567 char *bp; 568 int n; 569 char *tab[]; 570 { 571 572 i = 0; 573 do { 574 if (buf[i] == '#' || buf[i] == ':') 575 while (i < n && buf[i] != '\n') 576 i++; 577 if (++i >= n) 578 break; 579 if (lookup(tab) == 1) 580 return (1); 581 } while (i < n); 582 return (0); 583 } 584