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