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