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