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