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 /* LINTED: pointer cast may result in improper alignment */ 637 } else if (*(int *)fbuf == CORE_MAGIC) { 638 /* LINTED: pointer cast may result in improper alignment */ 639 struct core *corep = (struct core *)fbuf; 640 641 (void) printf("a.out core file"); 642 643 if (*(corep->c_cmdname) != '\0') 644 (void) printf(" from '%s'", corep->c_cmdname); 645 (void) putchar('\n'); 646 return (1); 647 } 648 649 /* 650 * Runtime linker (ld.so.1) configuration file. 651 */ 652 if (is_rtld_config()) 653 return (1); 654 655 /* 656 * ZIP files, JAR files, and Java executables 657 */ 658 if (zipfile(fbuf, ifd)) 659 return (1); 660 661 if (is_crash_dump(fbuf, ifd)) 662 return (1); 663 664 /* 665 * ChecK against Magic Table entries. 666 * The magic entries checked here always start with default 667 * magic tests and may be followed by other, non-default magic 668 * tests. If no default tests are to be executed, all the 669 * magic tests should have been in the first magic table. 670 */ 671 switch (f_ckmtab(magicbuf, mread, 0)) { 672 case -1: /* Error */ 673 exit(2); 674 break; 675 case 0: /* Not magic */ 676 return (0); 677 /* NOTREACHED */ 678 break; 679 default: /* Switch is magic index */ 680 681 /* 682 * f_ckmtab recognizes file type, 683 * check if it is PostScript. 684 * if not, check if elf or a.out 685 */ 686 if (magicbuf[0] == '%' && magicbuf[1] == '!') { 687 (void) putchar('\n'); 688 } else { 689 690 /* 691 * Check that the file is executable (dynamic 692 * objects must be executable to be exec'ed, 693 * shared objects need not be, but by convention 694 * should be executable). 695 * 696 * Note that we should already have processed 697 * the file if it was an ELF file. 698 */ 699 ar_coff_or_aout(elffd); 700 (void) putchar('\n'); 701 } 702 return (1); 703 /* NOTREACHED */ 704 break; 705 } 706 707 return (0); /* file was not identified */ 708 } 709 710 /* 711 * def_context_tests() - default context-sensitive tests. 712 * These are the last tests to be applied. 713 * If no match is found, prints out "data". 714 */ 715 716 static void 717 def_context_tests(void) 718 { 719 int j; 720 int nl; 721 char ch; 722 int len; 723 724 if (ccom() == 0) 725 goto notc; 726 while (fbuf[i] == '#') { 727 j = i; 728 while (fbuf[i++] != '\n') { 729 if (i - j > 255) { 730 (void) printf(gettext("data\n")); 731 return; 732 } 733 if (i >= fbsz) 734 goto notc; 735 } 736 if (ccom() == 0) 737 goto notc; 738 } 739 check: 740 if (lookup(c) == 1) { 741 while ((ch = fbuf[i]) != ';' && ch != '{') { 742 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 743 len = 1; 744 i += len; 745 if (i >= fbsz) 746 goto notc; 747 } 748 (void) printf(gettext("c program text")); 749 goto outa; 750 } 751 nl = 0; 752 while (fbuf[i] != '(') { 753 if (fbuf[i] <= 0) 754 goto notas; 755 if (fbuf[i] == ';') { 756 i++; 757 goto check; 758 } 759 if (fbuf[i++] == '\n') 760 if (nl++ > 6) 761 goto notc; 762 if (i >= fbsz) 763 goto notc; 764 } 765 while (fbuf[i] != ')') { 766 if (fbuf[i++] == '\n') 767 if (nl++ > 6) 768 goto notc; 769 if (i >= fbsz) 770 goto notc; 771 } 772 while (fbuf[i] != '{') { 773 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 774 len = 1; 775 if (fbuf[i] == '\n') 776 if (nl++ > 6) 777 goto notc; 778 i += len; 779 if (i >= fbsz) 780 goto notc; 781 } 782 (void) printf(gettext("c program text")); 783 goto outa; 784 notc: 785 i = 0; /* reset to begining of file again */ 786 while (fbuf[i] == 'c' || fbuf[i] == 'C'|| fbuf[i] == '!' || 787 fbuf[i] == '*' || fbuf[i] == '\n') { 788 while (fbuf[i++] != '\n') 789 if (i >= fbsz) 790 goto notfort; 791 } 792 if (lookup(fort) == 1) { 793 (void) printf(gettext("fortran program text")); 794 goto outa; 795 } 796 notfort: /* looking for assembler program */ 797 i = 0; /* reset to beginning of file again */ 798 if (ccom() == 0) /* assembler programs may contain */ 799 /* c-style comments */ 800 goto notas; 801 if (ascom() == 0) 802 goto notas; 803 j = i - 1; 804 if (fbuf[i] == '.') { 805 i++; 806 if (lookup(as) == 1) { 807 (void) printf(gettext("assembler program text")); 808 goto outa; 809 } else if (j != -1 && fbuf[j] == '\n' && isalpha(fbuf[j + 2])) { 810 (void) printf( 811 gettext("[nt]roff, tbl, or eqn input text")); 812 goto outa; 813 } 814 } 815 while (lookup(asc) == 0) { 816 if (ccom() == 0) 817 goto notas; 818 if (ascom() == 0) 819 goto notas; 820 while (fbuf[i] != '\n' && fbuf[i++] != ':') { 821 if (i >= fbsz) 822 goto notas; 823 } 824 while (fbuf[i] == '\n' || fbuf[i] == ' ' || fbuf[i] == '\t') 825 if (i++ >= fbsz) 826 goto notas; 827 j = i - 1; 828 if (fbuf[i] == '.') { 829 i++; 830 if (lookup(as) == 1) { 831 (void) printf( 832 gettext("assembler program text")); 833 goto outa; 834 } else if (fbuf[j] == '\n' && isalpha(fbuf[j+2])) { 835 (void) printf( 836 gettext("[nt]roff, tbl, or eqn input " 837 "text")); 838 goto outa; 839 } 840 } 841 } 842 (void) printf(gettext("assembler program text")); 843 goto outa; 844 notas: 845 /* start modification for multibyte env */ 846 IS_ascii = 1; 847 if (fbsz < FBSZ) 848 Max = fbsz; 849 else 850 Max = FBSZ - MB_LEN_MAX; /* prevent cut of wchar read */ 851 /* end modification for multibyte env */ 852 853 for (i = 0; i < Max; /* null */) 854 if (fbuf[i] & 0200) { 855 IS_ascii = 0; 856 if ((fbuf[0] == '\100') && 857 ((uchar_t)fbuf[1] == (uchar_t)'\357')) { 858 (void) printf(gettext("troff output\n")); 859 return; 860 } 861 /* start modification for multibyte env */ 862 if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX)) 863 <= 0 || !iswprint(wchar)) { 864 (void) printf(gettext("data\n")); 865 return; 866 } 867 i += length; 868 } 869 else 870 i++; 871 i = fbsz; 872 /* end modification for multibyte env */ 873 if (mbuf.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH)) 874 (void) printf(gettext("commands text")); 875 else if (troffint(fbuf, fbsz)) 876 (void) printf(gettext("troff intermediate output text")); 877 else if (english(fbuf, fbsz)) 878 (void) printf(gettext("English text")); 879 else if (IS_ascii) 880 (void) printf(gettext("ascii text")); 881 else 882 (void) printf(gettext("text")); /* for multibyte env */ 883 outa: 884 /* 885 * This code is to make sure that no MB char is cut in half 886 * while still being used. 887 */ 888 fbsz = (fbsz < FBSZ ? fbsz : fbsz - MB_CUR_MAX + 1); 889 while (i < fbsz) { 890 if (isascii(fbuf[i])) { 891 i++; 892 continue; 893 } else { 894 if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX)) 895 <= 0 || !iswprint(wchar)) { 896 (void) printf(gettext(" with garbage\n")); 897 return; 898 } 899 i = i + length; 900 } 901 } 902 (void) printf("\n"); 903 } 904 905 static int 906 troffint(char *bp, int n) 907 { 908 int k; 909 910 i = 0; 911 for (k = 0; k < 6; k++) { 912 if (lookup(troff) == 0) 913 return (0); 914 if (lookup(troff) == 0) 915 return (0); 916 while (i < n && bp[i] != '\n') 917 i++; 918 if (i++ >= n) 919 return (0); 920 } 921 return (1); 922 } 923 924 static void 925 ar_coff_or_aout(int elffd) 926 { 927 Elf *elf; 928 929 /* 930 * Get the files elf descriptor and process it as an elf or 931 * a.out (4.x) file. 932 */ 933 934 elf = elf_begin(elffd, ELF_C_READ, (Elf *)0); 935 switch (elf_kind(elf)) { 936 case ELF_K_AR : 937 (void) printf(gettext(", not a dynamic executable " 938 "or shared object")); 939 break; 940 case ELF_K_COFF: 941 (void) printf(gettext(", unsupported or unknown " 942 "file type")); 943 break; 944 default: 945 /* 946 * This is either an unknown file or an aout format 947 * At this time, we don't print dynamic/stripped 948 * info. on a.out or non-Elf binaries. 949 */ 950 break; 951 } 952 (void) elf_end(elf); 953 } 954 955 956 static void 957 print_elf_type(Elf_Info EI) 958 { 959 switch (EI.type) { 960 case ET_NONE: 961 (void) printf(" %s", gettext("unknown type")); 962 break; 963 case ET_REL: 964 (void) printf(" %s", gettext("relocatable")); 965 break; 966 case ET_EXEC: 967 (void) printf(" %s", gettext("executable")); 968 break; 969 case ET_DYN: 970 (void) printf(" %s", gettext("dynamic lib")); 971 break; 972 default: 973 break; 974 } 975 } 976 977 static void 978 print_elf_machine(int machine) 979 { 980 /* 981 * This table must be kept in sync with the EM_ constants 982 * in /usr/include/sys/elf.h. 983 */ 984 static const char *mach_str[EM_NUM] = { 985 [EM_NONE] = "unknown machine", 986 [EM_M32] = "WE32100", 987 [EM_SPARC] = "SPARC", 988 [EM_386] = "80386", 989 [EM_68K] = "M68000", 990 [EM_88K] = "M88000", 991 [EM_486] = "80486", 992 [EM_860] = "i860", 993 [EM_MIPS] = "MIPS RS3000 Big-Endian", 994 [EM_S370] = "S/370", 995 [EM_MIPS_RS3_LE] = "MIPS RS3000 Little-Endian", 996 [EM_RS6000] = "MIPS RS6000", 997 [EM_PA_RISC] = "PA-RISC", 998 [EM_nCUBE] = "nCUBE", 999 [EM_VPP500] = "VPP500", 1000 [EM_SPARC32PLUS] = "SPARC32PLUS", 1001 [EM_960] = "i960", 1002 [EM_PPC] = "PowerPC", 1003 [EM_PPC64] = "PowerPC64", 1004 [EM_S390] = "S/390", 1005 [EM_V800] = "V800", 1006 [EM_FR20] = "FR20", 1007 [EM_RH32] = "RH32", 1008 [EM_RCE] = "RCE", 1009 [EM_ARM] = "ARM", 1010 [EM_ALPHA] = "Alpha", 1011 [EM_SH] = "S/390", 1012 [EM_SPARCV9] = "SPARCV9", 1013 [EM_TRICORE] = "Tricore", 1014 [EM_ARC] = "ARC", 1015 [EM_H8_300] = "H8/300", 1016 [EM_H8_300H] = "H8/300H", 1017 [EM_H8S] = "H8S", 1018 [EM_H8_500] = "H8/500", 1019 [EM_IA_64] = "IA64", 1020 [EM_MIPS_X] = "MIPS-X", 1021 [EM_COLDFIRE] = "Coldfire", 1022 [EM_68HC12] = "M68HC12", 1023 [EM_MMA] = "MMA", 1024 [EM_PCP] = "PCP", 1025 [EM_NCPU] = "nCPU", 1026 [EM_NDR1] = "NDR1", 1027 [EM_STARCORE] = "Starcore", 1028 [EM_ME16] = "ME16", 1029 [EM_ST100] = "ST100", 1030 [EM_TINYJ] = "TINYJ", 1031 [EM_AMD64] = "AMD64", 1032 [EM_PDSP] = "PDSP", 1033 [EM_FX66] = "FX66", 1034 [EM_ST9PLUS] = "ST9 PLUS", 1035 [EM_ST7] = "ST7", 1036 [EM_68HC16] = "68HC16", 1037 [EM_68HC11] = "68HC11", 1038 [EM_68HC08] = "68H08", 1039 [EM_68HC05] = "68HC05", 1040 [EM_SVX] = "SVX", 1041 [EM_ST19] = "ST19", 1042 [EM_VAX] = "VAX", 1043 [EM_CRIS] = "CRIS", 1044 [EM_JAVELIN] = "Javelin", 1045 [EM_FIREPATH] = "Firepath", 1046 [EM_ZSP] = "ZSP", 1047 [EM_MMIX] = "MMIX", 1048 [EM_HUANY] = "HUANY", 1049 [EM_PRISM] = "Prism", 1050 [EM_AVR] = "AVR", 1051 [EM_FR30] = "FR30", 1052 [EM_D10V] = "D10V", 1053 [EM_D30V] = "D30V", 1054 [EM_V850] = "V850", 1055 [EM_M32R] = "M32R", 1056 [EM_MN10300] = "MN10300", 1057 [EM_MN10200] = "MN10200", 1058 [EM_PJ] = "picoJava", 1059 [EM_OPENRISC] = "OpenRISC", 1060 [EM_ARC_A5] = "Tangent-A5", 1061 [EM_XTENSA] = "Xtensa", 1062 1063 [EM_VIDEOCORE] = "Videocore", 1064 [EM_TMM_GPP] = "TMM_GPP", 1065 [EM_NS32K] = "NS32K", 1066 [EM_TPC] = "TPC", 1067 [EM_SNP1K] = "SNP1K", 1068 [EM_ST200] = "ST200", 1069 [EM_IP2K] = "IP2K", 1070 [EM_MAX] = "MAX", 1071 [EM_CR] = "CompactRISC", 1072 [EM_F2MC16] = "F2MC16", 1073 [EM_MSP430] = "MSP430", 1074 [EM_BLACKFIN] = "Blackfin", 1075 [EM_SE_C33] = "S1C33", 1076 [EM_SEP] = "SEP", 1077 [EM_ARCA] = "Arca", 1078 [EM_UNICORE] = "Unicore", 1079 [EM_EXCESS] = "eXcess", 1080 [EM_DXP] = "DXP", 1081 [EM_ALTERA_NIOS2] = "Nios 2", 1082 [EM_CRX] = "CompactRISC CRX", 1083 [EM_XGATE] = "XGATE", 1084 [EM_C166] = "C16x/XC16x", 1085 [EM_M16C] = "M16C", 1086 [EM_DSPIC30F] = "dsPIC30F", 1087 [EM_CE] = "CE RISC", 1088 [EM_M32C] = "M32C", 1089 [EM_TSK3000] = "TSK3000", 1090 [EM_RS08] = "RS08", 1091 [EM_SHARC] = "SHARC", 1092 [EM_ECOG2] = "eCOG2", 1093 [EM_SCORE7] = "SCORE7", 1094 [EM_DSP24] = "DSP24", 1095 [EM_VIDEOCORE3] = "Videocore III", 1096 [EM_LATTICEMICO32] = "LATTICEMICO32", 1097 [EM_SE_C17] = "SE_C17", 1098 [EM_TI_C6000] = "TMS320C6000", 1099 [EM_TI_C2000] = "TMS320C2000", 1100 [EM_TI_C5500] = "TMS320C55x", 1101 [EM_TI_ARP32] = "ASRP32", 1102 [EM_TI_PRU] = "TI_PRU", 1103 [EM_MMDSP_PLUS] = "MMDSP_PLUS", 1104 [EM_CYPRESS_M8C] = "M8C", 1105 [EM_R32C] = "R32C", 1106 [EM_TRIMEDIA] = "TriMedia", 1107 [EM_QDSP6] = "QDSP6", 1108 [EM_8051] = "8051", 1109 [EM_STXP7X] = "STxP7x", 1110 [EM_NDS32] = "NDS32", 1111 [EM_ECOG1] = "eCOG1X", 1112 [EM_MAXQ30] = "MAXQ30", 1113 [EM_XIMO16] = "XIMO16", 1114 [EM_MANIK] = "M2000", 1115 [EM_CRAYNV2] = "CRAYNV2", 1116 [EM_RX] = "RX", 1117 [EM_METAG] = "METAG", 1118 [EM_MCST_ELBRUS] = "Elbrus", 1119 [EM_ECOG16] = "eCOG16", 1120 [EM_CR16] = "CR16", 1121 [EM_ETPU] = "ETPU", 1122 [EM_SLE9X] = "SLE9X", 1123 [EM_L10M] = "L10M", 1124 [EM_K10M] = "K10M", 1125 1126 [EM_AARCH64] = "aarch64", 1127 1128 [EM_AVR32] = "AVR32", 1129 [EM_STM8] = "STM8", 1130 [EM_TILE64] = "TILE64", 1131 [EM_TILEPRO] = "TILEPRO", 1132 [EM_MICROBLAZE] = "MicroBlaze", 1133 [EM_CUDA] = "CUDA", 1134 [EM_TILEGX] = "TILE-Gx", 1135 [EM_CLOUDSHIELD] = "CloudShield", 1136 [EM_COREA_1ST] = "CORE-A 1st", 1137 [EM_COREA_2ND] = "CORE-A 2nd", 1138 [EM_ARC_COMPACT2] = "ARCompact V2", 1139 [EM_OPEN8] = "Open8", 1140 [EM_RL78] = "RL78", 1141 [EM_VIDEOCORE5] = "VideoCore V", 1142 [EM_78KOR] = "78KOR", 1143 [EM_56800EX] = "56800EX", 1144 [EM_BA1] = "BA1", 1145 [EM_BA2] = "BA2", 1146 [EM_XCORE] = "xCORE", 1147 [EM_MCHP_PIC] = "MCHP_PIC", 1148 [EM_KM32] = "KM32", 1149 [EM_KMX32] = "KMX32", 1150 [EM_KMX16] = "KMX16", 1151 [EM_KMX8] = "KMX8", 1152 [EM_KVARC] = "KVARC", 1153 [EM_CDP] = "CDP", 1154 [EM_COGE] = "COGE", 1155 [EM_COOL] = "CoolEngine", 1156 [EM_NORC] = "NORC", 1157 [EM_CSR_KALIMBA] = "Kalimba", 1158 [EM_Z80] = "Zilog Z80", 1159 [EM_VISIUM] = "VISIUMcore", 1160 [EM_FT32] = "FT32", 1161 [EM_MOXIE] = "Moxie", 1162 [EM_AMDGPU] = "AMD GPU", 1163 [EM_RISCV] = "RISC-V" 1164 }; 1165 /* If new machine is added, refuse to compile until we're updated */ 1166 #if EM_NUM != 244 1167 #error "Number of known ELF machine constants has changed" 1168 #endif 1169 1170 const char *str; 1171 1172 if ((machine < EM_NONE) || (machine >= EM_NUM)) 1173 machine = EM_NONE; 1174 1175 str = mach_str[machine]; 1176 if (str) 1177 (void) printf(" %s", str); 1178 } 1179 1180 static void 1181 print_elf_datatype(int datatype) 1182 { 1183 switch (datatype) { 1184 case ELFDATA2LSB: 1185 (void) printf(" LSB"); 1186 break; 1187 case ELFDATA2MSB: 1188 (void) printf(" MSB"); 1189 break; 1190 default: 1191 break; 1192 } 1193 } 1194 1195 static void 1196 print_elf_class(int class) 1197 { 1198 switch (class) { 1199 case ELFCLASS32: 1200 (void) printf(" %s", gettext("32-bit")); 1201 break; 1202 case ELFCLASS64: 1203 (void) printf(" %s", gettext("64-bit")); 1204 break; 1205 default: 1206 break; 1207 } 1208 } 1209 1210 static void 1211 print_elf_flags(Elf_Info EI) 1212 { 1213 unsigned int flags; 1214 1215 flags = EI.flags; 1216 switch (EI.machine) { 1217 case EM_SPARCV9: 1218 if (flags & EF_SPARC_EXT_MASK) { 1219 if (flags & EF_SPARC_SUN_US3) { 1220 (void) printf("%s", gettext( 1221 ", UltraSPARC3 Extensions Required")); 1222 } else if (flags & EF_SPARC_SUN_US1) { 1223 (void) printf("%s", gettext( 1224 ", UltraSPARC1 Extensions Required")); 1225 } 1226 if (flags & EF_SPARC_HAL_R1) 1227 (void) printf("%s", gettext( 1228 ", HaL R1 Extensions Required")); 1229 } 1230 break; 1231 case EM_SPARC32PLUS: 1232 if (flags & EF_SPARC_32PLUS) 1233 (void) printf("%s", gettext(", V8+ Required")); 1234 if (flags & EF_SPARC_SUN_US3) { 1235 (void) printf("%s", 1236 gettext(", UltraSPARC3 Extensions Required")); 1237 } else if (flags & EF_SPARC_SUN_US1) { 1238 (void) printf("%s", 1239 gettext(", UltraSPARC1 Extensions Required")); 1240 } 1241 if (flags & EF_SPARC_HAL_R1) 1242 (void) printf("%s", 1243 gettext(", HaL R1 Extensions Required")); 1244 break; 1245 default: 1246 break; 1247 } 1248 } 1249 1250 /* 1251 * check_ident: checks the ident field of the presumeably 1252 * elf file. If check fails, this is not an 1253 * elf file. 1254 */ 1255 static int 1256 check_ident(unsigned char *ident, int fd) 1257 { 1258 int class; 1259 if (pread64(fd, ident, EI_NIDENT, 0) != EI_NIDENT) 1260 return (ELF_READ_FAIL); 1261 class = ident[EI_CLASS]; 1262 if (class != ELFCLASS32 && class != ELFCLASS64) 1263 return (ELF_READ_FAIL); 1264 if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || 1265 ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) 1266 return (ELF_READ_FAIL); 1267 1268 return (ELF_READ_OKAY); 1269 } 1270 1271 static int 1272 elf_check(char *file) 1273 { 1274 Elf_Info EInfo; 1275 int class, version, format; 1276 unsigned char ident[EI_NIDENT]; 1277 1278 (void) memset(&EInfo, 0, sizeof (Elf_Info)); 1279 EInfo.file = file; 1280 1281 /* 1282 * Verify information in file indentifier. 1283 * Return quietly if not elf; Different type of file. 1284 */ 1285 if (check_ident(ident, elffd) == ELF_READ_FAIL) 1286 return (1); 1287 1288 /* 1289 * Read the elf headers for processing and get the 1290 * get the needed information in Elf_Info struct. 1291 */ 1292 class = ident[EI_CLASS]; 1293 if (class == ELFCLASS32) { 1294 if (elf_read32(elffd, &EInfo) == ELF_READ_FAIL) { 1295 (void) fprintf(stderr, gettext("%s: %s: can't " 1296 "read ELF header\n"), File, file); 1297 return (1); 1298 } 1299 } else if (class == ELFCLASS64) { 1300 if (elf_read64(elffd, &EInfo) == ELF_READ_FAIL) { 1301 (void) fprintf(stderr, gettext("%s: %s: can't " 1302 "read ELF header\n"), File, file); 1303 return (1); 1304 } 1305 } else { 1306 /* something wrong */ 1307 return (1); 1308 } 1309 1310 /* version not in ident then 1 */ 1311 version = ident[EI_VERSION] ? ident[EI_VERSION] : 1; 1312 1313 format = ident[EI_DATA]; 1314 (void) printf("%s", gettext("ELF")); 1315 print_elf_class(class); 1316 print_elf_datatype(format); 1317 print_elf_type(EInfo); 1318 1319 if (EInfo.core_type != EC_NOTCORE) { 1320 /* Print what kind of core is this */ 1321 if (EInfo.core_type == EC_OLDCORE) 1322 (void) printf(" %s", gettext("pre-2.6 core file")); 1323 else 1324 (void) printf(" %s", gettext("core file")); 1325 } 1326 1327 /* Print machine info */ 1328 print_elf_machine(EInfo.machine); 1329 1330 /* Print Version */ 1331 if (version == 1) 1332 (void) printf(" %s %d", gettext("Version"), version); 1333 1334 if (EInfo.kmod) { 1335 (void) printf(", %s", gettext("kernel module")); 1336 } 1337 1338 /* Print Flags */ 1339 print_elf_flags(EInfo); 1340 1341 /* Last bit, if it is a core */ 1342 if (EInfo.core_type != EC_NOTCORE) { 1343 /* Print the program name that dumped this core */ 1344 (void) printf(gettext(", from '%s'"), EInfo.fname); 1345 return (0); 1346 } 1347 1348 /* Print Capabilities */ 1349 if (EInfo.cap_str[0] != '\0') 1350 (void) printf(" [%s]", EInfo.cap_str); 1351 1352 if ((EInfo.type != ET_EXEC) && (EInfo.type != ET_DYN)) 1353 return (0); 1354 1355 /* Print if it is dynamically linked */ 1356 if (EInfo.dynamic) 1357 (void) printf(gettext(", dynamically linked")); 1358 else 1359 (void) printf(gettext(", statically linked")); 1360 1361 /* Printf it it is stripped */ 1362 if (EInfo.stripped & E_SYMTAB) { 1363 (void) printf(gettext(", not stripped")); 1364 if (!(EInfo.stripped & E_DBGINF)) { 1365 (void) printf(gettext( 1366 ", no debugging information available")); 1367 } 1368 } else { 1369 (void) printf(gettext(", stripped")); 1370 } 1371 1372 return (0); 1373 } 1374 1375 /* 1376 * is_rtld_config - If file is a runtime linker config file, prints 1377 * the description and returns True (1). Otherwise, silently returns 1378 * False (0). 1379 */ 1380 int 1381 is_rtld_config(void) 1382 { 1383 Rtc_id *id; 1384 1385 if ((fbsz >= sizeof (*id)) && RTC_ID_TEST(fbuf)) { 1386 (void) printf(gettext("Runtime Linking Configuration")); 1387 id = (Rtc_id *) fbuf; 1388 print_elf_class(id->id_class); 1389 print_elf_datatype(id->id_data); 1390 print_elf_machine(id->id_machine); 1391 (void) printf("\n"); 1392 return (1); 1393 } 1394 1395 return (0); 1396 } 1397 1398 /* 1399 * lookup - 1400 * Attempts to match one of the strings from a list, 'tab', 1401 * with what is in the file, starting at the current index position 'i'. 1402 * Looks past any initial whitespace and expects whitespace or other 1403 * delimiting characters to follow the matched string. 1404 * A match identifies the file as being 'assembler', 'fortran', 'c', etc. 1405 * Returns 1 for a successful match, 0 otherwise. 1406 */ 1407 static int 1408 lookup(char **tab) 1409 { 1410 register char r; 1411 register int k, j, l; 1412 1413 while (fbuf[i] == ' ' || fbuf[i] == '\t' || fbuf[i] == '\n') 1414 i++; 1415 for (j = 0; tab[j] != 0; j++) { 1416 l = 0; 1417 for (k = i; ((r = tab[j][l++]) == fbuf[k] && r != '\0'); k++) 1418 ; 1419 if (r == '\0') 1420 if (fbuf[k] == ' ' || fbuf[k] == '\n' || 1421 fbuf[k] == '\t' || fbuf[k] == '{' || 1422 fbuf[k] == '/') { 1423 i = k; 1424 return (1); 1425 } 1426 } 1427 return (0); 1428 } 1429 1430 /* 1431 * ccom - 1432 * Increments the current index 'i' into the file buffer 'fbuf' past any 1433 * whitespace lines and C-style comments found, starting at the current 1434 * position of 'i'. Returns 1 as long as we don't increment i past the 1435 * size of fbuf (fbsz). Otherwise, returns 0. 1436 */ 1437 1438 static int 1439 ccom(void) 1440 { 1441 register char cc; 1442 int len; 1443 1444 while ((cc = fbuf[i]) == ' ' || cc == '\t' || cc == '\n') 1445 if (i++ >= fbsz) 1446 return (0); 1447 if (fbuf[i] == '/' && fbuf[i+1] == '*') { 1448 i += 2; 1449 while (fbuf[i] != '*' || fbuf[i+1] != '/') { 1450 if (fbuf[i] == '\\') 1451 i++; 1452 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0) 1453 len = 1; 1454 i += len; 1455 if (i >= fbsz) 1456 return (0); 1457 } 1458 if ((i += 2) >= fbsz) 1459 return (0); 1460 } 1461 if (fbuf[i] == '\n') 1462 if (ccom() == 0) 1463 return (0); 1464 return (1); 1465 } 1466 1467 /* 1468 * ascom - 1469 * Increments the current index 'i' into the file buffer 'fbuf' past 1470 * consecutive assembler program comment lines starting with ASCOMCHAR, 1471 * starting at the current position of 'i'. 1472 * Returns 1 as long as we don't increment i past the 1473 * size of fbuf (fbsz). Otherwise returns 0. 1474 */ 1475 1476 static int 1477 ascom(void) 1478 { 1479 while (fbuf[i] == ASCOMCHAR) { 1480 i++; 1481 while (fbuf[i++] != '\n') 1482 if (i >= fbsz) 1483 return (0); 1484 while (fbuf[i] == '\n') 1485 if (i++ >= fbsz) 1486 return (0); 1487 } 1488 return (1); 1489 } 1490 1491 /* look for "1hddddd" where d is a digit */ 1492 static int 1493 sccs(void) 1494 { 1495 register int j; 1496 1497 if (fbuf[0] == 1 && fbuf[1] == 'h') { 1498 for (j = 2; j <= 6; j++) { 1499 if (isdigit(fbuf[j])) 1500 continue; 1501 else 1502 return (0); 1503 } 1504 } else { 1505 return (0); 1506 } 1507 return (1); 1508 } 1509 1510 static int 1511 english(char *bp, int n) 1512 { 1513 #define NASC 128 /* number of ascii char ?? */ 1514 register int j, vow, freq, rare, len; 1515 register int badpun = 0, punct = 0; 1516 int ct[NASC]; 1517 1518 if (n < 50) 1519 return (0); /* no point in statistics on squibs */ 1520 for (j = 0; j < NASC; j++) 1521 ct[j] = 0; 1522 for (j = 0; j < n; j += len) { 1523 if ((unsigned char)bp[j] < NASC) 1524 ct[bp[j]|040]++; 1525 switch (bp[j]) { 1526 case '.': 1527 case ',': 1528 case ')': 1529 case '%': 1530 case ';': 1531 case ':': 1532 case '?': 1533 punct++; 1534 if (j < n-1 && bp[j+1] != ' ' && bp[j+1] != '\n') 1535 badpun++; 1536 } 1537 if ((len = mblen(&bp[j], MB_CUR_MAX)) <= 0) 1538 len = 1; 1539 } 1540 if (badpun*5 > punct) 1541 return (0); 1542 vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u']; 1543 freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n']; 1544 rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z']; 1545 if (2*ct[';'] > ct['e']) 1546 return (0); 1547 if ((ct['>'] + ct['<'] + ct['/']) > ct['e']) 1548 return (0); /* shell file test */ 1549 return (vow * 5 >= n - ct[' '] && freq >= 10 * rare); 1550 } 1551 1552 1553 static int 1554 shellscript(char buf[], struct stat64 *sb) 1555 { 1556 char *tp, *cp, *xp, *up, *gp; 1557 1558 cp = strchr(buf, '\n'); 1559 if (cp == NULL || cp - fbuf > fbsz) 1560 return (0); 1561 for (tp = buf; tp != cp && isspace((unsigned char)*tp); tp++) 1562 if (!isascii(*tp)) 1563 return (0); 1564 for (xp = tp; tp != cp && !isspace((unsigned char)*tp); tp++) 1565 if (!isascii(*tp)) 1566 return (0); 1567 if (tp == xp) 1568 return (0); 1569 if (sb->st_mode & S_ISUID) 1570 up = gettext("set-uid "); 1571 else 1572 up = ""; 1573 1574 if (sb->st_mode & S_ISGID) 1575 gp = gettext("set-gid "); 1576 else 1577 gp = ""; 1578 1579 if (strncmp(xp, "/bin/sh", tp - xp) == 0) 1580 xp = gettext("shell"); 1581 else if (strncmp(xp, "/bin/csh", tp - xp) == 0) 1582 xp = gettext("c-shell"); 1583 else if (strncmp(xp, "/usr/sbin/dtrace", tp - xp) == 0) 1584 xp = gettext("DTrace"); 1585 else 1586 *tp = '\0'; 1587 /* 1588 * TRANSLATION_NOTE 1589 * This message is printed by file command for shell scripts. 1590 * The first %s is for the translation for "set-uid " (if the script 1591 * has the set-uid bit set), or is for an empty string (if the 1592 * script does not have the set-uid bit set). 1593 * Similarly, the second %s is for the translation for "set-gid ", 1594 * or is for an empty string. 1595 * The third %s is for the translation for either: "shell", "c-shell", 1596 * or "DTrace", or is for the pathname of the program the script 1597 * executes. 1598 */ 1599 (void) printf(gettext("%s%sexecutable %s script\n"), up, gp, xp); 1600 return (1); 1601 } 1602 1603 static int 1604 get_door_target(char *file, char *buf, size_t bufsize) 1605 { 1606 int fd; 1607 door_info_t di; 1608 psinfo_t psinfo; 1609 1610 if ((fd = open64(file, O_RDONLY)) < 0 || 1611 door_info(fd, &di) != 0) { 1612 if (fd >= 0) 1613 (void) close(fd); 1614 return (-1); 1615 } 1616 (void) close(fd); 1617 1618 (void) sprintf(buf, "/proc/%ld/psinfo", di.di_target); 1619 if ((fd = open64(buf, O_RDONLY)) < 0 || 1620 read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) { 1621 if (fd >= 0) 1622 (void) close(fd); 1623 return (-1); 1624 } 1625 (void) close(fd); 1626 1627 (void) snprintf(buf, bufsize, "%s[%ld]", psinfo.pr_fname, di.di_target); 1628 return (0); 1629 } 1630 1631 /* 1632 * ZIP file header information 1633 */ 1634 #define SIGSIZ 4 1635 #define LOCSIG "PK\003\004" 1636 #define LOCHDRSIZ 30 1637 1638 #define CH(b, n) (((unsigned char *)(b))[n]) 1639 #define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8)) 1640 #define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16)) 1641 1642 #define LOCNAM(b) (SH(b, 26)) /* filename size */ 1643 #define LOCEXT(b) (SH(b, 28)) /* extra field size */ 1644 1645 #define XFHSIZ 4 /* header id, data size */ 1646 #define XFHID(b) (SH(b, 0)) /* extract field header id */ 1647 #define XFDATASIZ(b) (SH(b, 2)) /* extract field data size */ 1648 #define XFJAVASIG 0xcafe /* java executables */ 1649 1650 static int 1651 zipfile(char *fbuf, int fd) 1652 { 1653 off_t xoff, xoff_end; 1654 1655 if (strncmp(fbuf, LOCSIG, SIGSIZ) != 0) 1656 return (0); 1657 1658 xoff = LOCHDRSIZ + LOCNAM(fbuf); 1659 xoff_end = xoff + LOCEXT(fbuf); 1660 1661 while (xoff < xoff_end) { 1662 char xfhdr[XFHSIZ]; 1663 1664 if (pread(fd, xfhdr, XFHSIZ, xoff) != XFHSIZ) 1665 break; 1666 1667 if (XFHID(xfhdr) == XFJAVASIG) { 1668 (void) printf("%s\n", gettext("java archive file")); 1669 return (1); 1670 } 1671 xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr); 1672 } 1673 1674 /* 1675 * We could just print "ZIP archive" here. 1676 * 1677 * However, customers may be using their own entries in 1678 * /etc/magic to distinguish one kind of ZIP file from another, so 1679 * let's defer the printing of "ZIP archive" to there. 1680 */ 1681 return (0); 1682 } 1683 1684 static int 1685 is_crash_dump(const char *buf, int fd) 1686 { 1687 /* LINTED: pointer cast may result in improper alignment */ 1688 const dumphdr_t *dhp = (const dumphdr_t *)buf; 1689 1690 /* 1691 * The current DUMP_MAGIC string covers Solaris 7 and later releases. 1692 * The utsname struct is only present in dumphdr_t's with dump_version 1693 * greater than or equal to 9. 1694 */ 1695 if (dhp->dump_magic == DUMP_MAGIC) { 1696 print_dumphdr(fd, dhp, return_uint32, NATIVE_ISA); 1697 1698 } else if (dhp->dump_magic == swap_uint32(DUMP_MAGIC)) { 1699 print_dumphdr(fd, dhp, swap_uint32, OTHER_ISA); 1700 1701 } else if (dhp->dump_magic == OLD_DUMP_MAGIC || 1702 dhp->dump_magic == swap_uint32(OLD_DUMP_MAGIC)) { 1703 char *isa = (dhp->dump_magic == OLD_DUMP_MAGIC ? 1704 NATIVE_ISA : OTHER_ISA); 1705 (void) printf(gettext("SunOS 32-bit %s crash dump\n"), isa); 1706 1707 } else { 1708 return (0); 1709 } 1710 1711 return (1); 1712 } 1713 1714 static void 1715 print_dumphdr(const int fd, const dumphdr_t *dhp, uint32_t (*swap)(uint32_t), 1716 const char *isa) 1717 { 1718 dumphdr_t dh; 1719 1720 /* 1721 * A dumphdr_t is bigger than FBSZ, so we have to manually read the 1722 * rest of it. 1723 */ 1724 if (swap(dhp->dump_version) > 8 && pread(fd, &dh, sizeof (dumphdr_t), 1725 (off_t)0) == sizeof (dumphdr_t)) { 1726 const char *c = swap(dh.dump_flags) & DF_COMPRESSED ? 1727 "compressed " : ""; 1728 const char *l = swap(dh.dump_flags) & DF_LIVE ? 1729 "live" : "crash"; 1730 1731 (void) printf(gettext( 1732 "%s %s %s %u-bit %s %s%s dump from '%s'\n"), 1733 dh.dump_utsname.sysname, dh.dump_utsname.release, 1734 dh.dump_utsname.version, swap(dh.dump_wordsize), isa, 1735 c, l, dh.dump_utsname.nodename); 1736 } else { 1737 (void) printf(gettext("SunOS %u-bit %s crash dump\n"), 1738 swap(dhp->dump_wordsize), isa); 1739 } 1740 } 1741 1742 static void 1743 usage(void) 1744 { 1745 (void) fprintf(stderr, gettext( 1746 "usage: file [-bdh] [-M mfile] [-m mfile] [-f ffile] file ...\n" 1747 " file [-bdh] [-M mfile] [-m mfile] -f ffile\n" 1748 " file -i [-bh] [-f ffile] file ...\n" 1749 " file -i [-bh] -f ffile\n" 1750 " file -c [-d] [-M mfile] [-m mfile]\n")); 1751 exit(2); 1752 } 1753 1754 static uint32_t 1755 swap_uint32(uint32_t in) 1756 { 1757 uint32_t out; 1758 1759 out = (in & 0x000000ff) << 24; 1760 out |= (in & 0x0000ff00) << 8; /* >> 8 << 16 */ 1761 out |= (in & 0x00ff0000) >> 8; /* >> 16 << 8 */ 1762 out |= (in & 0xff000000) >> 24; 1763 1764 return (out); 1765 } 1766 1767 static uint32_t 1768 return_uint32(uint32_t in) 1769 { 1770 return (in); 1771 } 1772 1773 /* 1774 * Check if str is in the string list str_list. 1775 */ 1776 int 1777 is_in_list(char *str) 1778 { 1779 int i; 1780 1781 /* 1782 * Only need to compare the strlen(str_list[i]) bytes. 1783 * That way .stab will match on .stab* sections, and 1784 * .debug will match on .debug* sections. 1785 */ 1786 for (i = 0; debug_sections[i] != NULL; i++) { 1787 if (strncmp(debug_sections[i], str, 1788 strlen(debug_sections[i])) == 0) { 1789 return (1); 1790 } 1791 } 1792 return (0); 1793 } 1794 1795 /* 1796 * default_magic - 1797 * allocate space for and create the default magic file 1798 * name string. 1799 */ 1800 1801 static void 1802 default_magic(void) 1803 { 1804 const char *msg_locale = setlocale(LC_MESSAGES, NULL); 1805 struct stat statbuf; 1806 1807 if ((dfile = malloc(strlen(msg_locale) + 35)) == NULL) { 1808 int err = errno; 1809 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 1810 File, strerror(err)); 1811 exit(2); 1812 } 1813 (void) snprintf(dfile, strlen(msg_locale) + 35, 1814 "/usr/lib/locale/%s/LC_MESSAGES/magic", msg_locale); 1815 if (stat(dfile, &statbuf) != 0) { 1816 (void) strcpy(dfile, "/etc/magic"); 1817 } 1818 } 1819 1820 /* 1821 * add_to_mlist - 1822 * Add the given magic_file filename string to the list of magic 1823 * files (mlist). This list of files will later be examined, and 1824 * each magic file's entries will be added in order to 1825 * the mtab table. 1826 * 1827 * The first flag is set to 1 to add to the first list, mlist1. 1828 * The first flag is set to 0 to add to the second list, mlist2. 1829 */ 1830 1831 static void 1832 add_to_mlist(char *magic_file, int first) 1833 { 1834 char **mlist; /* ordered list of magic files */ 1835 size_t mlist_sz; /* number of pointers allocated for mlist */ 1836 char **mlistp; /* next entry in mlist */ 1837 size_t mlistp_off; 1838 1839 if (first) { 1840 mlist = mlist1; 1841 mlist_sz = mlist1_sz; 1842 mlistp = mlist1p; 1843 } else { 1844 mlist = mlist2; 1845 mlist_sz = mlist2_sz; 1846 mlistp = mlist2p; 1847 } 1848 1849 if (mlist == NULL) { /* initial mlist allocation */ 1850 if ((mlist = calloc(MLIST_SZ, sizeof (char *))) == NULL) { 1851 int err = errno; 1852 (void) fprintf(stderr, gettext("%s: malloc " 1853 "failed: %s\n"), File, strerror(err)); 1854 exit(2); 1855 } 1856 mlist_sz = MLIST_SZ; 1857 mlistp = mlist; 1858 } 1859 if ((mlistp - mlist) >= mlist_sz) { 1860 mlistp_off = mlistp - mlist; 1861 mlist_sz *= 2; 1862 if ((mlist = realloc(mlist, 1863 mlist_sz * sizeof (char *))) == NULL) { 1864 int err = errno; 1865 (void) fprintf(stderr, gettext("%s: malloc " 1866 "failed: %s\n"), File, strerror(err)); 1867 exit(2); 1868 } 1869 mlistp = mlist + mlistp_off; 1870 } 1871 /* 1872 * now allocate memory for and copy the 1873 * magic file name string 1874 */ 1875 if ((*mlistp = malloc(strlen(magic_file) + 1)) == NULL) { 1876 int err = errno; 1877 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), 1878 File, strerror(err)); 1879 exit(2); 1880 } 1881 (void) strlcpy(*mlistp, magic_file, strlen(magic_file) + 1); 1882 mlistp++; 1883 1884 if (first) { 1885 mlist1 = mlist; 1886 mlist1_sz = mlist_sz; 1887 mlist1p = mlistp; 1888 } else { 1889 mlist2 = mlist; 1890 mlist2_sz = mlist_sz; 1891 mlist2p = mlistp; 1892 } 1893 } 1894 1895 static void 1896 fd_cleanup(void) 1897 { 1898 if (ifd != -1) { 1899 (void) close(ifd); 1900 ifd = -1; 1901 } 1902 if (elffd != -1) { 1903 (void) close(elffd); 1904 elffd = -1; 1905 } 1906 }