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 }