1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* Copyright (c) 1987, 1988 Microsoft Corporation */ 26 /* All Rights Reserved */ 27 28 /* 29 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 30 * Use is subject to license terms. 31 */ 32 33 #define _LARGEFILE64_SOURCE 34 35 /* Get definitions for the relocation types supported. */ 36 #define ELF_TARGET_ALL 37 38 #include <ctype.h> 39 #include <unistd.h> 40 #include <fcntl.h> 41 #include <signal.h> 42 #include <stdio.h> 43 #include <libelf.h> 44 #include <stdlib.h> 45 #include <limits.h> 46 #include <locale.h> 47 #include <wctype.h> 48 #include <string.h> 49 #include <errno.h> 50 #include <door.h> 51 #include <sys/param.h> 52 #include <sys/types.h> 53 #include <sys/mkdev.h> 54 #include <sys/stat.h> 55 #include <sys/elf.h> 56 #include <procfs.h> 57 #include <sys/core.h> 58 #include <sys/dumphdr.h> 59 #include <netinet/in.h> 60 #include <gelf.h> 61 #include <elfcap.h> 62 #include <sgsrtcid.h> 63 #include "file.h" 64 #include "elf_read.h" 65 66 /* 67 * Misc 68 */ 69 70 #define FBSZ 512 71 #define MLIST_SZ 12 72 73 /* 74 * The 0x8FCA0102 magic string was used in crash dumps generated by releases 75 * prior to Solaris 7. 76 */ 77 #define OLD_DUMP_MAGIC 0x8FCA0102 78 79 #if defined(__sparc) 80 #define NATIVE_ISA "SPARC" 81 #define OTHER_ISA "Intel" 82 #else 83 #define NATIVE_ISA "Intel" 84 #define OTHER_ISA "SPARC" 85 #endif 86 87 /* Assembly language comment char */ 88 #ifdef pdp11 89 #define ASCOMCHAR '/' 90 #else 91 #define ASCOMCHAR '!' 92 #endif 93 94 #pragma align 16(fbuf) 95 static char fbuf[FBSZ]; 96 97 /* 98 * Magic file variables 99 */ 100 static intmax_t maxmagicoffset; 101 static intmax_t tmpmax; 102 static char *magicbuf; 103 104 static char *dfile; 105 static char *troff[] = { /* new troff intermediate lang */ 106 "x", "T", "res", "init", "font", "202", "V0", "p1", 0}; 107 108 static char *fort[] = { /* FORTRAN */ 109 "function", "subroutine", "common", "dimension", "block", 110 "integer", "real", "data", "double", 111 "FUNCTION", "SUBROUTINE", "COMMON", "DIMENSION", "BLOCK", 112 "INTEGER", "REAL", "DATA", "DOUBLE", 0}; 113 114 static char *asc[] = { /* Assembler Commands */ 115 "sys", "mov", "tst", "clr", "jmp", "cmp", "set", "inc", 116 "dec", 0}; 117 118 static char *c[] = { /* C Language */ 119 "int", "char", "float", "double", "short", "long", "unsigned", 120 "register", "static", "struct", "extern", 0}; 121 122 static char *as[] = { /* Assembler Pseudo Ops, prepended with '.' */ 123 "globl", "global", "ident", "file", "byte", "even", 124 "text", "data", "bss", "comm", 0}; 125 126 /* 127 * The line and debug section names are used by the strip command. 128 * Any changes in the strip implementation need to be reflected here. 129 */ 130 static char *debug_sections[] = { /* Debug sections in a ELF file */ 131 ".debug", ".stab", ".dwarf", ".line", NULL}; 132 133 /* start for MB env */ 134 static wchar_t wchar; 135 static int length; 136 static int IS_ascii; 137 static int Max; 138 /* end for MB env */ 139 static int i; /* global index into first 'fbsz' bytes of file */ 140 static int fbsz; 141 static int ifd = -1; 142 static int elffd = -1; 143 static int tret; 144 static int hflg; 145 static int dflg; 146 static int mflg; 147 static int M_flg; 148 static int iflg; 149 static struct stat64 mbuf; 150 151 static char **mlist1; /* 1st ordered list of magic files */ 152 static char **mlist2; /* 2nd ordered list of magic files */ 153 static size_t mlist1_sz; /* number of ptrs allocated for mlist1 */ 154 static size_t mlist2_sz; /* number of ptrs allocated for mlist2 */ 155 static char **mlist1p; /* next entry in mlist1 */ 156 static char **mlist2p; /* next entry in mlist2 */ 157 158 static ssize_t mread; 159 160 static void ar_coff_or_aout(int ifd); 161 static int type(char *file); 162 static int def_position_tests(char *file); 163 static void def_context_tests(void); 164 static int troffint(char *bp, int n); 165 static int lookup(char **tab); 166 static int ccom(void); 167 static int ascom(void); 168 static int sccs(void); 169 static int english(char *bp, int n); 170 static int shellscript(char buf[], struct stat64 *sb); 171 static int elf_check(char *file); 172 static int get_door_target(char *, char *, size_t); 173 static int zipfile(char *, int); 174 static int is_crash_dump(const char *, int); 175 static void print_dumphdr(const int, const dumphdr_t *, uint32_t (*)(uint32_t), 176 const char *); 177 static uint32_t swap_uint32(uint32_t); 178 static uint32_t return_uint32(uint32_t); 179 static void usage(void); 180 static void default_magic(void); 181 static void add_to_mlist(char *, int); 182 static void fd_cleanup(void); 183 static int is_rtld_config(void); 184 185 /* from elf_read.c */ 186 int elf_read32(int elffd, Elf_Info *EInfo); 187 int elf_read64(int elffd, Elf_Info *EInfo); 188 189 #ifdef XPG4 190 /* SUSv3 requires a single <space> after the colon */ 191 #define prf(x) (void) printf("%s: ", x); 192 #else /* !XPG4 */ 193 #define prf(x) (void) printf("%s:%s", x, (int)strlen(x) > 6 ? "\t" : "\t\t"); 194 #endif /* XPG4 */ 195 196 /* 197 * Static program identifier - used to prevent localization of the name "file" 198 * within individual error messages. 199 */ 200 const char *File = "file"; 201 202 int 203 main(int argc, char **argv) 204 { 205 char *p; 206 int ch; 207 FILE *fl; 208 int cflg = 0; 209 int eflg = 0; 210 int fflg = 0; 211 char *ap = NULL; 212 int pathlen; 213 char **filep; 214 215 (void) setlocale(LC_ALL, ""); 216 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 217 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 218 #endif 219 (void) textdomain(TEXT_DOMAIN); 220 221 while ((ch = getopt(argc, argv, "M:cdf:him:")) != EOF) { 222 switch (ch) { 223 224 case 'M': 225 add_to_mlist(optarg, !dflg); 226 M_flg++; 227 break; 228 229 case 'c': 230 cflg++; 231 break; 232 233 case 'd': 234 if (!dflg) { 235 default_magic(); 236 add_to_mlist(dfile, 0); 237 dflg++; 238 } 239 break; 240 241 case 'f': 242 fflg++; 243 errno = 0; 244 if ((fl = fopen(optarg, "r")) == NULL) { 245 int err = errno; 246 (void) fprintf(stderr, gettext("%s: cannot " 247 "open file %s: %s\n"), File, optarg, 248 err ? strerror(err) : ""); 249 usage(); 250 } 251 pathlen = pathconf("/", _PC_PATH_MAX); 252 if (pathlen == -1) { 253 int err = errno; 254 (void) fprintf(stderr, gettext("%s: cannot " 255 "determine maximum path length: %s\n"), 256 File, strerror(err)); 257 exit(1); 258 } 259 pathlen += 2; /* for null and newline in fgets */ 260 if ((ap = malloc(pathlen * sizeof (char))) == NULL) { 261 int err = errno; 262 (void) fprintf(stderr, gettext("%s: malloc " 263 "failed: %s\n"), File, strerror(err)); 264 exit(2); 265 } 266 break; 267 268 case 'h': 269 hflg++; 270 break; 271 272 case 'i': 273 iflg++; 274 break; 275 276 case 'm': 277 add_to_mlist(optarg, !dflg); 278 mflg++; 279 break; 280 281 case '?': 282 eflg++; 283 break; 284 } 285 } 286 if (!cflg && !fflg && (eflg || optind == argc)) 287 usage(); 288 if (iflg && (dflg || mflg || M_flg)) { 289 usage(); 290 } 291 if (iflg && cflg) { 292 usage(); 293 } 294 295 if (!dflg && !mflg && !M_flg && !iflg) { 296 /* no -d, -m, nor -M option; also -i option doesn't need magic */ 297 default_magic(); 298 if (f_mkmtab(dfile, cflg, 0) == -1) { 299 exit(2); 300 } 301 } 302 303 else if (mflg && !M_flg && !dflg) { 304 /* -m specified without -d nor -M */ 305 306 #ifdef XPG4 /* For SUSv3 only */ 307 308 /* 309 * The default position-dependent magic file tests 310 * in /etc/magic will follow all the -m magic tests. 311 */ 312 313 for (filep = mlist1; filep < mlist1p; filep++) { 314 if (f_mkmtab(*filep, cflg, 1) == -1) { 315 exit(2); 316 } 317 } 318 default_magic(); 319 if (f_mkmtab(dfile, cflg, 0) == -1) { 320 exit(2); 321 } 322 #else /* !XPG4 */ 323 /* 324 * Retain Solaris file behavior for -m before SUSv3, 325 * when the new -d and -M options are not specified. 326 * Use the -m file specified in place of the default 327 * /etc/magic file. Solaris file will 328 * now allow more than one magic file to be specified 329 * with multiple -m options, for consistency with 330 * other behavior. 331 * 332 * Put the magic table(s) specified by -m into 333 * the second magic table instead of the first 334 * (as indicated by the last argument to f_mkmtab()), 335 * since they replace the /etc/magic tests and 336 * must be executed alongside the default 337 * position-sensitive tests. 338 */ 339 340 for (filep = mlist1; filep < mlist1p; filep++) { 341 if (f_mkmtab(*filep, cflg, 0) == -1) { 342 exit(2); 343 } 344 } 345 #endif /* XPG4 */ 346 } else { 347 /* 348 * For any other combination of -d, -m, and -M, 349 * use the magic files in command-line order. 350 * Store the entries from the two separate lists of magic 351 * files, if any, into two separate magic file tables. 352 * mlist1: magic tests executed before default magic tests 353 * mlist2: default magic tests and after 354 */ 355 for (filep = mlist1; filep && (filep < mlist1p); filep++) { 356 if (f_mkmtab(*filep, cflg, 1) == -1) { 357 exit(2); 358 } 359 } 360 for (filep = mlist2; filep && (filep < mlist2p); filep++) { 361 if (f_mkmtab(*filep, cflg, 0) == -1) { 362 exit(2); 363 } 364 } 365 } 366 367 /* Initialize the magic file variables; check both magic tables */ 368 tmpmax = f_getmaxoffset(1); 369 maxmagicoffset = f_getmaxoffset(0); 370 if (maxmagicoffset < tmpmax) { 371 maxmagicoffset = tmpmax; 372 } 373 if (maxmagicoffset < (intmax_t)FBSZ) 374 maxmagicoffset = (intmax_t)FBSZ; 375 if ((magicbuf = malloc(maxmagicoffset)) == NULL) { 376 int err = errno; 377 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 378 File, strerror(err)); 379 exit(2); 380 } 381 382 if (cflg) { 383 f_prtmtab(); 384 if (ferror(stdout) != 0) { 385 (void) fprintf(stderr, gettext("%s: error writing to " 386 "stdout\n"), File); 387 exit(1); 388 } 389 if (fclose(stdout) != 0) { 390 int err = errno; 391 (void) fprintf(stderr, gettext("%s: fclose " 392 "failed: %s\n"), File, strerror(err)); 393 exit(1); 394 } 395 exit(0); 396 } 397 398 for (; fflg || optind < argc; optind += !fflg) { 399 register int l; 400 401 if (fflg) { 402 if ((p = fgets(ap, pathlen, fl)) == NULL) { 403 fflg = 0; 404 optind--; 405 continue; 406 } 407 l = strlen(p); 408 if (l > 0) 409 p[l - 1] = '\0'; 410 } else 411 p = argv[optind]; 412 prf(p); /* print "file_name:<tab>" */ 413 414 if (type(p)) 415 tret = 1; 416 } 417 if (ap != NULL) 418 free(ap); 419 if (tret != 0) 420 exit(tret); 421 422 if (ferror(stdout) != 0) { 423 (void) fprintf(stderr, gettext("%s: error writing to " 424 "stdout\n"), File); 425 exit(1); 426 } 427 if (fclose(stdout) != 0) { 428 int err = errno; 429 (void) fprintf(stderr, gettext("%s: fclose failed: %s\n"), 430 File, strerror(err)); 431 exit(1); 432 } 433 return (0); 434 } 435 436 static int 437 type(char *file) 438 { 439 int cc; 440 char buf[BUFSIZ]; 441 int (*statf)() = hflg ? lstat64 : stat64; 442 443 i = 0; /* reset index to beginning of file */ 444 ifd = -1; 445 if ((*statf)(file, &mbuf) < 0) { 446 if (statf == lstat64 || lstat64(file, &mbuf) < 0) { 447 int err = errno; 448 (void) printf(gettext("cannot open: %s\n"), 449 strerror(err)); 450 return (0); /* POSIX.2 */ 451 } 452 } 453 switch (mbuf.st_mode & S_IFMT) { 454 case S_IFREG: 455 if (iflg) { 456 (void) printf(gettext("regular file\n")); 457 return (0); 458 } 459 break; 460 case S_IFCHR: 461 (void) printf(gettext("character")); 462 goto spcl; 463 464 case S_IFDIR: 465 (void) printf(gettext("directory\n")); 466 return (0); 467 468 case S_IFIFO: 469 (void) printf(gettext("fifo\n")); 470 return (0); 471 472 case S_IFLNK: 473 if ((cc = readlink(file, buf, BUFSIZ)) < 0) { 474 int err = errno; 475 (void) printf(gettext("readlink error: %s\n"), 476 strerror(err)); 477 return (1); 478 } 479 buf[cc] = '\0'; 480 (void) printf(gettext("symbolic link to %s\n"), buf); 481 return (0); 482 483 case S_IFBLK: 484 (void) printf(gettext("block")); 485 /* major and minor, see sys/mkdev.h */ 486 spcl: 487 (void) printf(gettext(" special (%d/%d)\n"), 488 major(mbuf.st_rdev), minor(mbuf.st_rdev)); 489 return (0); 490 491 case S_IFSOCK: 492 (void) printf("socket\n"); 493 /* FIXME, should open and try to getsockname. */ 494 return (0); 495 496 case S_IFDOOR: 497 if (get_door_target(file, buf, sizeof (buf)) == 0) 498 (void) printf(gettext("door to %s\n"), buf); 499 else 500 (void) printf(gettext("door\n")); 501 return (0); 502 503 } 504 505 if (elf_version(EV_CURRENT) == EV_NONE) { 506 (void) printf(gettext("libelf is out of date\n")); 507 return (1); 508 } 509 510 ifd = open64(file, O_RDONLY); 511 if (ifd < 0) { 512 int err = errno; 513 (void) printf(gettext("cannot open: %s\n"), strerror(err)); 514 return (0); /* POSIX.2 */ 515 } 516 517 /* need another fd for elf, since we might want to read the file too */ 518 elffd = open64(file, O_RDONLY); 519 if (elffd < 0) { 520 int err = errno; 521 (void) printf(gettext("cannot open: %s\n"), strerror(err)); 522 (void) close(ifd); 523 ifd = -1; 524 return (0); /* POSIX.2 */ 525 } 526 if ((fbsz = read(ifd, fbuf, FBSZ)) == -1) { 527 int err = errno; 528 (void) printf(gettext("cannot read: %s\n"), strerror(err)); 529 (void) close(ifd); 530 ifd = -1; 531 return (0); /* POSIX.2 */ 532 } 533 if (fbsz == 0) { 534 (void) printf(gettext("empty file\n")); 535 fd_cleanup(); 536 return (0); 537 } 538 539 /* 540 * First try user-specified position-dependent magic tests, if any, 541 * which need to execute before the default tests. 542 */ 543 if ((mread = pread(ifd, (void*)magicbuf, (size_t)maxmagicoffset, 544 (off_t)0)) == -1) { 545 int err = errno; 546 (void) printf(gettext("cannot read: %s\n"), strerror(err)); 547 fd_cleanup(); 548 return (0); 549 } 550 551 /* 552 * ChecK against Magic Table entries. 553 * Check first magic table for magic tests to be applied 554 * before default tests. 555 * If no default tests are to be applied, all magic tests 556 * should occur in this magic table. 557 */ 558 switch (f_ckmtab(magicbuf, mread, 1)) { 559 case -1: /* Error */ 560 exit(2); 561 break; 562 case 0: /* Not magic */ 563 break; 564 default: /* Switch is magic index */ 565 (void) putchar('\n'); 566 fd_cleanup(); 567 return (0); 568 /* NOTREACHED */ 569 break; 570 } 571 572 if (dflg || !M_flg) { 573 /* 574 * default position-dependent tests, 575 * plus non-default magic tests, if any 576 */ 577 switch (def_position_tests(file)) { 578 case -1: /* error */ 579 fd_cleanup(); 580 return (1); 581 case 1: /* matching type found */ 582 fd_cleanup(); 583 return (0); 584 /* NOTREACHED */ 585 break; 586 case 0: /* no matching type found */ 587 break; 588 } 589 /* default context-sensitive tests */ 590 def_context_tests(); 591 } else { 592 /* no more tests to apply; no match was found */ 593 (void) printf(gettext("data\n")); 594 } 595 fd_cleanup(); 596 return (0); 597 } 598 599 /* 600 * def_position_tests() - applies default position-sensitive tests, 601 * looking for values in specific positions in the file. 602 * These are followed by default (followed by possibly some 603 * non-default) magic file tests. 604 * 605 * All position-sensitive tests, default or otherwise, must 606 * be applied before context-sensitive tests, to avoid 607 * false context-sensitive matches. 608 * 609 * Returns -1 on error which should result in error (non-zero) 610 * exit status for the file utility. 611 * Returns 0 if no matching file type found. 612 * Returns 1 if matching file type found. 613 */ 614 615 static int 616 def_position_tests(char *file) 617 { 618 if (sccs()) { /* look for "1hddddd" where d is a digit */ 619 (void) printf("sccs \n"); 620 return (1); 621 } 622 if (fbuf[0] == '#' && fbuf[1] == '!' && shellscript(fbuf+2, &mbuf)) 623 return (1); 624 625 if (elf_check(file) == 0) { 626 (void) putchar('\n'); 627 return (1); 628 /* LINTED: pointer cast may result in improper alignment */ 629 } else if (*(int *)fbuf == CORE_MAGIC) { 630 /* LINTED: pointer cast may result in improper alignment */ 631 struct core *corep = (struct core *)fbuf; 632 633 (void) printf("a.out core file"); 634 635 if (*(corep->c_cmdname) != '\0') 636 (void) printf(" from '%s'", corep->c_cmdname); 637 (void) putchar('\n'); 638 return (1); 639 } 640 641 /* 642 * Runtime linker (ld.so.1) configuration file. 643 */ 644 if (is_rtld_config()) 645 return (1); 646 647 /* 648 * ZIP files, JAR files, and Java executables 649 */ 650 if (zipfile(fbuf, ifd)) 651 return (1); 652 653 if (is_crash_dump(fbuf, ifd)) 654 return (1); 655 656 /* 657 * ChecK against Magic Table entries. 658 * The magic entries checked here always start with default 659 * magic tests and may be followed by other, non-default magic 660 * tests. If no default tests are to be executed, all the 661 * magic tests should have been in the first magic table. 662 */ 663 switch (f_ckmtab(magicbuf, mread, 0)) { 664 case -1: /* Error */ 665 exit(2); 666 break; 667 case 0: /* Not magic */ 668 return (0); 669 /* NOTREACHED */ 670 break; 671 default: /* Switch is magic index */ 672 673 /* 674 * f_ckmtab recognizes file type, 675 * check if it is PostScript. 676 * if not, check if elf or a.out 677 */ 678 if (magicbuf[0] == '%' && magicbuf[1] == '!') { 679 (void) putchar('\n'); 680 } else { 681 682 /* 683 * Check that the file is executable (dynamic 684 * objects must be executable to be exec'ed, 685 * shared objects need not be, but by convention 686 * should be executable). 687 * 688 * Note that we should already have processed 689 * the file if it was an ELF file. 690 */ 691 ar_coff_or_aout(elffd); 692 (void) putchar('\n'); 693 } 694 return (1); 695 /* NOTREACHED */ 696 break; 697 } 698 699 return (0); /* file was not identified */ 700 } 701 702 /* 703 * def_context_tests() - default context-sensitive tests. 704 * These are the last tests to be applied. 705 * If no match is found, prints out "data". 706 */ 707 708 static void 709 def_context_tests(void) 710 { 711 int j; 712 int nl; 713 char ch; 714 int len; 715 716 if (ccom() == 0) 717 goto notc; 718 while (fbuf[i] == '#') { 719 j = i; 720 while (fbuf[i++] != '\n') { 721 if (i - j > 255) { 722 (void) printf(gettext("data\n")); 723 return; 724 } 725 if (i >= fbsz) 726 goto notc; 727 } 728 if (ccom() == 0) 729 goto notc; 730 } 731 check: 732 if (lookup(c) == 1) { 733 while ((ch = fbuf[i]) != ';' && ch != '{') { 734 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 735 len = 1; 736 i += len; 737 if (i >= fbsz) 738 goto notc; 739 } 740 (void) printf(gettext("c program text")); 741 goto outa; 742 } 743 nl = 0; 744 while (fbuf[i] != '(') { 745 if (fbuf[i] <= 0) 746 goto notas; 747 if (fbuf[i] == ';') { 748 i++; 749 goto check; 750 } 751 if (fbuf[i++] == '\n') 752 if (nl++ > 6) 753 goto notc; 754 if (i >= fbsz) 755 goto notc; 756 } 757 while (fbuf[i] != ')') { 758 if (fbuf[i++] == '\n') 759 if (nl++ > 6) 760 goto notc; 761 if (i >= fbsz) 762 goto notc; 763 } 764 while (fbuf[i] != '{') { 765 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 766 len = 1; 767 if (fbuf[i] == '\n') 768 if (nl++ > 6) 769 goto notc; 770 i += len; 771 if (i >= fbsz) 772 goto notc; 773 } 774 (void) printf(gettext("c program text")); 775 goto outa; 776 notc: 777 i = 0; /* reset to begining of file again */ 778 while (fbuf[i] == 'c' || fbuf[i] == 'C'|| fbuf[i] == '!' || 779 fbuf[i] == '*' || fbuf[i] == '\n') { 780 while (fbuf[i++] != '\n') 781 if (i >= fbsz) 782 goto notfort; 783 } 784 if (lookup(fort) == 1) { 785 (void) printf(gettext("fortran program text")); 786 goto outa; 787 } 788 notfort: /* looking for assembler program */ 789 i = 0; /* reset to beginning of file again */ 790 if (ccom() == 0) /* assembler programs may contain */ 791 /* c-style comments */ 792 goto notas; 793 if (ascom() == 0) 794 goto notas; 795 j = i - 1; 796 if (fbuf[i] == '.') { 797 i++; 798 if (lookup(as) == 1) { 799 (void) printf(gettext("assembler program text")); 800 goto outa; 801 } else if (j != -1 && fbuf[j] == '\n' && isalpha(fbuf[j + 2])) { 802 (void) printf( 803 gettext("[nt]roff, tbl, or eqn input text")); 804 goto outa; 805 } 806 } 807 while (lookup(asc) == 0) { 808 if (ccom() == 0) 809 goto notas; 810 if (ascom() == 0) 811 goto notas; 812 while (fbuf[i] != '\n' && fbuf[i++] != ':') { 813 if (i >= fbsz) 814 goto notas; 815 } 816 while (fbuf[i] == '\n' || fbuf[i] == ' ' || fbuf[i] == '\t') 817 if (i++ >= fbsz) 818 goto notas; 819 j = i - 1; 820 if (fbuf[i] == '.') { 821 i++; 822 if (lookup(as) == 1) { 823 (void) printf( 824 gettext("assembler program text")); 825 goto outa; 826 } else if (fbuf[j] == '\n' && isalpha(fbuf[j+2])) { 827 (void) printf( 828 gettext("[nt]roff, tbl, or eqn input " 829 "text")); 830 goto outa; 831 } 832 } 833 } 834 (void) printf(gettext("assembler program text")); 835 goto outa; 836 notas: 837 /* start modification for multibyte env */ 838 IS_ascii = 1; 839 if (fbsz < FBSZ) 840 Max = fbsz; 841 else 842 Max = FBSZ - MB_LEN_MAX; /* prevent cut of wchar read */ 843 /* end modification for multibyte env */ 844 845 for (i = 0; i < Max; /* null */) 846 if (fbuf[i] & 0200) { 847 IS_ascii = 0; 848 if (fbuf[0] == '\100' && fbuf[1] == '\357') { 849 (void) printf(gettext("troff output\n")); 850 return; 851 } 852 /* start modification for multibyte env */ 853 if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX)) 854 <= 0 || !iswprint(wchar)) { 855 (void) printf(gettext("data\n")); 856 return; 857 } 858 i += length; 859 } 860 else 861 i++; 862 i = fbsz; 863 /* end modification for multibyte env */ 864 if (mbuf.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH)) 865 (void) printf(gettext("commands text")); 866 else if (troffint(fbuf, fbsz)) 867 (void) printf(gettext("troff intermediate output text")); 868 else if (english(fbuf, fbsz)) 869 (void) printf(gettext("English text")); 870 else if (IS_ascii) 871 (void) printf(gettext("ascii text")); 872 else 873 (void) printf(gettext("text")); /* for multibyte env */ 874 outa: 875 /* 876 * This code is to make sure that no MB char is cut in half 877 * while still being used. 878 */ 879 fbsz = (fbsz < FBSZ ? fbsz : fbsz - MB_CUR_MAX + 1); 880 while (i < fbsz) { 881 if (isascii(fbuf[i])) { 882 i++; 883 continue; 884 } else { 885 if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX)) 886 <= 0 || !iswprint(wchar)) { 887 (void) printf(gettext(" with garbage\n")); 888 return; 889 } 890 i = i + length; 891 } 892 } 893 (void) printf("\n"); 894 } 895 896 static int 897 troffint(char *bp, int n) 898 { 899 int k; 900 901 i = 0; 902 for (k = 0; k < 6; k++) { 903 if (lookup(troff) == 0) 904 return (0); 905 if (lookup(troff) == 0) 906 return (0); 907 while (i < n && bp[i] != '\n') 908 i++; 909 if (i++ >= n) 910 return (0); 911 } 912 return (1); 913 } 914 915 static void 916 ar_coff_or_aout(int elffd) 917 { 918 Elf *elf; 919 920 /* 921 * Get the files elf descriptor and process it as an elf or 922 * a.out (4.x) file. 923 */ 924 925 elf = elf_begin(elffd, ELF_C_READ, (Elf *)0); 926 switch (elf_kind(elf)) { 927 case ELF_K_AR : 928 (void) printf(gettext(", not a dynamic executable " 929 "or shared object")); 930 break; 931 case ELF_K_COFF: 932 (void) printf(gettext(", unsupported or unknown " 933 "file type")); 934 break; 935 default: 936 /* 937 * This is either an unknown file or an aout format 938 * At this time, we don't print dynamic/stripped 939 * info. on a.out or non-Elf binaries. 940 */ 941 break; 942 } 943 (void) elf_end(elf); 944 } 945 946 947 static void 948 print_elf_type(Elf_Info EI) 949 { 950 switch (EI.type) { 951 case ET_NONE: 952 (void) printf(" %s", gettext("unknown type")); 953 break; 954 case ET_REL: 955 (void) printf(" %s", gettext("relocatable")); 956 break; 957 case ET_EXEC: 958 (void) printf(" %s", gettext("executable")); 959 break; 960 case ET_DYN: 961 (void) printf(" %s", gettext("dynamic lib")); 962 break; 963 default: 964 break; 965 } 966 } 967 968 static void 969 print_elf_machine(int machine) 970 { 971 /* 972 * This table must be kept in sync with the EM_ constants 973 * in /usr/include/sys/elf.h. 974 */ 975 static const char *mach_str[EM_NUM] = { 976 "unknown machine", /* 0 - EM_NONE */ 977 "WE32100", /* 1 - EM_M32 */ 978 "SPARC", /* 2 - EM_SPARC */ 979 "80386", /* 3 - EM_386 */ 980 "M68000", /* 4 - EM_68K */ 981 "M88000", /* 5 - EM_88K */ 982 "80486", /* 6 - EM_486 */ 983 "i860", /* 7 - EM_860 */ 984 "MIPS RS3000 Big-Endian", /* 8 - EM_MIPS */ 985 "S/370", /* 9 - EM_S370 */ 986 "MIPS RS3000 Little-Endian", /* 10 - EM_MIPS_RS3_LE */ 987 "MIPS RS6000", /* 11 - EM_RS6000 */ 988 NULL, /* 12 - EM_UNKNOWN12 */ 989 NULL, /* 13 - EM_UNKNOWN13 */ 990 NULL, /* 14 - EM_UNKNOWN14 */ 991 "PA-RISC", /* 15 - EM_PA_RISC */ 992 "nCUBE", /* 16 - EM_nCUBE */ 993 "VPP500", /* 17 - EM_VPP500 */ 994 "SPARC32PLUS", /* 18 - EM_SPARC32PLUS */ 995 "i960", /* 19 - EM_960 */ 996 "PowerPC", /* 20 - EM_PPC */ 997 "PowerPC64", /* 21 - EM_PPC64 */ 998 "S/390", /* 22 - EM_S390 */ 999 NULL, /* 23 - EM_UNKNOWN23 */ 1000 NULL, /* 24 - EM_UNKNOWN24 */ 1001 NULL, /* 25 - EM_UNKNOWN25 */ 1002 NULL, /* 26 - EM_UNKNOWN26 */ 1003 NULL, /* 27 - EM_UNKNOWN27 */ 1004 NULL, /* 28 - EM_UNKNOWN28 */ 1005 NULL, /* 29 - EM_UNKNOWN29 */ 1006 NULL, /* 30 - EM_UNKNOWN30 */ 1007 NULL, /* 31 - EM_UNKNOWN31 */ 1008 NULL, /* 32 - EM_UNKNOWN32 */ 1009 NULL, /* 33 - EM_UNKNOWN33 */ 1010 NULL, /* 34 - EM_UNKNOWN34 */ 1011 NULL, /* 35 - EM_UNKNOWN35 */ 1012 "V800", /* 36 - EM_V800 */ 1013 "FR20", /* 37 - EM_FR20 */ 1014 "RH32", /* 38 - EM_RH32 */ 1015 "RCE", /* 39 - EM_RCE */ 1016 "ARM", /* 40 - EM_ARM */ 1017 "Alpha", /* 41 - EM_ALPHA */ 1018 "S/390", /* 42 - EM_SH */ 1019 "SPARCV9", /* 43 - EM_SPARCV9 */ 1020 "Tricore", /* 44 - EM_TRICORE */ 1021 "ARC", /* 45 - EM_ARC */ 1022 "H8/300", /* 46 - EM_H8_300 */ 1023 "H8/300H", /* 47 - EM_H8_300H */ 1024 "H8S", /* 48 - EM_H8S */ 1025 "H8/500", /* 49 - EM_H8_500 */ 1026 "IA64", /* 50 - EM_IA_64 */ 1027 "MIPS-X", /* 51 - EM_MIPS_X */ 1028 "Coldfire", /* 52 - EM_COLDFIRE */ 1029 "M68HC12", /* 53 - EM_68HC12 */ 1030 "MMA", /* 54 - EM_MMA */ 1031 "PCP", /* 55 - EM_PCP */ 1032 "nCPU", /* 56 - EM_NCPU */ 1033 "NDR1", /* 57 - EM_NDR1 */ 1034 "Starcore", /* 58 - EM_STARCORE */ 1035 "ME16", /* 59 - EM_ME16 */ 1036 "ST100", /* 60 - EM_ST100 */ 1037 "TINYJ", /* 61 - EM_TINYJ */ 1038 "AMD64", /* 62 - EM_AMD64 */ 1039 "PDSP", /* 63 - EM_PDSP */ 1040 NULL, /* 64 - EM_UNKNOWN64 */ 1041 NULL, /* 65 - EM_UNKNOWN65 */ 1042 "FX66", /* 66 - EM_FX66 */ 1043 "ST9 PLUS", /* 67 - EM_ST9PLUS */ 1044 "ST7", /* 68 - EM_ST7 */ 1045 "68HC16", /* 69 - EM_68HC16 */ 1046 "68HC11", /* 70 - EM_68HC11 */ 1047 "68H08", /* 71 - EM_68HC08 */ 1048 "68HC05", /* 72 - EM_68HC05 */ 1049 "SVX", /* 73 - EM_SVX */ 1050 "ST19", /* 74 - EM_ST19 */ 1051 "VAX", /* 75 - EM_VAX */ 1052 "CRIS", /* 76 - EM_CRIS */ 1053 "Javelin", /* 77 - EM_JAVELIN */ 1054 "Firepath", /* 78 - EM_FIREPATH */ 1055 "ZSP", /* 79 - EM_ZSP */ 1056 "MMIX", /* 80 - EM_MMIX */ 1057 "HUANY", /* 81 - EM_HUANY */ 1058 "Prism", /* 82 - EM_PRISM */ 1059 "AVR", /* 83 - EM_AVR */ 1060 "FR30", /* 84 - EM_FR30 */ 1061 "D10V", /* 85 - EM_D10V */ 1062 "D30V", /* 86 - EM_D30V */ 1063 "V850", /* 87 - EM_V850 */ 1064 "M32R", /* 88 - EM_M32R */ 1065 "MN10300", /* 89 - EM_MN10300 */ 1066 "MN10200", /* 90 - EM_MN10200 */ 1067 "picoJava", /* 91 - EM_PJ */ 1068 "OpenRISC", /* 92 - EM_OPENRISC */ 1069 "Tangent-A5", /* 93 - EM_ARC_A5 */ 1070 "Xtensa" /* 94 - EM_XTENSA */ 1071 }; 1072 /* If new machine is added, refuse to compile until we're updated */ 1073 #if EM_NUM != 95 1074 #error "Number of known ELF machine constants has changed" 1075 #endif 1076 1077 const char *str; 1078 1079 if ((machine < EM_NONE) || (machine >= EM_NUM)) 1080 machine = EM_NONE; 1081 1082 str = mach_str[machine]; 1083 if (str) 1084 (void) printf(" %s", str); 1085 } 1086 1087 static void 1088 print_elf_datatype(int datatype) 1089 { 1090 switch (datatype) { 1091 case ELFDATA2LSB: 1092 (void) printf(" LSB"); 1093 break; 1094 case ELFDATA2MSB: 1095 (void) printf(" MSB"); 1096 break; 1097 default: 1098 break; 1099 } 1100 } 1101 1102 static void 1103 print_elf_class(int class) 1104 { 1105 switch (class) { 1106 case ELFCLASS32: 1107 (void) printf(" %s", gettext("32-bit")); 1108 break; 1109 case ELFCLASS64: 1110 (void) printf(" %s", gettext("64-bit")); 1111 break; 1112 default: 1113 break; 1114 } 1115 } 1116 1117 static void 1118 print_elf_flags(Elf_Info EI) 1119 { 1120 unsigned int flags; 1121 1122 flags = EI.flags; 1123 switch (EI.machine) { 1124 case EM_SPARCV9: 1125 if (flags & EF_SPARC_EXT_MASK) { 1126 if (flags & EF_SPARC_SUN_US3) { 1127 (void) printf("%s", gettext( 1128 ", UltraSPARC3 Extensions Required")); 1129 } else if (flags & EF_SPARC_SUN_US1) { 1130 (void) printf("%s", gettext( 1131 ", UltraSPARC1 Extensions Required")); 1132 } 1133 if (flags & EF_SPARC_HAL_R1) 1134 (void) printf("%s", gettext( 1135 ", HaL R1 Extensions Required")); 1136 } 1137 break; 1138 case EM_SPARC32PLUS: 1139 if (flags & EF_SPARC_32PLUS) 1140 (void) printf("%s", gettext(", V8+ Required")); 1141 if (flags & EF_SPARC_SUN_US3) { 1142 (void) printf("%s", 1143 gettext(", UltraSPARC3 Extensions Required")); 1144 } else if (flags & EF_SPARC_SUN_US1) { 1145 (void) printf("%s", 1146 gettext(", UltraSPARC1 Extensions Required")); 1147 } 1148 if (flags & EF_SPARC_HAL_R1) 1149 (void) printf("%s", 1150 gettext(", HaL R1 Extensions Required")); 1151 break; 1152 default: 1153 break; 1154 } 1155 } 1156 1157 /* 1158 * check_ident: checks the ident field of the presumeably 1159 * elf file. If check fails, this is not an 1160 * elf file. 1161 */ 1162 static int 1163 check_ident(unsigned char *ident, int fd) 1164 { 1165 int class; 1166 if (pread64(fd, ident, EI_NIDENT, 0) != EI_NIDENT) 1167 return (ELF_READ_FAIL); 1168 class = ident[EI_CLASS]; 1169 if (class != ELFCLASS32 && class != ELFCLASS64) 1170 return (ELF_READ_FAIL); 1171 if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 1172 ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) 1173 return (ELF_READ_FAIL); 1174 1175 return (ELF_READ_OKAY); 1176 } 1177 1178 static int 1179 elf_check(char *file) 1180 { 1181 Elf_Info EInfo; 1182 int class, version, format; 1183 unsigned char ident[EI_NIDENT]; 1184 1185 (void) memset(&EInfo, 0, sizeof (Elf_Info)); 1186 EInfo.file = file; 1187 1188 /* 1189 * Verify information in file indentifier. 1190 * Return quietly if not elf; Different type of file. 1191 */ 1192 if (check_ident(ident, elffd) == ELF_READ_FAIL) 1193 return (1); 1194 1195 /* 1196 * Read the elf headers for processing and get the 1197 * get the needed information in Elf_Info struct. 1198 */ 1199 class = ident[EI_CLASS]; 1200 if (class == ELFCLASS32) { 1201 if (elf_read32(elffd, &EInfo) == ELF_READ_FAIL) { 1202 (void) fprintf(stderr, gettext("%s: %s: can't " 1203 "read ELF header\n"), File, file); 1204 return (1); 1205 } 1206 } else if (class == ELFCLASS64) { 1207 if (elf_read64(elffd, &EInfo) == ELF_READ_FAIL) { 1208 (void) fprintf(stderr, gettext("%s: %s: can't " 1209 "read ELF header\n"), File, file); 1210 return (1); 1211 } 1212 } else { 1213 /* something wrong */ 1214 return (1); 1215 } 1216 1217 /* version not in ident then 1 */ 1218 version = ident[EI_VERSION] ? ident[EI_VERSION] : 1; 1219 1220 format = ident[EI_DATA]; 1221 (void) printf("%s", gettext("ELF")); 1222 print_elf_class(class); 1223 print_elf_datatype(format); 1224 print_elf_type(EInfo); 1225 1226 if (EInfo.core_type != EC_NOTCORE) { 1227 /* Print what kind of core is this */ 1228 if (EInfo.core_type == EC_OLDCORE) 1229 (void) printf(" %s", gettext("pre-2.6 core file")); 1230 else 1231 (void) printf(" %s", gettext("core file")); 1232 } 1233 1234 /* Print machine info */ 1235 print_elf_machine(EInfo.machine); 1236 1237 /* Print Version */ 1238 if (version == 1) 1239 (void) printf(" %s %d", gettext("Version"), version); 1240 1241 /* Print Flags */ 1242 print_elf_flags(EInfo); 1243 1244 /* Last bit, if it is a core */ 1245 if (EInfo.core_type != EC_NOTCORE) { 1246 /* Print the program name that dumped this core */ 1247 (void) printf(gettext(", from '%s'"), EInfo.fname); 1248 return (0); 1249 } 1250 1251 /* Print Capabilities */ 1252 if (EInfo.cap_str[0] != '\0') 1253 (void) printf(" [%s]", EInfo.cap_str); 1254 1255 if ((EInfo.type != ET_EXEC) && (EInfo.type != ET_DYN)) 1256 return (0); 1257 1258 /* Print if it is dynamically linked */ 1259 if (EInfo.dynamic) 1260 (void) printf(gettext(", dynamically linked")); 1261 else 1262 (void) printf(gettext(", statically linked")); 1263 1264 /* Printf it it is stripped */ 1265 if (EInfo.stripped & E_SYMTAB) { 1266 (void) printf(gettext(", not stripped")); 1267 if (!(EInfo.stripped & E_DBGINF)) { 1268 (void) printf(gettext( 1269 ", no debugging information available")); 1270 } 1271 } else { 1272 (void) printf(gettext(", stripped")); 1273 } 1274 1275 return (0); 1276 } 1277 1278 /* 1279 * is_rtld_config - If file is a runtime linker config file, prints 1280 * the description and returns True (1). Otherwise, silently returns 1281 * False (0). 1282 */ 1283 int 1284 is_rtld_config(void) 1285 { 1286 Rtc_id *id; 1287 1288 if ((fbsz >= sizeof (*id)) && RTC_ID_TEST(fbuf)) { 1289 (void) printf(gettext("Runtime Linking Configuration")); 1290 id = (Rtc_id *) fbuf; 1291 print_elf_class(id->id_class); 1292 print_elf_datatype(id->id_data); 1293 print_elf_machine(id->id_machine); 1294 (void) printf("\n"); 1295 return (1); 1296 } 1297 1298 return (0); 1299 } 1300 1301 /* 1302 * lookup - 1303 * Attempts to match one of the strings from a list, 'tab', 1304 * with what is in the file, starting at the current index position 'i'. 1305 * Looks past any initial whitespace and expects whitespace or other 1306 * delimiting characters to follow the matched string. 1307 * A match identifies the file as being 'assembler', 'fortran', 'c', etc. 1308 * Returns 1 for a successful match, 0 otherwise. 1309 */ 1310 static int 1311 lookup(char **tab) 1312 { 1313 register char r; 1314 register int k, j, l; 1315 1316 while (fbuf[i] == ' ' || fbuf[i] == '\t' || fbuf[i] == '\n') 1317 i++; 1318 for (j = 0; tab[j] != 0; j++) { 1319 l = 0; 1320 for (k = i; ((r = tab[j][l++]) == fbuf[k] && r != '\0'); k++) 1321 ; 1322 if (r == '\0') 1323 if (fbuf[k] == ' ' || fbuf[k] == '\n' || 1324 fbuf[k] == '\t' || fbuf[k] == '{' || 1325 fbuf[k] == '/') { 1326 i = k; 1327 return (1); 1328 } 1329 } 1330 return (0); 1331 } 1332 1333 /* 1334 * ccom - 1335 * Increments the current index 'i' into the file buffer 'fbuf' past any 1336 * whitespace lines and C-style comments found, starting at the current 1337 * position of 'i'. Returns 1 as long as we don't increment i past the 1338 * size of fbuf (fbsz). Otherwise, returns 0. 1339 */ 1340 1341 static int 1342 ccom(void) 1343 { 1344 register char cc; 1345 int len; 1346 1347 while ((cc = fbuf[i]) == ' ' || cc == '\t' || cc == '\n') 1348 if (i++ >= fbsz) 1349 return (0); 1350 if (fbuf[i] == '/' && fbuf[i+1] == '*') { 1351 i += 2; 1352 while (fbuf[i] != '*' || fbuf[i+1] != '/') { 1353 if (fbuf[i] == '\\') 1354 i++; 1355 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 1356 len = 1; 1357 i += len; 1358 if (i >= fbsz) 1359 return (0); 1360 } 1361 if ((i += 2) >= fbsz) 1362 return (0); 1363 } 1364 if (fbuf[i] == '\n') 1365 if (ccom() == 0) 1366 return (0); 1367 return (1); 1368 } 1369 1370 /* 1371 * ascom - 1372 * Increments the current index 'i' into the file buffer 'fbuf' past 1373 * consecutive assembler program comment lines starting with ASCOMCHAR, 1374 * starting at the current position of 'i'. 1375 * Returns 1 as long as we don't increment i past the 1376 * size of fbuf (fbsz). Otherwise returns 0. 1377 */ 1378 1379 static int 1380 ascom(void) 1381 { 1382 while (fbuf[i] == ASCOMCHAR) { 1383 i++; 1384 while (fbuf[i++] != '\n') 1385 if (i >= fbsz) 1386 return (0); 1387 while (fbuf[i] == '\n') 1388 if (i++ >= fbsz) 1389 return (0); 1390 } 1391 return (1); 1392 } 1393 1394 static int 1395 sccs(void) 1396 { /* look for "1hddddd" where d is a digit */ 1397 register int j; 1398 1399 if (fbuf[0] == 1 && fbuf[1] == 'h') { 1400 for (j = 2; j <= 6; j++) { 1401 if (isdigit(fbuf[j])) 1402 continue; 1403 else 1404 return (0); 1405 } 1406 } else { 1407 return (0); 1408 } 1409 return (1); 1410 } 1411 1412 static int 1413 english(char *bp, int n) 1414 { 1415 #define NASC 128 /* number of ascii char ?? */ 1416 register int j, vow, freq, rare, len; 1417 register int badpun = 0, punct = 0; 1418 int ct[NASC]; 1419 1420 if (n < 50) 1421 return (0); /* no point in statistics on squibs */ 1422 for (j = 0; j < NASC; j++) 1423 ct[j] = 0; 1424 for (j = 0; j < n; j += len) { 1425 if ((unsigned char)bp[j] < NASC) 1426 ct[bp[j]|040]++; 1427 switch (bp[j]) { 1428 case '.': 1429 case ',': 1430 case ')': 1431 case '%': 1432 case ';': 1433 case ':': 1434 case '?': 1435 punct++; 1436 if (j < n-1 && bp[j+1] != ' ' && bp[j+1] != '\n') 1437 badpun++; 1438 } 1439 if ((len = mblen(&bp[j], MB_CUR_MAX)) <= 0) 1440 len = 1; 1441 } 1442 if (badpun*5 > punct) 1443 return (0); 1444 vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 1445 freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 1446 rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 1447 if (2*ct[';'] > ct['e']) 1448 return (0); 1449 if ((ct['>'] + ct['<'] + ct['/']) > ct['e']) 1450 return (0); /* shell file test */ 1451 return (vow * 5 >= n - ct[' '] && freq >= 10 * rare); 1452 } 1453 1454 1455 static int 1456 shellscript(char buf[], struct stat64 *sb) 1457 { 1458 char *tp, *cp, *xp, *up, *gp; 1459 1460 cp = strchr(buf, '\n'); 1461 if (cp == NULL || cp - fbuf > fbsz) 1462 return (0); 1463 for (tp = buf; tp != cp && isspace((unsigned char)*tp); tp++) 1464 if (!isascii(*tp)) 1465 return (0); 1466 for (xp = tp; tp != cp && !isspace((unsigned char)*tp); tp++) 1467 if (!isascii(*tp)) 1468 return (0); 1469 if (tp == xp) 1470 return (0); 1471 if (sb->st_mode & S_ISUID) 1472 up = gettext("set-uid "); 1473 else 1474 up = ""; 1475 1476 if (sb->st_mode & S_ISGID) 1477 gp = gettext("set-gid "); 1478 else 1479 gp = ""; 1480 1481 if (strncmp(xp, "/bin/sh", tp - xp) == 0) 1482 xp = gettext("shell"); 1483 else if (strncmp(xp, "/bin/csh", tp - xp) == 0) 1484 xp = gettext("c-shell"); 1485 else if (strncmp(xp, "/usr/sbin/dtrace", tp - xp) == 0) 1486 xp = gettext("DTrace"); 1487 else 1488 *tp = '\0'; 1489 /* 1490 * TRANSLATION_NOTE 1491 * This message is printed by file command for shell scripts. 1492 * The first %s is for the translation for "set-uid " (if the script 1493 * has the set-uid bit set), or is for an empty string (if the 1494 * script does not have the set-uid bit set). 1495 * Similarly, the second %s is for the translation for "set-gid ", 1496 * or is for an empty string. 1497 * The third %s is for the translation for either: "shell", "c-shell", 1498 * or "DTrace", or is for the pathname of the program the script 1499 * executes. 1500 */ 1501 (void) printf(gettext("%s%sexecutable %s script\n"), up, gp, xp); 1502 return (1); 1503 } 1504 1505 static int 1506 get_door_target(char *file, char *buf, size_t bufsize) 1507 { 1508 int fd; 1509 door_info_t di; 1510 psinfo_t psinfo; 1511 1512 if ((fd = open64(file, O_RDONLY)) < 0 || 1513 door_info(fd, &di) != 0) { 1514 if (fd >= 0) 1515 (void) close(fd); 1516 return (-1); 1517 } 1518 (void) close(fd); 1519 1520 (void) sprintf(buf, "/proc/%ld/psinfo", di.di_target); 1521 if ((fd = open64(buf, O_RDONLY)) < 0 || 1522 read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) { 1523 if (fd >= 0) 1524 (void) close(fd); 1525 return (-1); 1526 } 1527 (void) close(fd); 1528 1529 (void) snprintf(buf, bufsize, "%s[%ld]", psinfo.pr_fname, di.di_target); 1530 return (0); 1531 } 1532 1533 /* 1534 * ZIP file header information 1535 */ 1536 #define SIGSIZ 4 1537 #define LOCSIG "PK\003\004" 1538 #define LOCHDRSIZ 30 1539 1540 #define CH(b, n) (((unsigned char *)(b))[n]) 1541 #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) 1542 #define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) 1543 1544 #define LOCNAM(b) (SH(b, 26)) /* filename size */ 1545 #define LOCEXT(b) (SH(b, 28)) /* extra field size */ 1546 1547 #define XFHSIZ 4 /* header id, data size */ 1548 #define XFHID(b) (SH(b, 0)) /* extract field header id */ 1549 #define XFDATASIZ(b) (SH(b, 2)) /* extract field data size */ 1550 #define XFJAVASIG 0xcafe /* java executables */ 1551 1552 static int 1553 zipfile(char *fbuf, int fd) 1554 { 1555 off_t xoff, xoff_end; 1556 1557 if (strncmp(fbuf, LOCSIG, SIGSIZ) != 0) 1558 return (0); 1559 1560 xoff = LOCHDRSIZ + LOCNAM(fbuf); 1561 xoff_end = xoff + LOCEXT(fbuf); 1562 1563 while (xoff < xoff_end) { 1564 char xfhdr[XFHSIZ]; 1565 1566 if (pread(fd, xfhdr, XFHSIZ, xoff) != XFHSIZ) 1567 break; 1568 1569 if (XFHID(xfhdr) == XFJAVASIG) { 1570 (void) printf("%s\n", gettext("java archive file")); 1571 return (1); 1572 } 1573 xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr); 1574 } 1575 1576 /* 1577 * We could just print "ZIP archive" here. 1578 * 1579 * However, customers may be using their own entries in 1580 * /etc/magic to distinguish one kind of ZIP file from another, so 1581 * let's defer the printing of "ZIP archive" to there. 1582 */ 1583 return (0); 1584 } 1585 1586 static int 1587 is_crash_dump(const char *buf, int fd) 1588 { 1589 /* LINTED: pointer cast may result in improper alignment */ 1590 const dumphdr_t *dhp = (const dumphdr_t *)buf; 1591 1592 /* 1593 * The current DUMP_MAGIC string covers Solaris 7 and later releases. 1594 * The utsname struct is only present in dumphdr_t's with dump_version 1595 * greater than or equal to 9. 1596 */ 1597 if (dhp->dump_magic == DUMP_MAGIC) { 1598 print_dumphdr(fd, dhp, return_uint32, NATIVE_ISA); 1599 1600 } else if (dhp->dump_magic == swap_uint32(DUMP_MAGIC)) { 1601 print_dumphdr(fd, dhp, swap_uint32, OTHER_ISA); 1602 1603 } else if (dhp->dump_magic == OLD_DUMP_MAGIC || 1604 dhp->dump_magic == swap_uint32(OLD_DUMP_MAGIC)) { 1605 char *isa = (dhp->dump_magic == OLD_DUMP_MAGIC ? 1606 NATIVE_ISA : OTHER_ISA); 1607 (void) printf(gettext("SunOS 32-bit %s crash dump\n"), isa); 1608 1609 } else { 1610 return (0); 1611 } 1612 1613 return (1); 1614 } 1615 1616 static void 1617 print_dumphdr(const int fd, const dumphdr_t *dhp, uint32_t (*swap)(uint32_t), 1618 const char *isa) 1619 { 1620 dumphdr_t dh; 1621 1622 /* 1623 * A dumphdr_t is bigger than FBSZ, so we have to manually read the 1624 * rest of it. 1625 */ 1626 if (swap(dhp->dump_version) > 8 && pread(fd, &dh, sizeof (dumphdr_t), 1627 (off_t)0) == sizeof (dumphdr_t)) { 1628 const char *c = swap(dh.dump_flags) & DF_COMPRESSED ? 1629 "compressed " : ""; 1630 const char *l = swap(dh.dump_flags) & DF_LIVE ? 1631 "live" : "crash"; 1632 1633 (void) printf(gettext( 1634 "%s %s %s %u-bit %s %s%s dump from '%s'\n"), 1635 dh.dump_utsname.sysname, dh.dump_utsname.release, 1636 dh.dump_utsname.version, swap(dh.dump_wordsize), isa, 1637 c, l, dh.dump_utsname.nodename); 1638 } else { 1639 (void) printf(gettext("SunOS %u-bit %s crash dump\n"), 1640 swap(dhp->dump_wordsize), isa); 1641 } 1642 } 1643 1644 static void 1645 usage(void) 1646 { 1647 (void) fprintf(stderr, gettext( 1648 "usage: file [-dh] [-M mfile] [-m mfile] [-f ffile] file ...\n" 1649 " file [-dh] [-M mfile] [-m mfile] -f ffile\n" 1650 " file -i [-h] [-f ffile] file ...\n" 1651 " file -i [-h] -f ffile\n" 1652 " file -c [-d] [-M mfile] [-m mfile]\n")); 1653 exit(2); 1654 } 1655 1656 static uint32_t 1657 swap_uint32(uint32_t in) 1658 { 1659 uint32_t out; 1660 1661 out = (in & 0x000000ff) << 24; 1662 out |= (in & 0x0000ff00) << 8; /* >> 8 << 16 */ 1663 out |= (in & 0x00ff0000) >> 8; /* >> 16 << 8 */ 1664 out |= (in & 0xff000000) >> 24; 1665 1666 return (out); 1667 } 1668 1669 static uint32_t 1670 return_uint32(uint32_t in) 1671 { 1672 return (in); 1673 } 1674 1675 /* 1676 * Check if str is in the string list str_list. 1677 */ 1678 int 1679 is_in_list(char *str) 1680 { 1681 int i; 1682 1683 /* 1684 * Only need to compare the strlen(str_list[i]) bytes. 1685 * That way .stab will match on .stab* sections, and 1686 * .debug will match on .debug* sections. 1687 */ 1688 for (i = 0; debug_sections[i] != NULL; i++) { 1689 if (strncmp(debug_sections[i], str, 1690 strlen(debug_sections[i])) == 0) { 1691 return (1); 1692 } 1693 } 1694 return (0); 1695 } 1696 1697 /* 1698 * default_magic - 1699 * allocate space for and create the default magic file 1700 * name string. 1701 */ 1702 1703 static void 1704 default_magic(void) 1705 { 1706 const char *msg_locale = setlocale(LC_MESSAGES, NULL); 1707 struct stat statbuf; 1708 1709 if ((dfile = malloc(strlen(msg_locale) + 35)) == NULL) { 1710 int err = errno; 1711 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 1712 File, strerror(err)); 1713 exit(2); 1714 } 1715 (void) snprintf(dfile, strlen(msg_locale) + 35, 1716 "/usr/lib/locale/%s/LC_MESSAGES/magic", msg_locale); 1717 if (stat(dfile, &statbuf) != 0) { 1718 (void) strcpy(dfile, "/etc/magic"); 1719 } 1720 } 1721 1722 /* 1723 * add_to_mlist - 1724 * Add the given magic_file filename string to the list of magic 1725 * files (mlist). This list of files will later be examined, and 1726 * each magic file's entries will be added in order to 1727 * the mtab table. 1728 * 1729 * The first flag is set to 1 to add to the first list, mlist1. 1730 * The first flag is set to 0 to add to the second list, mlist2. 1731 */ 1732 1733 static void 1734 add_to_mlist(char *magic_file, int first) 1735 { 1736 char **mlist; /* ordered list of magic files */ 1737 size_t mlist_sz; /* number of pointers allocated for mlist */ 1738 char **mlistp; /* next entry in mlist */ 1739 size_t mlistp_off; 1740 1741 if (first) { 1742 mlist = mlist1; 1743 mlist_sz = mlist1_sz; 1744 mlistp = mlist1p; 1745 } else { 1746 mlist = mlist2; 1747 mlist_sz = mlist2_sz; 1748 mlistp = mlist2p; 1749 } 1750 1751 if (mlist == NULL) { /* initial mlist allocation */ 1752 if ((mlist = calloc(MLIST_SZ, sizeof (char *))) == NULL) { 1753 int err = errno; 1754 (void) fprintf(stderr, gettext("%s: malloc " 1755 "failed: %s\n"), File, strerror(err)); 1756 exit(2); 1757 } 1758 mlist_sz = MLIST_SZ; 1759 mlistp = mlist; 1760 } 1761 if ((mlistp - mlist) >= mlist_sz) { 1762 mlistp_off = mlistp - mlist; 1763 mlist_sz *= 2; 1764 if ((mlist = realloc(mlist, 1765 mlist_sz * sizeof (char *))) == NULL) { 1766 int err = errno; 1767 (void) fprintf(stderr, gettext("%s: malloc " 1768 "failed: %s\n"), File, strerror(err)); 1769 exit(2); 1770 } 1771 mlistp = mlist + mlistp_off; 1772 } 1773 /* 1774 * now allocate memory for and copy the 1775 * magic file name string 1776 */ 1777 if ((*mlistp = malloc(strlen(magic_file) + 1)) == NULL) { 1778 int err = errno; 1779 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 1780 File, strerror(err)); 1781 exit(2); 1782 } 1783 (void) strlcpy(*mlistp, magic_file, strlen(magic_file) + 1); 1784 mlistp++; 1785 1786 if (first) { 1787 mlist1 = mlist; 1788 mlist1_sz = mlist_sz; 1789 mlist1p = mlistp; 1790 } else { 1791 mlist2 = mlist; 1792 mlist2_sz = mlist_sz; 1793 mlist2p = mlistp; 1794 } 1795 } 1796 1797 static void 1798 fd_cleanup(void) 1799 { 1800 if (ifd != -1) { 1801 (void) close(ifd); 1802 ifd = -1; 1803 } 1804 if (elffd != -1) { 1805 (void) close(elffd); 1806 elffd = -1; 1807 } 1808 }