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