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 [EM_LANAI] = "Lanai", 1167 [EM_CEVA] = "CEVA", 1168 [EM_CEVA_X2] = "CEVA X2", 1169 [EM_BPF] = "Linux BPF", 1170 [EM_GRAPHCORE_IPU] = "Graphcore IPU", 1171 [EM_IMG1] = "Imagination Technologies", 1172 [EM_NFP] = "Netronome Flow Processor", 1173 [EM_VE] = "NEC Vector Engine", 1174 [EM_CSKY] = "C-SKY", 1175 [EM_ARC_COMPACT3_64] = "ARCv2.3 (64-bit)", 1176 [EM_MCS6502] = "MCS6502", 1177 [EM_ARC_COMPACT3] = "ARCv2.3 (32-bit)", 1178 [EM_KVX] = "Kalray KVX", 1179 [EM_65816] = "WDC 65816/65C816", 1180 [EM_LOONGARCH] = "Loongarch", 1181 [EM_KF32] = "KungFu32", 1182 [EM_U16_U8CORE] = "nX-U16/U8", 1183 [EM_TACHYUM] = "Tachyum", 1184 [EM_56800EF] = "NXP 56800EF", 1185 [EM_SBF] = "Solana Bytecode", 1186 [EM_AIENGINE] = "AMD/Xilinx AIEngine", 1187 [EM_SIMA_MLA] = "SiMa MLA", 1188 [EM_BANG] = "BANG", 1189 [EM_LOONGGPU] = "LoongGPU", 1190 [EM_SW64] = "SW64", 1191 [EM_AIECTRLCODE] = "AMD/Xilinx AIEngine ctrlcode", 1192 }; 1193 /* If new machine is added, refuse to compile until we're updated */ 1194 #if EM_NUM != (EM_AIECTRLCODE + 1) 1195 #error "Number of known ELF machine constants has changed" 1196 #endif 1197 1198 const char *str; 1199 1200 if ((machine < EM_NONE) || (machine >= EM_NUM)) 1201 machine = EM_NONE; 1202 1203 str = mach_str[machine]; 1204 if (str) 1205 (void) printf(" %s", str); 1206 } 1207 1208 static void 1209 print_elf_datatype(int datatype) 1210 { 1211 switch (datatype) { 1212 case ELFDATA2LSB: 1213 (void) printf(" LSB"); 1214 break; 1215 case ELFDATA2MSB: 1216 (void) printf(" MSB"); 1217 break; 1218 default: 1219 break; 1220 } 1221 } 1222 1223 static void 1224 print_elf_class(int class) 1225 { 1226 switch (class) { 1227 case ELFCLASS32: 1228 (void) printf(" %s", gettext("32-bit")); 1229 break; 1230 case ELFCLASS64: 1231 (void) printf(" %s", gettext("64-bit")); 1232 break; 1233 default: 1234 break; 1235 } 1236 } 1237 1238 static void 1239 print_elf_flags(Elf_Info EI) 1240 { 1241 unsigned int flags; 1242 1243 flags = EI.flags; 1244 switch (EI.machine) { 1245 case EM_SPARCV9: 1246 if (flags & EF_SPARC_EXT_MASK) { 1247 if (flags & EF_SPARC_SUN_US3) { 1248 (void) printf("%s", gettext( 1249 ", UltraSPARC3 Extensions Required")); 1250 } else if (flags & EF_SPARC_SUN_US1) { 1251 (void) printf("%s", gettext( 1252 ", UltraSPARC1 Extensions Required")); 1253 } 1254 if (flags & EF_SPARC_HAL_R1) 1255 (void) printf("%s", gettext( 1256 ", HaL R1 Extensions Required")); 1257 } 1258 break; 1259 case EM_SPARC32PLUS: 1260 if (flags & EF_SPARC_32PLUS) 1261 (void) printf("%s", gettext(", V8+ Required")); 1262 if (flags & EF_SPARC_SUN_US3) { 1263 (void) printf("%s", 1264 gettext(", UltraSPARC3 Extensions Required")); 1265 } else if (flags & EF_SPARC_SUN_US1) { 1266 (void) printf("%s", 1267 gettext(", UltraSPARC1 Extensions Required")); 1268 } 1269 if (flags & EF_SPARC_HAL_R1) 1270 (void) printf("%s", 1271 gettext(", HaL R1 Extensions Required")); 1272 break; 1273 default: 1274 break; 1275 } 1276 } 1277 1278 /* 1279 * check_ident: checks the ident field of the presumeably 1280 * elf file. If check fails, this is not an 1281 * elf file. 1282 */ 1283 static int 1284 check_ident(unsigned char *ident, int fd) 1285 { 1286 int class; 1287 if (pread64(fd, ident, EI_NIDENT, 0) != EI_NIDENT) 1288 return (ELF_READ_FAIL); 1289 class = ident[EI_CLASS]; 1290 if (class != ELFCLASS32 && class != ELFCLASS64) 1291 return (ELF_READ_FAIL); 1292 if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 1293 ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) 1294 return (ELF_READ_FAIL); 1295 1296 return (ELF_READ_OKAY); 1297 } 1298 1299 static int 1300 elf_check(char *file) 1301 { 1302 Elf_Info EInfo; 1303 int class, version, format; 1304 unsigned char ident[EI_NIDENT]; 1305 1306 (void) memset(&EInfo, 0, sizeof (Elf_Info)); 1307 EInfo.file = file; 1308 1309 /* 1310 * Verify information in file indentifier. 1311 * Return quietly if not elf; Different type of file. 1312 */ 1313 if (check_ident(ident, elffd) == ELF_READ_FAIL) 1314 return (1); 1315 1316 /* 1317 * Read the elf headers for processing and get the 1318 * get the needed information in Elf_Info struct. 1319 */ 1320 class = ident[EI_CLASS]; 1321 if (class == ELFCLASS32) { 1322 if (elf_read32(elffd, &EInfo) == ELF_READ_FAIL) { 1323 (void) fprintf(stderr, gettext("%s: %s: can't " 1324 "read ELF header\n"), File, file); 1325 return (1); 1326 } 1327 } else if (class == ELFCLASS64) { 1328 if (elf_read64(elffd, &EInfo) == ELF_READ_FAIL) { 1329 (void) fprintf(stderr, gettext("%s: %s: can't " 1330 "read ELF header\n"), File, file); 1331 return (1); 1332 } 1333 } else { 1334 /* something wrong */ 1335 return (1); 1336 } 1337 1338 /* version not in ident then 1 */ 1339 version = ident[EI_VERSION] ? ident[EI_VERSION] : 1; 1340 1341 format = ident[EI_DATA]; 1342 (void) printf("%s", gettext("ELF")); 1343 print_elf_class(class); 1344 print_elf_datatype(format); 1345 print_elf_type(EInfo); 1346 1347 if (EInfo.core_type != EC_NOTCORE) { 1348 /* Print what kind of core is this */ 1349 if (EInfo.core_type == EC_OLDCORE) 1350 (void) printf(" %s", gettext("pre-2.6 core file")); 1351 else 1352 (void) printf(" %s", gettext("core file")); 1353 } 1354 1355 /* Print machine info */ 1356 print_elf_machine(EInfo.machine); 1357 1358 /* Print Version */ 1359 if (version == 1) 1360 (void) printf(" %s %d", gettext("Version"), version); 1361 1362 if (EInfo.kmod) { 1363 (void) printf(", %s", gettext("kernel module")); 1364 } 1365 1366 /* Print Flags */ 1367 print_elf_flags(EInfo); 1368 1369 /* Last bit, if it is a core */ 1370 if (EInfo.core_type != EC_NOTCORE) { 1371 /* Print the program name that dumped this core */ 1372 (void) printf(gettext(", from '%s'"), EInfo.fname); 1373 return (0); 1374 } 1375 1376 /* Print Capabilities */ 1377 if (EInfo.cap_str[0] != '\0') 1378 (void) printf(" [%s]", EInfo.cap_str); 1379 1380 if ((EInfo.type != ET_EXEC) && (EInfo.type != ET_DYN)) 1381 return (0); 1382 1383 /* Print if it is dynamically linked */ 1384 if (EInfo.dynamic) 1385 (void) printf(gettext(", dynamically linked")); 1386 else 1387 (void) printf(gettext(", statically linked")); 1388 1389 /* Printf it it is stripped */ 1390 if (EInfo.stripped & E_SYMTAB) { 1391 (void) printf(gettext(", not stripped")); 1392 if (!(EInfo.stripped & E_DBGINF)) { 1393 (void) printf(gettext( 1394 ", no debugging information available")); 1395 } 1396 } else { 1397 (void) printf(gettext(", stripped")); 1398 } 1399 1400 return (0); 1401 } 1402 1403 /* 1404 * is_rtld_config - If file is a runtime linker config file, prints 1405 * the description and returns True (1). Otherwise, silently returns 1406 * False (0). 1407 */ 1408 int 1409 is_rtld_config(void) 1410 { 1411 Rtc_id *id; 1412 1413 if ((fbsz >= sizeof (*id)) && RTC_ID_TEST(fbuf)) { 1414 (void) printf(gettext("Runtime Linking Configuration")); 1415 id = (Rtc_id *) fbuf; 1416 print_elf_class(id->id_class); 1417 print_elf_datatype(id->id_data); 1418 print_elf_machine(id->id_machine); 1419 (void) printf("\n"); 1420 return (1); 1421 } 1422 1423 return (0); 1424 } 1425 1426 /* 1427 * lookup - 1428 * Attempts to match one of the strings from a list, 'tab', 1429 * with what is in the file, starting at the current index position 'i'. 1430 * Looks past any initial whitespace and expects whitespace or other 1431 * delimiting characters to follow the matched string. 1432 * A match identifies the file as being 'assembler', 'fortran', 'c', etc. 1433 * Returns 1 for a successful match, 0 otherwise. 1434 */ 1435 static int 1436 lookup(char **tab) 1437 { 1438 register char r; 1439 register int k, j, l; 1440 1441 while (fbuf[i] == ' ' || fbuf[i] == '\t' || fbuf[i] == '\n') 1442 i++; 1443 for (j = 0; tab[j] != 0; j++) { 1444 l = 0; 1445 for (k = i; ((r = tab[j][l++]) == fbuf[k] && r != '\0'); k++) 1446 ; 1447 if (r == '\0') 1448 if (fbuf[k] == ' ' || fbuf[k] == '\n' || 1449 fbuf[k] == '\t' || fbuf[k] == '{' || 1450 fbuf[k] == '/') { 1451 i = k; 1452 return (1); 1453 } 1454 } 1455 return (0); 1456 } 1457 1458 /* 1459 * ccom - 1460 * Increments the current index 'i' into the file buffer 'fbuf' past any 1461 * whitespace lines and C-style comments found, starting at the current 1462 * position of 'i'. Returns 1 as long as we don't increment i past the 1463 * size of fbuf (fbsz). Otherwise, returns 0. 1464 */ 1465 1466 static int 1467 ccom(void) 1468 { 1469 register char cc; 1470 int len; 1471 1472 while ((cc = fbuf[i]) == ' ' || cc == '\t' || cc == '\n') 1473 if (i++ >= fbsz) 1474 return (0); 1475 if (fbuf[i] == '/' && fbuf[i+1] == '*') { 1476 i += 2; 1477 while (fbuf[i] != '*' || fbuf[i+1] != '/') { 1478 if (fbuf[i] == '\\') 1479 i++; 1480 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 1481 len = 1; 1482 i += len; 1483 if (i >= fbsz) 1484 return (0); 1485 } 1486 if ((i += 2) >= fbsz) 1487 return (0); 1488 } 1489 if (fbuf[i] == '\n') 1490 if (ccom() == 0) 1491 return (0); 1492 return (1); 1493 } 1494 1495 /* 1496 * ascom - 1497 * Increments the current index 'i' into the file buffer 'fbuf' past 1498 * consecutive assembler program comment lines starting with ASCOMCHAR, 1499 * starting at the current position of 'i'. 1500 * Returns 1 as long as we don't increment i past the 1501 * size of fbuf (fbsz). Otherwise returns 0. 1502 */ 1503 1504 static int 1505 ascom(void) 1506 { 1507 while (fbuf[i] == ASCOMCHAR) { 1508 i++; 1509 while (fbuf[i++] != '\n') 1510 if (i >= fbsz) 1511 return (0); 1512 while (fbuf[i] == '\n') 1513 if (i++ >= fbsz) 1514 return (0); 1515 } 1516 return (1); 1517 } 1518 1519 /* look for "1hddddd" where d is a digit */ 1520 static int 1521 sccs(void) 1522 { 1523 register int j; 1524 1525 if (fbuf[0] == 1 && fbuf[1] == 'h') { 1526 for (j = 2; j <= 6; j++) { 1527 if (isdigit(fbuf[j])) 1528 continue; 1529 else 1530 return (0); 1531 } 1532 } else { 1533 return (0); 1534 } 1535 return (1); 1536 } 1537 1538 static int 1539 english(char *bp, int n) 1540 { 1541 #define NASC 128 /* number of ascii char ?? */ 1542 register int j, vow, freq, rare, len; 1543 register int badpun = 0, punct = 0; 1544 int ct[NASC]; 1545 1546 if (n < 50) 1547 return (0); /* no point in statistics on squibs */ 1548 for (j = 0; j < NASC; j++) 1549 ct[j] = 0; 1550 for (j = 0; j < n; j += len) { 1551 if ((unsigned char)bp[j] < NASC) 1552 ct[bp[j]|040]++; 1553 switch (bp[j]) { 1554 case '.': 1555 case ',': 1556 case ')': 1557 case '%': 1558 case ';': 1559 case ':': 1560 case '?': 1561 punct++; 1562 if (j < n-1 && bp[j+1] != ' ' && bp[j+1] != '\n') 1563 badpun++; 1564 } 1565 if ((len = mblen(&bp[j], MB_CUR_MAX)) <= 0) 1566 len = 1; 1567 } 1568 if (badpun*5 > punct) 1569 return (0); 1570 vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 1571 freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 1572 rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 1573 if (2*ct[';'] > ct['e']) 1574 return (0); 1575 if ((ct['>'] + ct['<'] + ct['/']) > ct['e']) 1576 return (0); /* shell file test */ 1577 return (vow * 5 >= n - ct[' '] && freq >= 10 * rare); 1578 } 1579 1580 1581 static int 1582 shellscript(char buf[], struct stat64 *sb) 1583 { 1584 char *tp, *cp, *xp, *up, *gp; 1585 1586 cp = strchr(buf, '\n'); 1587 if (cp == NULL || cp - fbuf > fbsz) 1588 return (0); 1589 for (tp = buf; tp != cp && isspace((unsigned char)*tp); tp++) 1590 if (!isascii(*tp)) 1591 return (0); 1592 for (xp = tp; tp != cp && !isspace((unsigned char)*tp); tp++) 1593 if (!isascii(*tp)) 1594 return (0); 1595 if (tp == xp) 1596 return (0); 1597 if (sb->st_mode & S_ISUID) 1598 up = gettext("set-uid "); 1599 else 1600 up = ""; 1601 1602 if (sb->st_mode & S_ISGID) 1603 gp = gettext("set-gid "); 1604 else 1605 gp = ""; 1606 1607 if (strncmp(xp, "/bin/sh", tp - xp) == 0) 1608 xp = gettext("shell"); 1609 else if (strncmp(xp, "/bin/csh", tp - xp) == 0) 1610 xp = gettext("c-shell"); 1611 else if (strncmp(xp, "/usr/sbin/dtrace", tp - xp) == 0) 1612 xp = gettext("DTrace"); 1613 else 1614 *tp = '\0'; 1615 /* 1616 * TRANSLATION_NOTE 1617 * This message is printed by file command for shell scripts. 1618 * The first %s is for the translation for "set-uid " (if the script 1619 * has the set-uid bit set), or is for an empty string (if the 1620 * script does not have the set-uid bit set). 1621 * Similarly, the second %s is for the translation for "set-gid ", 1622 * or is for an empty string. 1623 * The third %s is for the translation for either: "shell", "c-shell", 1624 * or "DTrace", or is for the pathname of the program the script 1625 * executes. 1626 */ 1627 (void) printf(gettext("%s%sexecutable %s script\n"), up, gp, xp); 1628 return (1); 1629 } 1630 1631 static int 1632 get_door_target(char *file, char *buf, size_t bufsize) 1633 { 1634 int fd; 1635 door_info_t di; 1636 psinfo_t psinfo; 1637 1638 if ((fd = open64(file, O_RDONLY)) < 0 || 1639 door_info(fd, &di) != 0) { 1640 if (fd >= 0) 1641 (void) close(fd); 1642 return (-1); 1643 } 1644 (void) close(fd); 1645 1646 (void) sprintf(buf, "/proc/%ld/psinfo", di.di_target); 1647 if ((fd = open64(buf, O_RDONLY)) < 0 || 1648 read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) { 1649 if (fd >= 0) 1650 (void) close(fd); 1651 return (-1); 1652 } 1653 (void) close(fd); 1654 1655 (void) snprintf(buf, bufsize, "%s[%ld]", psinfo.pr_fname, di.di_target); 1656 return (0); 1657 } 1658 1659 /* 1660 * ZIP file header information 1661 */ 1662 #define SIGSIZ 4 1663 #define LOCSIG "PK\003\004" 1664 #define LOCHDRSIZ 30 1665 1666 #define CH(b, n) (((unsigned char *)(b))[n]) 1667 #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) 1668 #define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) 1669 1670 #define LOCNAM(b) (SH(b, 26)) /* filename size */ 1671 #define LOCEXT(b) (SH(b, 28)) /* extra field size */ 1672 1673 #define XFHSIZ 4 /* header id, data size */ 1674 #define XFHID(b) (SH(b, 0)) /* extract field header id */ 1675 #define XFDATASIZ(b) (SH(b, 2)) /* extract field data size */ 1676 #define XFJAVASIG 0xcafe /* java executables */ 1677 1678 static int 1679 zipfile(char *fbuf, int fd) 1680 { 1681 off_t xoff, xoff_end; 1682 1683 if (strncmp(fbuf, LOCSIG, SIGSIZ) != 0) 1684 return (0); 1685 1686 xoff = LOCHDRSIZ + LOCNAM(fbuf); 1687 xoff_end = xoff + LOCEXT(fbuf); 1688 1689 while (xoff < xoff_end) { 1690 char xfhdr[XFHSIZ]; 1691 1692 if (pread(fd, xfhdr, XFHSIZ, xoff) != XFHSIZ) 1693 break; 1694 1695 if (XFHID(xfhdr) == XFJAVASIG) { 1696 (void) printf("%s\n", gettext("java archive file")); 1697 return (1); 1698 } 1699 xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr); 1700 } 1701 1702 /* 1703 * We could just print "ZIP archive" here. 1704 * 1705 * However, customers may be using their own entries in 1706 * /etc/magic to distinguish one kind of ZIP file from another, so 1707 * let's defer the printing of "ZIP archive" to there. 1708 */ 1709 return (0); 1710 } 1711 1712 static int 1713 is_crash_dump(const char *buf, int fd) 1714 { 1715 /* LINTED: pointer cast may result in improper alignment */ 1716 const dumphdr_t *dhp = (const dumphdr_t *)buf; 1717 1718 /* 1719 * The current DUMP_MAGIC string covers Solaris 7 and later releases. 1720 * The utsname struct is only present in dumphdr_t's with dump_version 1721 * greater than or equal to 9. 1722 */ 1723 if (dhp->dump_magic == DUMP_MAGIC) { 1724 print_dumphdr(fd, dhp, return_uint32, NATIVE_ISA); 1725 1726 } else if (dhp->dump_magic == swap_uint32(DUMP_MAGIC)) { 1727 print_dumphdr(fd, dhp, swap_uint32, OTHER_ISA); 1728 1729 } else if (dhp->dump_magic == OLD_DUMP_MAGIC || 1730 dhp->dump_magic == swap_uint32(OLD_DUMP_MAGIC)) { 1731 char *isa = (dhp->dump_magic == OLD_DUMP_MAGIC ? 1732 NATIVE_ISA : OTHER_ISA); 1733 (void) printf(gettext("SunOS 32-bit %s crash dump\n"), isa); 1734 1735 } else { 1736 return (0); 1737 } 1738 1739 return (1); 1740 } 1741 1742 static void 1743 print_dumphdr(const int fd, const dumphdr_t *dhp, uint32_t (*swap)(uint32_t), 1744 const char *isa) 1745 { 1746 dumphdr_t dh; 1747 1748 /* 1749 * A dumphdr_t is bigger than FBSZ, so we have to manually read the 1750 * rest of it. 1751 */ 1752 if (swap(dhp->dump_version) > 8 && pread(fd, &dh, sizeof (dumphdr_t), 1753 (off_t)0) == sizeof (dumphdr_t)) { 1754 const char *c = swap(dh.dump_flags) & DF_COMPRESSED ? 1755 "compressed " : ""; 1756 const char *l = swap(dh.dump_flags) & DF_LIVE ? 1757 "live" : "crash"; 1758 1759 (void) printf(gettext( 1760 "%s %s %s %u-bit %s %s%s dump from '%s'\n"), 1761 dh.dump_utsname.sysname, dh.dump_utsname.release, 1762 dh.dump_utsname.version, swap(dh.dump_wordsize), isa, 1763 c, l, dh.dump_utsname.nodename); 1764 } else { 1765 (void) printf(gettext("SunOS %u-bit %s crash dump\n"), 1766 swap(dhp->dump_wordsize), isa); 1767 } 1768 } 1769 1770 static void 1771 usage(void) 1772 { 1773 (void) fprintf(stderr, gettext( 1774 "usage: file [-bdh] [-M mfile] [-m mfile] [-f ffile] file ...\n" 1775 " file [-bdh] [-M mfile] [-m mfile] -f ffile\n" 1776 " file -i [-bh] [-f ffile] file ...\n" 1777 " file -i [-bh] -f ffile\n" 1778 " file -c [-d] [-M mfile] [-m mfile]\n")); 1779 exit(2); 1780 } 1781 1782 static uint32_t 1783 swap_uint32(uint32_t in) 1784 { 1785 uint32_t out; 1786 1787 out = (in & 0x000000ff) << 24; 1788 out |= (in & 0x0000ff00) << 8; /* >> 8 << 16 */ 1789 out |= (in & 0x00ff0000) >> 8; /* >> 16 << 8 */ 1790 out |= (in & 0xff000000) >> 24; 1791 1792 return (out); 1793 } 1794 1795 static uint32_t 1796 return_uint32(uint32_t in) 1797 { 1798 return (in); 1799 } 1800 1801 /* 1802 * Check if str is in the string list str_list. 1803 */ 1804 int 1805 is_in_list(char *str) 1806 { 1807 int i; 1808 1809 /* 1810 * Only need to compare the strlen(str_list[i]) bytes. 1811 * That way .stab will match on .stab* sections, and 1812 * .debug will match on .debug* sections. 1813 */ 1814 for (i = 0; debug_sections[i] != NULL; i++) { 1815 if (strncmp(debug_sections[i], str, 1816 strlen(debug_sections[i])) == 0) { 1817 return (1); 1818 } 1819 } 1820 return (0); 1821 } 1822 1823 /* 1824 * default_magic - 1825 * allocate space for and create the default magic file 1826 * name string. 1827 */ 1828 1829 static void 1830 default_magic(void) 1831 { 1832 const char *msg_locale = setlocale(LC_MESSAGES, NULL); 1833 struct stat statbuf; 1834 1835 if ((dfile = malloc(strlen(msg_locale) + 35)) == NULL) { 1836 int err = errno; 1837 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 1838 File, strerror(err)); 1839 exit(2); 1840 } 1841 (void) snprintf(dfile, strlen(msg_locale) + 35, 1842 "/usr/lib/locale/%s/LC_MESSAGES/magic", msg_locale); 1843 if (stat(dfile, &statbuf) != 0) { 1844 (void) strcpy(dfile, "/etc/magic"); 1845 } 1846 } 1847 1848 /* 1849 * add_to_mlist - 1850 * Add the given magic_file filename string to the list of magic 1851 * files (mlist). This list of files will later be examined, and 1852 * each magic file's entries will be added in order to 1853 * the mtab table. 1854 * 1855 * The first flag is set to 1 to add to the first list, mlist1. 1856 * The first flag is set to 0 to add to the second list, mlist2. 1857 */ 1858 1859 static void 1860 add_to_mlist(char *magic_file, int first) 1861 { 1862 char **mlist; /* ordered list of magic files */ 1863 size_t mlist_sz; /* number of pointers allocated for mlist */ 1864 char **mlistp; /* next entry in mlist */ 1865 size_t mlistp_off; 1866 1867 if (first) { 1868 mlist = mlist1; 1869 mlist_sz = mlist1_sz; 1870 mlistp = mlist1p; 1871 } else { 1872 mlist = mlist2; 1873 mlist_sz = mlist2_sz; 1874 mlistp = mlist2p; 1875 } 1876 1877 if (mlist == NULL) { /* initial mlist allocation */ 1878 if ((mlist = calloc(MLIST_SZ, sizeof (char *))) == NULL) { 1879 int err = errno; 1880 (void) fprintf(stderr, gettext("%s: malloc " 1881 "failed: %s\n"), File, strerror(err)); 1882 exit(2); 1883 } 1884 mlist_sz = MLIST_SZ; 1885 mlistp = mlist; 1886 } 1887 if ((mlistp - mlist) >= mlist_sz) { 1888 mlistp_off = mlistp - mlist; 1889 mlist_sz *= 2; 1890 if ((mlist = realloc(mlist, 1891 mlist_sz * sizeof (char *))) == NULL) { 1892 int err = errno; 1893 (void) fprintf(stderr, gettext("%s: malloc " 1894 "failed: %s\n"), File, strerror(err)); 1895 exit(2); 1896 } 1897 mlistp = mlist + mlistp_off; 1898 } 1899 /* 1900 * now allocate memory for and copy the 1901 * magic file name string 1902 */ 1903 if ((*mlistp = malloc(strlen(magic_file) + 1)) == NULL) { 1904 int err = errno; 1905 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 1906 File, strerror(err)); 1907 exit(2); 1908 } 1909 (void) strlcpy(*mlistp, magic_file, strlen(magic_file) + 1); 1910 mlistp++; 1911 1912 if (first) { 1913 mlist1 = mlist; 1914 mlist1_sz = mlist_sz; 1915 mlist1p = mlistp; 1916 } else { 1917 mlist2 = mlist; 1918 mlist2_sz = mlist_sz; 1919 mlist2p = mlistp; 1920 } 1921 } 1922 1923 static void 1924 fd_cleanup(void) 1925 { 1926 if (ifd != -1) { 1927 (void) close(ifd); 1928 ifd = -1; 1929 } 1930 if (elffd != -1) { 1931 (void) close(elffd); 1932 elffd = -1; 1933 } 1934 } 1935