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 switch (machine) { 985 case EM_NONE: 986 (void) printf(" %s", gettext("unknown machine")); 987 break; 988 case EM_M32: 989 (void) printf(" %s", gettext("WE32100")); 990 break; 991 case EM_SPARC: 992 (void) printf(" %s", gettext("SPARC")); 993 break; 994 case EM_386: 995 (void) printf(" %s", gettext("80386")); 996 break; 997 case EM_68K: 998 (void) printf(" %s", gettext("M68000")); 999 break; 1000 case EM_88K: 1001 (void) printf(" %s", gettext("M88000")); 1002 break; 1003 case EM_486: 1004 (void) printf(" %s", gettext("80486")); 1005 break; 1006 case EM_860: 1007 (void) printf(" %s", gettext("i860")); 1008 break; 1009 case EM_MIPS: 1010 (void) printf(" %s", gettext("MIPS RS3000 Big-Endian")); 1011 break; 1012 case EM_MIPS_RS3_LE: 1013 (void) printf(" %s", gettext("MIPS RS3000 Little-Endian")); 1014 break; 1015 case EM_RS6000: 1016 (void) printf(" %s", gettext("MIPS RS6000")); 1017 break; 1018 case EM_PA_RISC: 1019 (void) printf(" %s", gettext("PA-RISC")); 1020 break; 1021 case EM_nCUBE: 1022 (void) printf(" %s", gettext("nCUBE")); 1023 break; 1024 case EM_VPP500: 1025 (void) printf(" %s", gettext("VPP500")); 1026 break; 1027 case EM_SPARC32PLUS: 1028 (void) printf(" %s", gettext("SPARC32PLUS")); 1029 break; 1030 case EM_PPC: 1031 (void) printf(" %s", gettext("PowerPC")); 1032 break; 1033 case EM_SPARCV9: 1034 (void) printf(" %s", gettext("SPARCV9")); 1035 break; 1036 case EM_IA_64: 1037 (void) printf(" %s", gettext("IA64")); 1038 break; 1039 case EM_AMD64: 1040 (void) printf(" %s", gettext("AMD64")); 1041 break; 1042 default: 1043 break; 1044 } 1045 } 1046 1047 static void 1048 print_elf_datatype(int datatype) 1049 { 1050 switch (datatype) { 1051 case ELFDATA2LSB: 1052 (void) printf(" %s", gettext("LSB")); 1053 break; 1054 case ELFDATA2MSB: 1055 (void) printf(" %s", gettext("MSB")); 1056 break; 1057 default: 1058 break; 1059 } 1060 } 1061 1062 static void 1063 print_elf_class(int class) 1064 { 1065 switch (class) { 1066 case ELFCLASS32: 1067 (void) printf(" %s", gettext("32-bit")); 1068 break; 1069 case ELFCLASS64: 1070 (void) printf(" %s", gettext("64-bit")); 1071 break; 1072 default: 1073 break; 1074 } 1075 } 1076 1077 static void 1078 print_elf_flags(int machine, unsigned int flags) 1079 { 1080 switch (machine) { 1081 case EM_SPARCV9: 1082 if (flags & EF_SPARC_EXT_MASK) { 1083 if (flags & EF_SPARC_SUN_US3) { 1084 (void) printf("%s", gettext( 1085 ", UltraSPARC3 Extensions Required")); 1086 } else if (flags & EF_SPARC_SUN_US1) { 1087 (void) printf("%s", gettext( 1088 ", UltraSPARC1 Extensions Required")); 1089 } 1090 if (flags & EF_SPARC_HAL_R1) 1091 (void) printf("%s", gettext( 1092 ", HaL R1 Extensions Required")); 1093 } 1094 break; 1095 case EM_SPARC32PLUS: 1096 if (flags & EF_SPARC_32PLUS) 1097 (void) printf("%s", gettext(", V8+ Required")); 1098 if (flags & EF_SPARC_SUN_US3) { 1099 (void) printf("%s", 1100 gettext(", UltraSPARC3 Extensions Required")); 1101 } else if (flags & EF_SPARC_SUN_US1) { 1102 (void) printf("%s", 1103 gettext(", UltraSPARC1 Extensions Required")); 1104 } 1105 if (flags & EF_SPARC_HAL_R1) 1106 (void) printf("%s", 1107 gettext(", HaL R1 Extensions Required")); 1108 break; 1109 default: 1110 break; 1111 } 1112 } 1113 1114 static int 1115 print_cap(Elf *elf, GElf_Ehdr *ehdr) 1116 { 1117 Elf_Scn *scn = 0; 1118 1119 /* 1120 * Traverse the files sections to see if any software/hardware 1121 * capabilities are available. 1122 */ 1123 while ((scn = elf_nextscn(elf, scn)) != 0) { 1124 GElf_Word ndx, capn; 1125 GElf_Shdr shdr; 1126 Elf_Data *data; 1127 1128 if (gelf_getshdr(scn, &shdr) == 0) { 1129 (void) fprintf(stderr, 1130 gettext("can't read ELF section header\n")); 1131 return (1); 1132 } 1133 if (shdr.sh_type != SHT_SUNW_cap) 1134 continue; 1135 1136 /* 1137 * Get the data associated with the .cap section. 1138 */ 1139 if ((data = elf_getdata(scn, 0)) == 0) { 1140 (void) fprintf(stderr, 1141 gettext("can't read ELF section data\n")); 1142 return (1); 1143 } 1144 1145 capn = (GElf_Word)(shdr.sh_size / shdr.sh_entsize); 1146 for (ndx = 0; ndx < capn; ndx++) { 1147 char str[100]; 1148 GElf_Cap cap; 1149 1150 if (gelf_getcap(data, ndx, &cap) == NULL) { 1151 (void) fprintf(stderr, 1152 gettext("can't read capabilities data\n")); 1153 return (1); 1154 } 1155 if (cap.c_tag != CA_SUNW_NULL) { 1156 (void) cap_val2str(cap.c_tag, cap.c_un.c_val, 1157 str, sizeof (str), 0, ehdr->e_machine); 1158 (void) printf(" [%s]", str); 1159 } 1160 } 1161 } 1162 return (0); 1163 } 1164 1165 static int 1166 elf_check(Elf *elf) 1167 { 1168 GElf_Ehdr ehdr; 1169 GElf_Phdr phdr; 1170 int dynamic, cnt; 1171 char *ident; 1172 size_t size; 1173 1174 /* 1175 * verify information in file header 1176 */ 1177 if (gelf_getehdr(elf, &ehdr) == (GElf_Ehdr *)0) { 1178 (void) fprintf(stderr, gettext("can't read ELF header\n")); 1179 return (1); 1180 } 1181 ident = elf_getident(elf, &size); 1182 (void) printf("%s", gettext("ELF")); 1183 print_elf_class(ident[EI_CLASS]); 1184 print_elf_datatype(ident[EI_DATA]); 1185 print_elf_type(elf, &ehdr, ident[EI_DATA]); 1186 print_elf_machine(ehdr.e_machine); 1187 if (ehdr.e_version == 1) 1188 (void) printf(" %s %d", 1189 gettext("Version"), (int)ehdr.e_version); 1190 print_elf_flags(ehdr.e_machine, ehdr.e_flags); 1191 1192 if (core(elf, &ehdr, ident[EI_DATA])) /* check for core file */ 1193 return (0); 1194 1195 if (print_cap(elf, &ehdr)) 1196 return (1); 1197 1198 /* 1199 * check type 1200 */ 1201 if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) 1202 return (1); 1203 1204 /* 1205 * read program header and check for dynamic section 1206 */ 1207 if (ehdr.e_phnum == 0) { 1208 (void) fprintf(stderr, gettext("can't read program header\n")); 1209 return (1); 1210 } 1211 1212 for (dynamic = 0, cnt = 0; cnt < (int)ehdr.e_phnum; cnt++) { 1213 if (gelf_getphdr(elf, cnt, &phdr) == NULL) { 1214 (void) fprintf(stderr, 1215 gettext("can't read program header\n")); 1216 return (1); 1217 } 1218 if (phdr.p_type == PT_DYNAMIC) { 1219 dynamic = 1; 1220 break; 1221 } 1222 } 1223 if (dynamic) 1224 (void) printf(gettext(", dynamically linked")); 1225 else 1226 (void) printf(gettext(", statically linked")); 1227 1228 is_stripped(elf); 1229 return (0); 1230 } 1231 1232 /* 1233 * is_stripped prints information on whether the executable has 1234 * been stripped. 1235 */ 1236 static void 1237 is_stripped(Elf *elf) 1238 { 1239 GElf_Shdr shdr; 1240 GElf_Ehdr ehdr; 1241 Elf_Scn *scn, *nextscn; 1242 char *section_name; 1243 int symtab = 0; 1244 int debuginfo = 0; 1245 1246 1247 if (gelf_getehdr(elf, &ehdr) == NULL) { 1248 return; 1249 } 1250 1251 /* 1252 * Definition time: 1253 * - "not stripped" means that an executable file 1254 * contains a Symbol Table (.symtab) 1255 * - "stripped" means that an executable file 1256 * does not contain a Symbol Table. 1257 * When strip -l or strip -x is run, it strips the 1258 * debugging information (.line section name (strip -l), 1259 * .line, .debug*, .stabs*, .dwarf* section names 1260 * and SHT_SUNW_DEBUGSTR and SHT_SUNW_DEBUG 1261 * section types (strip -x), however the Symbol 1262 * Table will still be present. 1263 * Therefore, if 1264 * - No Symbol Table present, then report 1265 * "stripped" 1266 * - Symbol Table present with debugging 1267 * information (line number or debug section names, 1268 * or SHT_SUNW_DEBUGSTR or SHT_SUNW_DEBUG section 1269 * types) then report: 1270 * "not stripped" 1271 * - Symbol Table present with no debugging 1272 * information (line number or debug section names, 1273 * or SHT_SUNW_DEBUGSTR or SHT_SUNW_DEBUG section 1274 * types) then report: 1275 * "not stripped, no debugging information 1276 * available" 1277 */ 1278 scn = NULL; 1279 while ((nextscn = elf_nextscn(elf, scn)) != NULL) { 1280 if (symtab && debuginfo) { 1281 break; 1282 } 1283 1284 scn = nextscn; 1285 if (gelf_getshdr(scn, &shdr) == NULL) { 1286 continue; 1287 } 1288 1289 if (!symtab && (shdr.sh_type == SHT_SYMTAB)) { 1290 symtab++; 1291 continue; 1292 } 1293 1294 if (!debuginfo && 1295 ((shdr.sh_type == SHT_SUNW_DEBUG) || 1296 (shdr.sh_type == SHT_SUNW_DEBUGSTR) || 1297 (((section_name = elf_strptr(elf, ehdr.e_shstrndx, 1298 (size_t)shdr.sh_name)) != NULL) && 1299 (is_in_list(debug_sections, section_name))))) { 1300 debuginfo++; 1301 } 1302 } 1303 1304 /* 1305 * Now that we've scanned all sections, print out the appropriate 1306 * diagnostic. 1307 */ 1308 if (symtab) { 1309 (void) printf(gettext(", not stripped")); 1310 if (!debuginfo) { 1311 (void) printf(gettext( 1312 ", no debugging information available")); 1313 } 1314 } else { 1315 (void) printf(gettext(", stripped")); 1316 } 1317 } 1318 1319 /* 1320 * is_rtld_config - If file is a runtime linker config file, prints 1321 * the description and returns True (1). Otherwise, silently returns 1322 * False (0). 1323 */ 1324 int 1325 is_rtld_config(void) 1326 { 1327 Rtc_id *id; 1328 1329 if ((fbsz >= sizeof (*id)) && RTC_ID_TEST(fbuf)) { 1330 (void) printf(gettext("Runtime Linking Configuration")); 1331 /* LINTED: pointer cast may result in improper alignment */ 1332 id = (Rtc_id *) fbuf; 1333 print_elf_class(id->id_class); 1334 print_elf_datatype(id->id_data); 1335 print_elf_machine(id->id_machine); 1336 (void) printf("\n"); 1337 return (1); 1338 } 1339 1340 return (0); 1341 } 1342 1343 /* 1344 * lookup - 1345 * Attempts to match one of the strings from a list, 'tab', 1346 * with what is in the file, starting at the current index position 'i'. 1347 * Looks past any initial whitespace and expects whitespace or other 1348 * delimiting characters to follow the matched string. 1349 * A match identifies the file as being 'assembler', 'fortran', 'c', etc. 1350 * Returns 1 for a successful match, 0 otherwise. 1351 */ 1352 static int 1353 lookup(char **tab) 1354 { 1355 register char r; 1356 register int k, j, l; 1357 1358 while (fbuf[i] == ' ' || fbuf[i] == '\t' || fbuf[i] == '\n') 1359 i++; 1360 for (j = 0; tab[j] != 0; j++) { 1361 l = 0; 1362 for (k = i; ((r = tab[j][l++]) == fbuf[k] && r != '\0'); k++); 1363 if (r == '\0') 1364 if (fbuf[k] == ' ' || fbuf[k] == '\n' || 1365 fbuf[k] == '\t' || fbuf[k] == '{' || 1366 fbuf[k] == '/') { 1367 i = k; 1368 return (1); 1369 } 1370 } 1371 return (0); 1372 } 1373 1374 /* 1375 * ccom - 1376 * Increments the current index 'i' into the file buffer 'fbuf' past any 1377 * whitespace lines and C-style comments found, starting at the current 1378 * position of 'i'. Returns 1 as long as we don't increment i past the 1379 * size of fbuf (fbsz). Otherwise, returns 0. 1380 */ 1381 1382 static int 1383 ccom(void) 1384 { 1385 register char cc; 1386 int len; 1387 1388 while ((cc = fbuf[i]) == ' ' || cc == '\t' || cc == '\n') 1389 if (i++ >= fbsz) 1390 return (0); 1391 if (fbuf[i] == '/' && fbuf[i+1] == '*') { 1392 i += 2; 1393 while (fbuf[i] != '*' || fbuf[i+1] != '/') { 1394 if (fbuf[i] == '\\') 1395 i++; 1396 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 1397 len = 1; 1398 i += len; 1399 if (i >= fbsz) 1400 return (0); 1401 } 1402 if ((i += 2) >= fbsz) 1403 return (0); 1404 } 1405 if (fbuf[i] == '\n') 1406 if (ccom() == 0) 1407 return (0); 1408 return (1); 1409 } 1410 1411 /* 1412 * ascom - 1413 * Increments the current index 'i' into the file buffer 'fbuf' past 1414 * consecutive assembler program comment lines starting with ASCOMCHAR, 1415 * starting at the current position of 'i'. 1416 * Returns 1 as long as we don't increment i past the 1417 * size of fbuf (fbsz). Otherwise returns 0. 1418 */ 1419 1420 static int 1421 ascom(void) 1422 { 1423 while (fbuf[i] == ASCOMCHAR) { 1424 i++; 1425 while (fbuf[i++] != '\n') 1426 if (i >= fbsz) 1427 return (0); 1428 while (fbuf[i] == '\n') 1429 if (i++ >= fbsz) 1430 return (0); 1431 } 1432 return (1); 1433 } 1434 1435 static int 1436 sccs(void) 1437 { /* look for "1hddddd" where d is a digit */ 1438 register int j; 1439 1440 if (fbuf[0] == 1 && fbuf[1] == 'h') { 1441 for (j = 2; j <= 6; j++) { 1442 if (isdigit(fbuf[j])) 1443 continue; 1444 else 1445 return (0); 1446 } 1447 } else { 1448 return (0); 1449 } 1450 return (1); 1451 } 1452 1453 static int 1454 english(char *bp, int n) 1455 { 1456 #define NASC 128 /* number of ascii char ?? */ 1457 register int j, vow, freq, rare, len; 1458 register int badpun = 0, punct = 0; 1459 int ct[NASC]; 1460 1461 if (n < 50) 1462 return (0); /* no point in statistics on squibs */ 1463 for (j = 0; j < NASC; j++) 1464 ct[j] = 0; 1465 for (j = 0; j < n; j += len) { 1466 if ((unsigned char)bp[j] < NASC) 1467 ct[bp[j]|040]++; 1468 switch (bp[j]) { 1469 case '.': 1470 case ',': 1471 case ')': 1472 case '%': 1473 case ';': 1474 case ':': 1475 case '?': 1476 punct++; 1477 if (j < n-1 && bp[j+1] != ' ' && bp[j+1] != '\n') 1478 badpun++; 1479 } 1480 if ((len = mblen(&bp[j], MB_CUR_MAX)) <= 0) 1481 len = 1; 1482 } 1483 if (badpun*5 > punct) 1484 return (0); 1485 vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 1486 freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 1487 rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 1488 if (2*ct[';'] > ct['e']) 1489 return (0); 1490 if ((ct['>'] + ct['<'] + ct['/']) > ct['e']) 1491 return (0); /* shell file test */ 1492 return (vow * 5 >= n - ct[' '] && freq >= 10 * rare); 1493 } 1494 1495 /* 1496 * Convert a word from an elf file to native format. 1497 * This is needed because there's no elf routine to 1498 * get and decode a Note section header. 1499 */ 1500 static void 1501 convert_gelf_word(Elf *elf, GElf_Word *data, int version, int format) 1502 { 1503 Elf_Data src, dst; 1504 1505 dst.d_buf = data; 1506 dst.d_version = version; 1507 dst.d_size = sizeof (GElf_Word); 1508 dst.d_type = ELF_T_WORD; 1509 src.d_buf = data; 1510 src.d_version = version; 1511 src.d_size = sizeof (GElf_Word); 1512 src.d_type = ELF_T_WORD; 1513 (void) gelf_xlatetom(elf, &dst, &src, format); 1514 } 1515 1516 static void 1517 convert_gelf_nhdr(Elf *elf, GElf_Nhdr *nhdr, GElf_Word version, int format) 1518 { 1519 convert_gelf_word(elf, &nhdr->n_namesz, version, format); 1520 convert_gelf_word(elf, &nhdr->n_descsz, version, format); 1521 convert_gelf_word(elf, &nhdr->n_type, version, format); 1522 } 1523 1524 /* 1525 * Return true if it is an old (pre-restructured /proc) core file. 1526 */ 1527 static int 1528 old_core(Elf *elf, GElf_Ehdr *ehdr, int format) 1529 { 1530 register int inx; 1531 GElf_Phdr phdr; 1532 GElf_Phdr nphdr; 1533 GElf_Nhdr nhdr; 1534 off_t offset; 1535 1536 if (ehdr->e_type != ET_CORE) 1537 return (0); 1538 for (inx = 0; inx < (int)ehdr->e_phnum; inx++) { 1539 if (gelf_getphdr(elf, inx, &phdr) == NULL) { 1540 return (0); 1541 } 1542 if (phdr.p_type == PT_NOTE) { 1543 /* 1544 * If the next segment is also a note, use it instead. 1545 */ 1546 if (gelf_getphdr(elf, inx+1, &nphdr) == NULL) { 1547 return (0); 1548 } 1549 if (nphdr.p_type == PT_NOTE) 1550 phdr = nphdr; 1551 offset = (off_t)phdr.p_offset; 1552 (void) pread(ifd, &nhdr, sizeof (GElf_Nhdr), offset); 1553 convert_gelf_nhdr(elf, &nhdr, ehdr->e_version, format); 1554 /* 1555 * Old core files have type NT_PRPSINFO. 1556 */ 1557 if (nhdr.n_type == NT_PRPSINFO) 1558 return (1); 1559 return (0); 1560 } 1561 } 1562 return (0); 1563 } 1564 1565 /* 1566 * If it's a core file, print out the name of the file that dumped core. 1567 */ 1568 static int 1569 core(Elf *elf, GElf_Ehdr *ehdr, int format) 1570 { 1571 register int inx; 1572 char *psinfo; 1573 GElf_Phdr phdr; 1574 GElf_Phdr nphdr; 1575 GElf_Nhdr nhdr; 1576 off_t offset; 1577 1578 if (ehdr->e_type != ET_CORE) 1579 return (0); 1580 for (inx = 0; inx < (int)ehdr->e_phnum; inx++) { 1581 if (gelf_getphdr(elf, inx, &phdr) == NULL) { 1582 (void) fprintf(stderr, 1583 gettext("can't read program header\n")); 1584 return (0); 1585 } 1586 if (phdr.p_type == PT_NOTE) { 1587 char *fname; 1588 size_t size; 1589 /* 1590 * If the next segment is also a note, use it instead. 1591 */ 1592 if (gelf_getphdr(elf, inx+1, &nphdr) == NULL) { 1593 (void) fprintf(stderr, 1594 gettext("can't read program header\n")); 1595 return (0); 1596 } 1597 if (nphdr.p_type == PT_NOTE) 1598 phdr = nphdr; 1599 offset = (off_t)phdr.p_offset; 1600 (void) pread(ifd, &nhdr, sizeof (GElf_Nhdr), offset); 1601 convert_gelf_nhdr(elf, &nhdr, ehdr->e_version, format); 1602 /* 1603 * Note: the ABI states that n_namesz must 1604 * be rounded up to a 4 byte boundary. 1605 */ 1606 offset += sizeof (GElf_Nhdr) + 1607 ((nhdr.n_namesz + 0x03) & ~0x3); 1608 size = nhdr.n_descsz; 1609 psinfo = malloc(size); 1610 (void) pread(ifd, psinfo, size, offset); 1611 /* 1612 * We want to print the string contained 1613 * in psinfo->pr_fname[], where 'psinfo' 1614 * is either an old NT_PRPSINFO structure 1615 * or a new NT_PSINFO structure. 1616 * 1617 * Old core files have only type NT_PRPSINFO. 1618 * New core files have type NT_PSINFO. 1619 * 1620 * These structures are also different by 1621 * virtue of being contained in a core file 1622 * of either 32-bit or 64-bit type. 1623 * 1624 * To further complicate matters, we ourself 1625 * might be compiled either 32-bit or 64-bit. 1626 * 1627 * For these reason, we just *know* the offsets of 1628 * pr_fname[] into the four different structures 1629 * here, regardless of how we are compiled. 1630 */ 1631 if (gelf_getclass(elf) == ELFCLASS32) { 1632 /* 32-bit core file, 32-bit structures */ 1633 if (nhdr.n_type == NT_PSINFO) 1634 fname = psinfo + 88; 1635 else /* old: NT_PRPSINFO */ 1636 fname = psinfo + 84; 1637 } else if (gelf_getclass(elf) == ELFCLASS64) { 1638 /* 64-bit core file, 64-bit structures */ 1639 if (nhdr.n_type == NT_PSINFO) 1640 fname = psinfo + 136; 1641 else /* old: NT_PRPSINFO */ 1642 fname = psinfo + 120; 1643 } else { 1644 free(psinfo); 1645 break; 1646 } 1647 (void) printf(gettext(", from '%s'"), fname); 1648 free(psinfo); 1649 break; 1650 } 1651 } 1652 return (1); 1653 } 1654 1655 static int 1656 shellscript(char buf[], struct stat64 *sb) 1657 { 1658 char *tp, *cp, *xp, *up, *gp; 1659 1660 cp = strchr(buf, '\n'); 1661 if (cp == NULL || cp - fbuf > fbsz) 1662 return (0); 1663 for (tp = buf; tp != cp && isspace((unsigned char)*tp); tp++) 1664 if (!isascii(*tp)) 1665 return (0); 1666 for (xp = tp; tp != cp && !isspace((unsigned char)*tp); tp++) 1667 if (!isascii(*tp)) 1668 return (0); 1669 if (tp == xp) 1670 return (0); 1671 if (sb->st_mode & S_ISUID) 1672 up = gettext("set-uid "); 1673 else 1674 up = ""; 1675 1676 if (sb->st_mode & S_ISGID) 1677 gp = gettext("set-gid "); 1678 else 1679 gp = ""; 1680 1681 if (strncmp(xp, "/bin/sh", tp - xp) == 0) 1682 xp = gettext("shell"); 1683 else if (strncmp(xp, "/bin/csh", tp - xp) == 0) 1684 xp = gettext("c-shell"); 1685 else if (strncmp(xp, "/usr/sbin/dtrace", tp - xp) == 0) 1686 xp = gettext("DTrace"); 1687 else 1688 *tp = '\0'; 1689 /* 1690 * TRANSLATION_NOTE 1691 * This message is printed by file command for shell scripts. 1692 * The first %s is for the translation for "set-uid " (if the script 1693 * has the set-uid bit set), or is for an empty string (if the 1694 * script does not have the set-uid bit set). 1695 * Similarly, the second %s is for the translation for "set-gid ", 1696 * or is for an empty string. 1697 * The third %s is for the translation for either: "shell", "c-shell", 1698 * or "DTrace", or is for the pathname of the program the script 1699 * executes. 1700 */ 1701 (void) printf(gettext("%s%sexecutable %s script\n"), up, gp, xp); 1702 return (1); 1703 } 1704 1705 static int 1706 get_door_target(char *file, char *buf, size_t bufsize) 1707 { 1708 int fd; 1709 door_info_t di; 1710 psinfo_t psinfo; 1711 1712 if ((fd = open64(file, O_RDONLY)) < 0 || 1713 door_info(fd, &di) != 0) { 1714 if (fd >= 0) 1715 (void) close(fd); 1716 return (-1); 1717 } 1718 (void) close(fd); 1719 1720 (void) sprintf(buf, "/proc/%ld/psinfo", di.di_target); 1721 if ((fd = open64(buf, O_RDONLY)) < 0 || 1722 read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) { 1723 if (fd >= 0) 1724 (void) close(fd); 1725 return (-1); 1726 } 1727 (void) close(fd); 1728 1729 (void) snprintf(buf, bufsize, "%s[%ld]", psinfo.pr_fname, di.di_target); 1730 return (0); 1731 } 1732 1733 /* 1734 * ZIP file header information 1735 */ 1736 #define SIGSIZ 4 1737 #define LOCSIG "PK\003\004" 1738 #define LOCHDRSIZ 30 1739 1740 #define CH(b, n) (((unsigned char *)(b))[n]) 1741 #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) 1742 #define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) 1743 1744 #define LOCNAM(b) (SH(b, 26)) /* filename size */ 1745 #define LOCEXT(b) (SH(b, 28)) /* extra field size */ 1746 1747 #define XFHSIZ 4 /* header id, data size */ 1748 #define XFHID(b) (SH(b, 0)) /* extract field header id */ 1749 #define XFDATASIZ(b) (SH(b, 2)) /* extract field data size */ 1750 #define XFJAVASIG 0xcafe /* java executables */ 1751 1752 static int 1753 zipfile(char *fbuf, int fd) 1754 { 1755 off_t xoff, xoff_end; 1756 1757 if (strncmp(fbuf, LOCSIG, SIGSIZ) != 0) 1758 return (0); 1759 1760 xoff = LOCHDRSIZ + LOCNAM(fbuf); 1761 xoff_end = xoff + LOCEXT(fbuf); 1762 1763 while (xoff < xoff_end) { 1764 char xfhdr[XFHSIZ]; 1765 1766 if (pread(fd, xfhdr, XFHSIZ, xoff) != XFHSIZ) 1767 break; 1768 1769 if (XFHID(xfhdr) == XFJAVASIG) { 1770 (void) printf("%s\n", gettext("java program")); 1771 return (1); 1772 } 1773 xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr); 1774 } 1775 1776 /* 1777 * We could just print "ZIP archive" here. 1778 * 1779 * However, customers may be using their own entries in 1780 * /etc/magic to distinguish one kind of ZIP file from another, so 1781 * let's defer the printing of "ZIP archive" to there. 1782 */ 1783 return (0); 1784 } 1785 1786 static int 1787 is_crash_dump(const char *buf, int fd) 1788 { 1789 /* LINTED: pointer cast may result in improper alignment */ 1790 const dumphdr_t *dhp = (const dumphdr_t *)buf; 1791 1792 /* 1793 * The current DUMP_MAGIC string covers Solaris 7 and later releases. 1794 * The utsname struct is only present in dumphdr_t's with dump_version 1795 * greater than or equal to 9. 1796 */ 1797 if (dhp->dump_magic == DUMP_MAGIC) { 1798 print_dumphdr(fd, dhp, return_uint32, NATIVE_ISA); 1799 1800 } else if (dhp->dump_magic == swap_uint32(DUMP_MAGIC)) { 1801 print_dumphdr(fd, dhp, swap_uint32, OTHER_ISA); 1802 1803 } else if (dhp->dump_magic == OLD_DUMP_MAGIC || 1804 dhp->dump_magic == swap_uint32(OLD_DUMP_MAGIC)) { 1805 char *isa = (dhp->dump_magic == OLD_DUMP_MAGIC ? 1806 NATIVE_ISA : OTHER_ISA); 1807 (void) printf(gettext("SunOS 32-bit %s crash dump\n"), isa); 1808 1809 } else { 1810 return (0); 1811 } 1812 1813 return (1); 1814 } 1815 1816 static void 1817 print_dumphdr(const int fd, const dumphdr_t *dhp, uint32_t (*swap)(uint32_t), 1818 const char *isa) 1819 { 1820 dumphdr_t dh; 1821 1822 /* 1823 * A dumphdr_t is bigger than FBSZ, so we have to manually read the 1824 * rest of it. 1825 */ 1826 if (swap(dhp->dump_version) > 8 && pread(fd, &dh, sizeof (dumphdr_t), 1827 (off_t)0) == sizeof (dumphdr_t)) { 1828 (void) printf(gettext( 1829 "%s %s %s %u-bit %s crash dump from '%s'\n"), 1830 dh.dump_utsname.sysname, dh.dump_utsname.release, 1831 dh.dump_utsname.version, swap(dh.dump_wordsize), isa, 1832 dh.dump_utsname.nodename); 1833 } else { 1834 (void) printf(gettext("SunOS %u-bit %s crash dump\n"), 1835 swap(dhp->dump_wordsize), isa); 1836 } 1837 } 1838 1839 static void 1840 usage(void) 1841 { 1842 (void) fprintf(stderr, gettext( 1843 "usage: file [-dh] [-M mfile] [-m mfile] [-f ffile] file ...\n" 1844 " file [-dh] [-M mfile] [-m mfile] -f ffile\n" 1845 " file -i [-h] [-f ffile] file ...\n" 1846 " file -i [-h] -f ffile\n" 1847 " file -c [-d] [-M mfile] [-m mfile]\n")); 1848 exit(2); 1849 } 1850 1851 static uint32_t 1852 swap_uint32(uint32_t in) 1853 { 1854 uint32_t out; 1855 1856 out = (in & 0x000000ff) << 24; 1857 out |= (in & 0x0000ff00) << 8; /* >> 8 << 16 */ 1858 out |= (in & 0x00ff0000) >> 8; /* >> 16 << 8 */ 1859 out |= (in & 0xff000000) >> 24; 1860 1861 return (out); 1862 } 1863 1864 static uint32_t 1865 return_uint32(uint32_t in) 1866 { 1867 return (in); 1868 } 1869 1870 /* 1871 * Check if str is in the string list str_list. 1872 */ 1873 static int 1874 is_in_list(char *str_list[], char *str) 1875 { 1876 int i; 1877 1878 /* 1879 * Only need to compare the strlen(str_list[i]) bytes. 1880 * That way .stab will match on .stab* sections, and 1881 * .debug will match on .debug* sections. 1882 */ 1883 for (i = 0; str_list[i] != NULL; i++) { 1884 if (strncmp(str_list[i], str, strlen(str_list[i])) == 0) { 1885 return (1); 1886 } 1887 } 1888 return (0); 1889 } 1890 1891 /* 1892 * default_magic - 1893 * allocate space for and create the default magic file 1894 * name string. 1895 */ 1896 1897 static void 1898 default_magic(void) 1899 { 1900 const char *msg_locale = setlocale(LC_MESSAGES, NULL); 1901 struct stat statbuf; 1902 1903 if ((dfile = (char *)malloc(strlen(msg_locale) + 35)) == NULL) { 1904 perror("file"); 1905 exit(2); 1906 } 1907 (void) snprintf(dfile, strlen(msg_locale) + 35, 1908 "/usr/lib/locale/%s/LC_MESSAGES/magic", msg_locale); 1909 if (stat(dfile, &statbuf) != 0) { 1910 (void) strcpy(dfile, "/etc/magic"); 1911 } 1912 } 1913 1914 /* 1915 * add_to_mlist - 1916 * Add the given magic_file filename string to the list of magic 1917 * files (mlist). This list of files will later be examined, and 1918 * each magic file's entries will be added in order to 1919 * the mtab table. 1920 * 1921 * The first flag is set to 1 to add to the first list, mlist1. 1922 * The first flag is set to 0 to add to the second list, mlist2. 1923 */ 1924 1925 static void 1926 add_to_mlist(char *magic_file, int first) 1927 { 1928 char **mlist; /* ordered list of magic files */ 1929 size_t mlist_sz; /* number of pointers allocated for mlist */ 1930 char **mlistp; /* next entry in mlist */ 1931 size_t mlistp_off; 1932 1933 if (first) { 1934 mlist = mlist1; 1935 mlist_sz = mlist1_sz; 1936 mlistp = mlist1p; 1937 } else { 1938 mlist = mlist2; 1939 mlist_sz = mlist2_sz; 1940 mlistp = mlist2p; 1941 } 1942 1943 if (mlist == NULL) { /* initial mlist allocation */ 1944 if ((mlist = (char **)calloc(MLIST_SZ, sizeof (char *))) 1945 == NULL) { 1946 perror("file"); 1947 exit(2); 1948 } 1949 mlist_sz = MLIST_SZ; 1950 mlistp = mlist; 1951 } 1952 if ((mlistp - mlist) >= mlist_sz) { 1953 mlistp_off = mlistp - mlist; 1954 mlist_sz *= 2; 1955 if ((mlist = (char **)realloc(mlist, 1956 mlist_sz * sizeof (char *))) == NULL) { 1957 perror("file"); 1958 exit(2); 1959 } 1960 mlistp = mlist + mlistp_off; 1961 } 1962 /* 1963 * now allocate memory for and copy the 1964 * magic file name string 1965 */ 1966 if ((*mlistp = malloc(strlen(magic_file) + 1)) == NULL) { 1967 perror("file"); 1968 exit(2); 1969 } 1970 (void) strlcpy(*mlistp, magic_file, strlen(magic_file) + 1); 1971 mlistp++; 1972 1973 if (first) { 1974 mlist1 = mlist; 1975 mlist1_sz = mlist_sz; 1976 mlist1p = mlistp; 1977 } else { 1978 mlist2 = mlist; 1979 mlist2_sz = mlist_sz; 1980 mlist2p = mlistp; 1981 } 1982 } 1983 1984 static void 1985 fd_cleanup(void) 1986 { 1987 if (ifd != -1) { 1988 (void) close(ifd); 1989 ifd = -1; 1990 } 1991 if (elffd != -1) { 1992 (void) close(elffd); 1993 elffd = -1; 1994 } 1995 } 1996