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