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 }