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