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  */
  32 
  33 #define _LARGEFILE64_SOURCE
  34 
  35 /* Get definitions for the relocation types supported. */
  36 #define ELF_TARGET_ALL
  37 
  38 #include <ctype.h>
  39 #include <unistd.h>
  40 #include <fcntl.h>
  41 #include <signal.h>
  42 #include <stdio.h>
  43 #include <libelf.h>
  44 #include <stdlib.h>
  45 #include <limits.h>
  46 #include <locale.h>
  47 #include <wctype.h>
  48 #include <string.h>
  49 #include <errno.h>
  50 #include <door.h>
  51 #include <sys/param.h>
  52 #include <sys/types.h>
  53 #include <sys/mkdev.h>
  54 #include <sys/stat.h>
  55 #include <sys/elf.h>
  56 #include <procfs.h>
  57 #include <sys/core.h>
  58 #include <sys/dumphdr.h>
  59 #include <netinet/in.h>
  60 #include <gelf.h>
  61 #include <elfcap.h>
  62 #include <sgsrtcid.h>
  63 #include "file.h"
  64 #include "elf_read.h"
  65 
  66 /*
  67  *      Misc
  68  */
  69 
  70 #define FBSZ            512
  71 #define MLIST_SZ        12
  72 
  73 /*
  74  * The 0x8FCA0102 magic string was used in crash dumps generated by releases
  75  * prior to Solaris 7.
  76  */
  77 #define OLD_DUMP_MAGIC  0x8FCA0102
  78 
  79 #if defined(__sparc)
  80 #define NATIVE_ISA      "SPARC"
  81 #define OTHER_ISA       "Intel"
  82 #else
  83 #define NATIVE_ISA      "Intel"
  84 #define OTHER_ISA       "SPARC"
  85 #endif
  86 
  87 /* Assembly language comment char */
  88 #ifdef pdp11
  89 #define ASCOMCHAR '/'
  90 #else
  91 #define ASCOMCHAR '!'
  92 #endif
  93 
  94 #pragma align   16(fbuf)
  95 static char     fbuf[FBSZ];
  96 
  97 /*
  98  * Magic file variables
  99  */
 100 static intmax_t maxmagicoffset;
 101 static intmax_t tmpmax;
 102 static char     *magicbuf;
 103 
 104 static char     *dfile;
 105 static char     *troff[] = {    /* new troff intermediate lang */
 106                 "x", "T", "res", "init", "font", "202", "V0", "p1", 0};
 107 
 108 static char     *fort[] = {                     /* FORTRAN */
 109                 "function", "subroutine", "common", "dimension", "block",
 110                 "integer", "real", "data", "double",
 111                 "FUNCTION", "SUBROUTINE", "COMMON", "DIMENSION", "BLOCK",
 112                 "INTEGER", "REAL", "DATA", "DOUBLE", 0};
 113 
 114 static char     *asc[] = {              /* Assembler Commands */
 115                 "sys", "mov", "tst", "clr", "jmp", "cmp", "set", "inc",
 116                 "dec", 0};
 117 
 118 static char     *c[] = {                        /* C Language */
 119                 "int", "char", "float", "double", "short", "long", "unsigned",
 120                 "register", "static", "struct", "extern", 0};
 121 
 122 static char     *as[] = {       /* Assembler Pseudo Ops, prepended with '.' */
 123                 "globl", "global", "ident", "file", "byte", "even",
 124                 "text", "data", "bss", "comm", 0};
 125 
 126 /*
 127  * The line and debug section names are used by the strip command.
 128  * Any changes in the strip implementation need to be reflected here.
 129  */
 130 static char     *debug_sections[] = { /* Debug sections in a ELF file */
 131                 ".debug", ".stab", ".dwarf", ".line", NULL};
 132 
 133 /* start for MB env */
 134 static wchar_t  wchar;
 135 static int      length;
 136 static int      IS_ascii;
 137 static int      Max;
 138 /* end for MB env */
 139 static int      i;      /* global index into first 'fbsz' bytes of file */
 140 static int      fbsz;
 141 static int      ifd = -1;
 142 static int      elffd = -1;
 143 static int      tret;
 144 static int      hflg;
 145 static int      dflg;
 146 static int      mflg;
 147 static int      M_flg;
 148 static int      iflg;
 149 static struct stat64    mbuf;
 150 
 151 static char     **mlist1;       /* 1st ordered list of magic files */
 152 static char     **mlist2;       /* 2nd ordered list of magic files */
 153 static size_t   mlist1_sz;      /* number of ptrs allocated for mlist1 */
 154 static size_t   mlist2_sz;      /* number of ptrs allocated for mlist2 */
 155 static char     **mlist1p;      /* next entry in mlist1 */
 156 static char     **mlist2p;      /* next entry in mlist2 */
 157 
 158 static ssize_t  mread;
 159 
 160 static void ar_coff_or_aout(int ifd);
 161 static int type(char *file);
 162 static int def_position_tests(char *file);
 163 static void def_context_tests(void);
 164 static int troffint(char *bp, int n);
 165 static int lookup(char **tab);
 166 static int ccom(void);
 167 static int ascom(void);
 168 static int sccs(void);
 169 static int english(char *bp, int n);
 170 static int shellscript(char buf[], struct stat64 *sb);
 171 static int elf_check(char *file);
 172 static int get_door_target(char *, char *, size_t);
 173 static int zipfile(char *, int);
 174 static int is_crash_dump(const char *, int);
 175 static void print_dumphdr(const int, const dumphdr_t *, uint32_t (*)(uint32_t),
 176     const char *);
 177 static uint32_t swap_uint32(uint32_t);
 178 static uint32_t return_uint32(uint32_t);
 179 static void usage(void);
 180 static void default_magic(void);
 181 static void add_to_mlist(char *, int);
 182 static void fd_cleanup(void);
 183 static int is_rtld_config(void);
 184 
 185 /* from elf_read.c */
 186 int elf_read32(int elffd, Elf_Info *EInfo);
 187 int elf_read64(int elffd, Elf_Info *EInfo);
 188 
 189 #ifdef XPG4
 190         /* SUSv3 requires a single <space> after the colon */
 191 #define prf(x)  (void) printf("%s: ", x);
 192 #else   /* !XPG4 */
 193 #define prf(x)  (void) printf("%s:%s", x, (int)strlen(x) > 6 ? "\t" : "\t\t");
 194 #endif  /* XPG4 */
 195 
 196 /*
 197  * Static program identifier - used to prevent localization of the name "file"
 198  * within individual error messages.
 199  */
 200 const char *File = "file";
 201 
 202 int
 203 main(int argc, char **argv)
 204 {
 205         char    *p;
 206         int     ch;
 207         FILE    *fl;
 208         int     cflg = 0;
 209         int     eflg = 0;
 210         int     fflg = 0;
 211         char    *ap = NULL;
 212         int     pathlen;
 213         char    **filep;
 214 
 215         (void) setlocale(LC_ALL, "");
 216 #if !defined(TEXT_DOMAIN)       /* Should be defined by cc -D */
 217 #define TEXT_DOMAIN "SYS_TEST"  /* Use this only if it weren't */
 218 #endif
 219         (void) textdomain(TEXT_DOMAIN);
 220 
 221         while ((ch = getopt(argc, argv, "M:cdf:him:")) != EOF) {
 222                 switch (ch) {
 223 
 224                 case 'M':
 225                         add_to_mlist(optarg, !dflg);
 226                         M_flg++;
 227                         break;
 228 
 229                 case 'c':
 230                         cflg++;
 231                         break;
 232 
 233                 case 'd':
 234                         if (!dflg) {
 235                                 default_magic();
 236                                 add_to_mlist(dfile, 0);
 237                                 dflg++;
 238                         }
 239                         break;
 240 
 241                 case 'f':
 242                         fflg++;
 243                         errno = 0;
 244                         if ((fl = fopen(optarg, "r")) == NULL) {
 245                                 int err = errno;
 246                                 (void) fprintf(stderr, gettext("%s: cannot "
 247                                     "open file %s: %s\n"), File, optarg,
 248                                     err ? strerror(err) : "");
 249                                 usage();
 250                         }
 251                         pathlen = pathconf("/", _PC_PATH_MAX);
 252                         if (pathlen == -1) {
 253                                 int err = errno;
 254                                 (void) fprintf(stderr, gettext("%s: cannot "
 255                                     "determine maximum path length: %s\n"),
 256                                     File, strerror(err));
 257                                 exit(1);
 258                         }
 259                         pathlen += 2; /* for null and newline in fgets */
 260                         if ((ap = malloc(pathlen * sizeof (char))) == NULL) {
 261                                 int err = errno;
 262                                 (void) fprintf(stderr, gettext("%s: malloc "
 263                                     "failed: %s\n"), File, strerror(err));
 264                                 exit(2);
 265                         }
 266                         break;
 267 
 268                 case 'h':
 269                         hflg++;
 270                         break;
 271 
 272                 case 'i':
 273                         iflg++;
 274                         break;
 275 
 276                 case 'm':
 277                         add_to_mlist(optarg, !dflg);
 278                         mflg++;
 279                         break;
 280 
 281                 case '?':
 282                         eflg++;
 283                         break;
 284                 }
 285         }
 286         if (!cflg && !fflg && (eflg || optind == argc))
 287                 usage();
 288         if (iflg && (dflg || mflg || M_flg)) {
 289                 usage();
 290         }
 291         if (iflg && cflg) {
 292                 usage();
 293         }
 294 
 295         if (!dflg && !mflg && !M_flg && !iflg) {
 296         /* no -d, -m, nor -M option; also -i option doesn't need magic  */
 297                 default_magic();
 298                 if (f_mkmtab(dfile, cflg, 0) == -1) {
 299                         exit(2);
 300                 }
 301         }
 302 
 303         else if (mflg && !M_flg && !dflg) {
 304         /* -m specified without -d nor -M */
 305 
 306 #ifdef XPG4     /* For SUSv3 only */
 307 
 308                 /*
 309                  * The default position-dependent magic file tests
 310                  * in /etc/magic will follow all the -m magic tests.
 311                  */
 312 
 313                 for (filep = mlist1; filep < mlist1p; filep++) {
 314                         if (f_mkmtab(*filep, cflg, 1) == -1) {
 315                                 exit(2);
 316                         }
 317                 }
 318                 default_magic();
 319                 if (f_mkmtab(dfile, cflg, 0) == -1) {
 320                         exit(2);
 321                 }
 322 #else   /* !XPG4 */
 323                 /*
 324                  * Retain Solaris file behavior for -m before SUSv3,
 325                  * when the new -d and -M options are not specified.
 326                  * Use the -m file specified in place of the default
 327                  * /etc/magic file.  Solaris file will
 328                  * now allow more than one magic file to be specified
 329                  * with multiple -m options, for consistency with
 330                  * other behavior.
 331                  *
 332                  * Put the magic table(s) specified by -m into
 333                  * the second magic table instead of the first
 334                  * (as indicated by the last argument to f_mkmtab()),
 335                  * since they replace the /etc/magic tests and
 336                  * must be executed alongside the default
 337                  * position-sensitive tests.
 338                  */
 339 
 340                 for (filep = mlist1; filep < mlist1p; filep++) {
 341                         if (f_mkmtab(*filep, cflg, 0) == -1) {
 342                                 exit(2);
 343                         }
 344                 }
 345 #endif /* XPG4 */
 346         } else {
 347                 /*
 348                  * For any other combination of -d, -m, and -M,
 349                  * use the magic files in command-line order.
 350                  * Store the entries from the two separate lists of magic
 351                  * files, if any, into two separate magic file tables.
 352                  * mlist1: magic tests executed before default magic tests
 353                  * mlist2: default magic tests and after
 354                  */
 355                 for (filep = mlist1; filep && (filep < mlist1p); filep++) {
 356                         if (f_mkmtab(*filep, cflg, 1) == -1) {
 357                                 exit(2);
 358                         }
 359                 }
 360                 for (filep = mlist2; filep && (filep < mlist2p); filep++) {
 361                         if (f_mkmtab(*filep, cflg, 0) == -1) {
 362                                 exit(2);
 363                         }
 364                 }
 365         }
 366 
 367         /* Initialize the magic file variables; check both magic tables */
 368         tmpmax = f_getmaxoffset(1);
 369         maxmagicoffset = f_getmaxoffset(0);
 370         if (maxmagicoffset < tmpmax) {
 371                 maxmagicoffset = tmpmax;
 372         }
 373         if (maxmagicoffset < (intmax_t)FBSZ)
 374                 maxmagicoffset = (intmax_t)FBSZ;
 375         if ((magicbuf = malloc(maxmagicoffset)) == NULL) {
 376                 int err = errno;
 377                 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
 378                     File, strerror(err));
 379                 exit(2);
 380         }
 381 
 382         if (cflg) {
 383                 f_prtmtab();
 384                 if (ferror(stdout) != 0) {
 385                         (void) fprintf(stderr, gettext("%s: error writing to "
 386                             "stdout\n"), File);
 387                         exit(1);
 388                 }
 389                 if (fclose(stdout) != 0) {
 390                         int err = errno;
 391                         (void) fprintf(stderr, gettext("%s: fclose "
 392                             "failed: %s\n"), File, strerror(err));
 393                         exit(1);
 394                 }
 395                 exit(0);
 396         }
 397 
 398         for (; fflg || optind < argc; optind += !fflg) {
 399                 register int    l;
 400 
 401                 if (fflg) {
 402                         if ((p = fgets(ap, pathlen, fl)) == NULL) {
 403                                 fflg = 0;
 404                                 optind--;
 405                                 continue;
 406                         }
 407                         l = strlen(p);
 408                         if (l > 0)
 409                                 p[l - 1] = '\0';
 410                 } else
 411                         p = argv[optind];
 412                 prf(p);                         /* print "file_name:<tab>" */
 413 
 414                 if (type(p))
 415                         tret = 1;
 416         }
 417         if (ap != NULL)
 418                 free(ap);
 419         if (tret != 0)
 420                 exit(tret);
 421 
 422         if (ferror(stdout) != 0) {
 423                 (void) fprintf(stderr, gettext("%s: error writing to "
 424                     "stdout\n"), File);
 425                 exit(1);
 426         }
 427         if (fclose(stdout) != 0) {
 428                 int err = errno;
 429                 (void) fprintf(stderr, gettext("%s: fclose failed: %s\n"),
 430                     File, strerror(err));
 431                 exit(1);
 432         }
 433         return (0);
 434 }
 435 
 436 static int
 437 type(char *file)
 438 {
 439         int     cc;
 440         char    buf[BUFSIZ];
 441         int     (*statf)() = hflg ? lstat64 : stat64;
 442 
 443         i = 0;          /* reset index to beginning of file */
 444         ifd = -1;
 445         if ((*statf)(file, &mbuf) < 0) {
 446                 if (statf == lstat64 || lstat64(file, &mbuf) < 0) {
 447                         int err = errno;
 448                         (void) printf(gettext("cannot open: %s\n"),
 449                             strerror(err));
 450                         return (0);             /* POSIX.2 */
 451                 }
 452         }
 453         switch (mbuf.st_mode & S_IFMT) {
 454         case S_IFREG:
 455                 if (iflg) {
 456                         (void) printf(gettext("regular file\n"));
 457                         return (0);
 458                 }
 459                 break;
 460         case S_IFCHR:
 461                 (void) printf(gettext("character"));
 462                 goto spcl;
 463 
 464         case S_IFDIR:
 465                 (void) printf(gettext("directory\n"));
 466                 return (0);
 467 
 468         case S_IFIFO:
 469                 (void) printf(gettext("fifo\n"));
 470                 return (0);
 471 
 472         case S_IFLNK:
 473                 if ((cc = readlink(file, buf, BUFSIZ)) < 0) {
 474                         int err = errno;
 475                         (void) printf(gettext("readlink error: %s\n"),
 476                             strerror(err));
 477                         return (1);
 478                 }
 479                 buf[cc] = '\0';
 480                 (void) printf(gettext("symbolic link to %s\n"), buf);
 481                 return (0);
 482 
 483         case S_IFBLK:
 484                 (void) printf(gettext("block"));
 485                                         /* major and minor, see sys/mkdev.h */
 486 spcl:
 487                 (void) printf(gettext(" special (%d/%d)\n"),
 488                     major(mbuf.st_rdev), minor(mbuf.st_rdev));
 489                 return (0);
 490 
 491         case S_IFSOCK:
 492                 (void) printf("socket\n");
 493                 /* FIXME, should open and try to getsockname. */
 494                 return (0);
 495 
 496         case S_IFDOOR:
 497                 if (get_door_target(file, buf, sizeof (buf)) == 0)
 498                         (void) printf(gettext("door to %s\n"), buf);
 499                 else
 500                         (void) printf(gettext("door\n"));
 501                 return (0);
 502 
 503         }
 504 
 505         if (elf_version(EV_CURRENT) == EV_NONE) {
 506                 (void) printf(gettext("libelf is out of date\n"));
 507                 return (1);
 508         }
 509 
 510         ifd = open64(file, O_RDONLY);
 511         if (ifd < 0) {
 512                 int err = errno;
 513                 (void) printf(gettext("cannot open: %s\n"), strerror(err));
 514                 return (0);                     /* POSIX.2 */
 515         }
 516 
 517         /* need another fd for elf, since we might want to read the file too */
 518         elffd = open64(file, O_RDONLY);
 519         if (elffd < 0) {
 520                 int err = errno;
 521                 (void) printf(gettext("cannot open: %s\n"), strerror(err));
 522                 (void) close(ifd);
 523                 ifd = -1;
 524                 return (0);                     /* POSIX.2 */
 525         }
 526         if ((fbsz = read(ifd, fbuf, FBSZ)) == -1) {
 527                 int err = errno;
 528                 (void) printf(gettext("cannot read: %s\n"), strerror(err));
 529                 (void) close(ifd);
 530                 ifd = -1;
 531                 return (0);                     /* POSIX.2 */
 532         }
 533         if (fbsz == 0) {
 534                 (void) printf(gettext("empty file\n"));
 535                 fd_cleanup();
 536                 return (0);
 537         }
 538 
 539         /*
 540          * First try user-specified position-dependent magic tests, if any,
 541          * which need to execute before the default tests.
 542          */
 543         if ((mread = pread(ifd, (void*)magicbuf, (size_t)maxmagicoffset,
 544             (off_t)0)) == -1) {
 545                 int err = errno;
 546                 (void) printf(gettext("cannot read: %s\n"), strerror(err));
 547                 fd_cleanup();
 548                 return (0);
 549         }
 550 
 551         /*
 552          * ChecK against Magic Table entries.
 553          * Check first magic table for magic tests to be applied
 554          * before default tests.
 555          * If no default tests are to be applied, all magic tests
 556          * should occur in this magic table.
 557          */
 558         switch (f_ckmtab(magicbuf, mread, 1)) {
 559                 case -1:        /* Error */
 560                         exit(2);
 561                         break;
 562                 case 0:         /* Not magic */
 563                         break;
 564                 default:        /* Switch is magic index */
 565                         (void) putchar('\n');
 566                         fd_cleanup();
 567                         return (0);
 568                         /* NOTREACHED */
 569                         break;
 570         }
 571 
 572         if (dflg || !M_flg) {
 573                 /*
 574                  * default position-dependent tests,
 575                  * plus non-default magic tests, if any
 576                  */
 577                 switch (def_position_tests(file)) {
 578                         case -1:        /* error */
 579                                 fd_cleanup();
 580                                 return (1);
 581                         case 1: /* matching type found */
 582                                 fd_cleanup();
 583                                 return (0);
 584                                 /* NOTREACHED */
 585                                 break;
 586                         case 0:         /* no matching type found */
 587                                 break;
 588                 }
 589                 /* default context-sensitive tests */
 590                 def_context_tests();
 591         } else {
 592                 /* no more tests to apply; no match was found */
 593                 (void) printf(gettext("data\n"));
 594         }
 595         fd_cleanup();
 596         return (0);
 597 }
 598 
 599 /*
 600  * def_position_tests() - applies default position-sensitive tests,
 601  *      looking for values in specific positions in the file.
 602  *      These are followed by default (followed by possibly some
 603  *      non-default) magic file tests.
 604  *
 605  *      All position-sensitive tests, default or otherwise, must
 606  *      be applied before context-sensitive tests, to avoid
 607  *      false context-sensitive matches.
 608  *
 609  *      Returns -1 on error which should result in error (non-zero)
 610  *      exit status for the file utility.
 611  *      Returns 0 if no matching file type found.
 612  *      Returns 1 if matching file type found.
 613  */
 614 
 615 static int
 616 def_position_tests(char *file)
 617 {
 618         if (sccs()) {   /* look for "1hddddd" where d is a digit */
 619                 (void) printf("sccs \n");
 620                 return (1);
 621         }
 622         if (fbuf[0] == '#' && fbuf[1] == '!' && shellscript(fbuf+2, &mbuf))
 623                 return (1);
 624 
 625         if (elf_check(file) == 0) {
 626                 (void) putchar('\n');
 627                 return (1);
 628         /* LINTED: pointer cast may result in improper alignment */
 629         } else if (*(int *)fbuf == CORE_MAGIC) {
 630                 /* LINTED: pointer cast may result in improper alignment */
 631                 struct core *corep = (struct core *)fbuf;
 632 
 633                 (void) printf("a.out core file");
 634 
 635                 if (*(corep->c_cmdname) != '\0')
 636                         (void) printf(" from '%s'", corep->c_cmdname);
 637                 (void) putchar('\n');
 638                 return (1);
 639         }
 640 
 641         /*
 642          * Runtime linker (ld.so.1) configuration file.
 643          */
 644         if (is_rtld_config())
 645                 return (1);
 646 
 647         /*
 648          * ZIP files, JAR files, and Java executables
 649          */
 650         if (zipfile(fbuf, ifd))
 651                 return (1);
 652 
 653         if (is_crash_dump(fbuf, ifd))
 654                 return (1);
 655 
 656         /*
 657          * ChecK against Magic Table entries.
 658          * The magic entries checked here always start with default
 659          * magic tests and may be followed by other, non-default magic
 660          * tests.  If no default tests are to be executed, all the
 661          * magic tests should have been in the first magic table.
 662          */
 663         switch (f_ckmtab(magicbuf, mread, 0)) {
 664                 case -1:        /* Error */
 665                         exit(2);
 666                         break;
 667                 case 0:         /* Not magic */
 668                         return (0);
 669                         /* NOTREACHED */
 670                         break;
 671                 default:        /* Switch is magic index */
 672 
 673                         /*
 674                          * f_ckmtab recognizes file type,
 675                          * check if it is PostScript.
 676                          * if not, check if elf or a.out
 677                          */
 678                         if (magicbuf[0] == '%' && magicbuf[1] == '!') {
 679                                 (void) putchar('\n');
 680                         } else {
 681 
 682                                 /*
 683                                  * Check that the file is executable (dynamic
 684                                  * objects must be executable to be exec'ed,
 685                                  * shared objects need not be, but by convention
 686                                  * should be executable).
 687                                  *
 688                                  * Note that we should already have processed
 689                                  * the file if it was an ELF file.
 690                                  */
 691                                 ar_coff_or_aout(elffd);
 692                                 (void) putchar('\n');
 693                         }
 694                         return (1);
 695                         /* NOTREACHED */
 696                         break;
 697         }
 698 
 699         return (0);     /* file was not identified */
 700 }
 701 
 702 /*
 703  * def_context_tests() - default context-sensitive tests.
 704  *      These are the last tests to be applied.
 705  *      If no match is found, prints out "data".
 706  */
 707 
 708 static void
 709 def_context_tests(void)
 710 {
 711         int     j;
 712         int     nl;
 713         char    ch;
 714         int     len;
 715 
 716         if (ccom() == 0)
 717                 goto notc;
 718         while (fbuf[i] == '#') {
 719                 j = i;
 720                 while (fbuf[i++] != '\n') {
 721                         if (i - j > 255) {
 722                                 (void) printf(gettext("data\n"));
 723                                 return;
 724                         }
 725                         if (i >= fbsz)
 726                                 goto notc;
 727                 }
 728                 if (ccom() == 0)
 729                         goto notc;
 730         }
 731 check:
 732         if (lookup(c) == 1) {
 733                 while ((ch = fbuf[i]) != ';' && ch != '{') {
 734                         if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0)
 735                                 len = 1;
 736                         i += len;
 737                         if (i >= fbsz)
 738                                 goto notc;
 739                 }
 740                 (void) printf(gettext("c program text"));
 741                 goto outa;
 742         }
 743         nl = 0;
 744         while (fbuf[i] != '(') {
 745                 if (fbuf[i] <= 0)
 746                         goto notas;
 747                 if (fbuf[i] == ';') {
 748                         i++;
 749                         goto check;
 750                 }
 751                 if (fbuf[i++] == '\n')
 752                         if (nl++ > 6)
 753                                 goto notc;
 754                 if (i >= fbsz)
 755                         goto notc;
 756         }
 757         while (fbuf[i] != ')') {
 758                 if (fbuf[i++] == '\n')
 759                         if (nl++ > 6)
 760                                 goto notc;
 761                 if (i >= fbsz)
 762                         goto notc;
 763         }
 764         while (fbuf[i] != '{') {
 765                 if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0)
 766                         len = 1;
 767                 if (fbuf[i] == '\n')
 768                         if (nl++ > 6)
 769                                 goto notc;
 770                 i += len;
 771                 if (i >= fbsz)
 772                         goto notc;
 773         }
 774         (void) printf(gettext("c program text"));
 775         goto outa;
 776 notc:
 777         i = 0;                  /* reset to begining of file again */
 778         while (fbuf[i] == 'c' || fbuf[i] == 'C'|| fbuf[i] == '!' ||
 779             fbuf[i] == '*' || fbuf[i] == '\n') {
 780                 while (fbuf[i++] != '\n')
 781                         if (i >= fbsz)
 782                                 goto notfort;
 783         }
 784         if (lookup(fort) == 1) {
 785                 (void) printf(gettext("fortran program text"));
 786                 goto outa;
 787         }
 788 notfort:                        /* looking for assembler program */
 789         i = 0;                  /* reset to beginning of file again */
 790         if (ccom() == 0)        /* assembler programs may contain */
 791                                 /* c-style comments */
 792                 goto notas;
 793         if (ascom() == 0)
 794                 goto notas;
 795         j = i - 1;
 796         if (fbuf[i] == '.') {
 797                 i++;
 798                 if (lookup(as) == 1) {
 799                         (void) printf(gettext("assembler program text"));
 800                         goto outa;
 801                 } else if (j != -1 && fbuf[j] == '\n' && isalpha(fbuf[j + 2])) {
 802                         (void) printf(
 803                             gettext("[nt]roff, tbl, or eqn input text"));
 804                         goto outa;
 805                 }
 806         }
 807         while (lookup(asc) == 0) {
 808                 if (ccom() == 0)
 809                         goto notas;
 810                 if (ascom() == 0)
 811                         goto notas;
 812                 while (fbuf[i] != '\n' && fbuf[i++] != ':') {
 813                         if (i >= fbsz)
 814                                 goto notas;
 815                 }
 816                 while (fbuf[i] == '\n' || fbuf[i] == ' ' || fbuf[i] == '\t')
 817                         if (i++ >= fbsz)
 818                                 goto notas;
 819                 j = i - 1;
 820                 if (fbuf[i] == '.') {
 821                         i++;
 822                         if (lookup(as) == 1) {
 823                                 (void) printf(
 824                                     gettext("assembler program text"));
 825                                 goto outa;
 826                         } else if (fbuf[j] == '\n' && isalpha(fbuf[j+2])) {
 827                                 (void) printf(
 828                                     gettext("[nt]roff, tbl, or eqn input "
 829                                     "text"));
 830                                 goto outa;
 831                         }
 832                 }
 833         }
 834         (void) printf(gettext("assembler program text"));
 835         goto outa;
 836 notas:
 837         /* start modification for multibyte env */
 838         IS_ascii = 1;
 839         if (fbsz < FBSZ)
 840                 Max = fbsz;
 841         else
 842                 Max = FBSZ - MB_LEN_MAX; /* prevent cut of wchar read */
 843         /* end modification for multibyte env */
 844 
 845         for (i = 0; i < Max; /* null */)
 846                 if (fbuf[i] & 0200) {
 847                         IS_ascii = 0;
 848                         if (fbuf[0] == '\100' && fbuf[1] == '\357') {
 849                                 (void) printf(gettext("troff output\n"));
 850                                 return;
 851                         }
 852                 /* start modification for multibyte env */
 853                         if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX))
 854                             <= 0 || !iswprint(wchar)) {
 855                                 (void) printf(gettext("data\n"));
 856                                 return;
 857                         }
 858                         i += length;
 859                 }
 860                 else
 861                         i++;
 862         i = fbsz;
 863                 /* end modification for multibyte env */
 864         if (mbuf.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH))
 865                 (void) printf(gettext("commands text"));
 866         else if (troffint(fbuf, fbsz))
 867                 (void) printf(gettext("troff intermediate output text"));
 868         else if (english(fbuf, fbsz))
 869                 (void) printf(gettext("English text"));
 870         else if (IS_ascii)
 871                 (void) printf(gettext("ascii text"));
 872         else
 873                 (void) printf(gettext("text")); /* for multibyte env */
 874 outa:
 875         /*
 876          * This code is to make sure that no MB char is cut in half
 877          * while still being used.
 878          */
 879         fbsz = (fbsz < FBSZ ? fbsz : fbsz - MB_CUR_MAX + 1);
 880         while (i < fbsz) {
 881                 if (isascii(fbuf[i])) {
 882                         i++;
 883                         continue;
 884                 } else {
 885                         if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX))
 886                             <= 0 || !iswprint(wchar)) {
 887                                 (void) printf(gettext(" with garbage\n"));
 888                                 return;
 889                         }
 890                         i = i + length;
 891                 }
 892         }
 893         (void) printf("\n");
 894 }
 895 
 896 static int
 897 troffint(char *bp, int n)
 898 {
 899         int k;
 900 
 901         i = 0;
 902         for (k = 0; k < 6; k++) {
 903                 if (lookup(troff) == 0)
 904                         return (0);
 905                 if (lookup(troff) == 0)
 906                         return (0);
 907                 while (i < n && bp[i] != '\n')
 908                         i++;
 909                 if (i++ >= n)
 910                         return (0);
 911         }
 912         return (1);
 913 }
 914 
 915 static void
 916 ar_coff_or_aout(int elffd)
 917 {
 918         Elf *elf;
 919 
 920         /*
 921          * Get the files elf descriptor and process it as an elf or
 922          * a.out (4.x) file.
 923          */
 924 
 925         elf = elf_begin(elffd, ELF_C_READ, (Elf *)0);
 926         switch (elf_kind(elf)) {
 927                 case ELF_K_AR :
 928                         (void) printf(gettext(", not a dynamic executable "
 929                             "or shared object"));
 930                         break;
 931                 case ELF_K_COFF:
 932                         (void) printf(gettext(", unsupported or unknown "
 933                             "file type"));
 934                         break;
 935                 default:
 936                         /*
 937                          * This is either an unknown file or an aout format
 938                          * At this time, we don't print dynamic/stripped
 939                          * info. on a.out or non-Elf binaries.
 940                          */
 941                         break;
 942         }
 943         (void) elf_end(elf);
 944 }
 945 
 946 
 947 static void
 948 print_elf_type(Elf_Info EI)
 949 {
 950         switch (EI.type) {
 951         case ET_NONE:
 952                 (void) printf(" %s", gettext("unknown type"));
 953                 break;
 954         case ET_REL:
 955                 (void) printf(" %s", gettext("relocatable"));
 956                 break;
 957         case ET_EXEC:
 958                 (void) printf(" %s", gettext("executable"));
 959                 break;
 960         case ET_DYN:
 961                 (void) printf(" %s", gettext("dynamic lib"));
 962                 break;
 963         default:
 964                 break;
 965         }
 966 }
 967 
 968 static void
 969 print_elf_machine(int machine)
 970 {
 971         /*
 972          * This table must be kept in sync with the EM_ constants
 973          * in /usr/include/sys/elf.h.
 974          */
 975         static const char *mach_str[EM_NUM] = {
 976                 "unknown machine",              /* 0 - EM_NONE */
 977                 "WE32100",                      /* 1 - EM_M32 */
 978                 "SPARC",                        /* 2 - EM_SPARC */
 979                 "80386",                        /* 3 - EM_386 */
 980                 "M68000",                       /* 4 - EM_68K */
 981                 "M88000",                       /* 5 - EM_88K */
 982                 "80486",                        /* 6 - EM_486 */
 983                 "i860",                         /* 7 - EM_860 */
 984                 "MIPS RS3000 Big-Endian",       /* 8 - EM_MIPS */
 985                 "S/370",                        /* 9 - EM_S370 */
 986                 "MIPS RS3000 Little-Endian",    /* 10 - EM_MIPS_RS3_LE */
 987                 "MIPS RS6000",                  /* 11 - EM_RS6000 */
 988                 NULL,                           /* 12 - EM_UNKNOWN12 */
 989                 NULL,                           /* 13 - EM_UNKNOWN13 */
 990                 NULL,                           /* 14 - EM_UNKNOWN14 */
 991                 "PA-RISC",                      /* 15 - EM_PA_RISC */
 992                 "nCUBE",                        /* 16 - EM_nCUBE */
 993                 "VPP500",                       /* 17 - EM_VPP500 */
 994                 "SPARC32PLUS",                  /* 18 - EM_SPARC32PLUS */
 995                 "i960",                         /* 19 - EM_960 */
 996                 "PowerPC",                      /* 20 - EM_PPC */
 997                 "PowerPC64",                    /* 21 - EM_PPC64 */
 998                 "S/390",                        /* 22 - EM_S390 */
 999                 NULL,                           /* 23 - EM_UNKNOWN23 */
1000                 NULL,                           /* 24 - EM_UNKNOWN24 */
1001                 NULL,                           /* 25 - EM_UNKNOWN25 */
1002                 NULL,                           /* 26 - EM_UNKNOWN26 */
1003                 NULL,                           /* 27 - EM_UNKNOWN27 */
1004                 NULL,                           /* 28 - EM_UNKNOWN28 */
1005                 NULL,                           /* 29 - EM_UNKNOWN29 */
1006                 NULL,                           /* 30 - EM_UNKNOWN30 */
1007                 NULL,                           /* 31 - EM_UNKNOWN31 */
1008                 NULL,                           /* 32 - EM_UNKNOWN32 */
1009                 NULL,                           /* 33 - EM_UNKNOWN33 */
1010                 NULL,                           /* 34 - EM_UNKNOWN34 */
1011                 NULL,                           /* 35 - EM_UNKNOWN35 */
1012                 "V800",                         /* 36 - EM_V800 */
1013                 "FR20",                         /* 37 - EM_FR20 */
1014                 "RH32",                         /* 38 - EM_RH32 */
1015                 "RCE",                          /* 39 - EM_RCE */
1016                 "ARM",                          /* 40 - EM_ARM */
1017                 "Alpha",                        /* 41 - EM_ALPHA */
1018                 "S/390",                        /* 42 - EM_SH */
1019                 "SPARCV9",                      /* 43 - EM_SPARCV9 */
1020                 "Tricore",                      /* 44 - EM_TRICORE */
1021                 "ARC",                          /* 45 - EM_ARC */
1022                 "H8/300",                       /* 46 - EM_H8_300 */
1023                 "H8/300H",                      /* 47 - EM_H8_300H */
1024                 "H8S",                          /* 48 - EM_H8S */
1025                 "H8/500",                       /* 49 - EM_H8_500 */
1026                 "IA64",                         /* 50 - EM_IA_64 */
1027                 "MIPS-X",                       /* 51 - EM_MIPS_X */
1028                 "Coldfire",                     /* 52 - EM_COLDFIRE */
1029                 "M68HC12",                      /* 53 - EM_68HC12 */
1030                 "MMA",                          /* 54 - EM_MMA */
1031                 "PCP",                          /* 55 - EM_PCP */
1032                 "nCPU",                         /* 56 - EM_NCPU */
1033                 "NDR1",                         /* 57 - EM_NDR1 */
1034                 "Starcore",                     /* 58 - EM_STARCORE */
1035                 "ME16",                         /* 59 - EM_ME16 */
1036                 "ST100",                        /* 60 - EM_ST100 */
1037                 "TINYJ",                        /* 61 - EM_TINYJ */
1038                 "AMD64",                        /* 62 - EM_AMD64 */
1039                 "PDSP",                         /* 63 - EM_PDSP */
1040                 NULL,                           /* 64 - EM_UNKNOWN64 */
1041                 NULL,                           /* 65 - EM_UNKNOWN65 */
1042                 "FX66",                         /* 66 - EM_FX66 */
1043                 "ST9 PLUS",                     /* 67 - EM_ST9PLUS */
1044                 "ST7",                          /* 68 - EM_ST7 */
1045                 "68HC16",                       /* 69 - EM_68HC16 */
1046                 "68HC11",                       /* 70 - EM_68HC11 */
1047                 "68H08",                        /* 71 - EM_68HC08 */
1048                 "68HC05",                       /* 72 - EM_68HC05 */
1049                 "SVX",                          /* 73 - EM_SVX */
1050                 "ST19",                         /* 74 - EM_ST19 */
1051                 "VAX",                          /* 75 - EM_VAX */
1052                 "CRIS",                         /* 76 - EM_CRIS */
1053                 "Javelin",                      /* 77 - EM_JAVELIN */
1054                 "Firepath",                     /* 78 - EM_FIREPATH */
1055                 "ZSP",                          /* 79 - EM_ZSP */
1056                 "MMIX",                         /* 80 - EM_MMIX */
1057                 "HUANY",                        /* 81 - EM_HUANY */
1058                 "Prism",                        /* 82 - EM_PRISM */
1059                 "AVR",                          /* 83 - EM_AVR */
1060                 "FR30",                         /* 84 - EM_FR30 */
1061                 "D10V",                         /* 85 - EM_D10V */
1062                 "D30V",                         /* 86 - EM_D30V */
1063                 "V850",                         /* 87 - EM_V850 */
1064                 "M32R",                         /* 88 - EM_M32R */
1065                 "MN10300",                      /* 89 - EM_MN10300 */
1066                 "MN10200",                      /* 90 - EM_MN10200 */
1067                 "picoJava",                     /* 91 - EM_PJ */
1068                 "OpenRISC",                     /* 92 - EM_OPENRISC */
1069                 "Tangent-A5",                   /* 93 - EM_ARC_A5 */
1070                 "Xtensa"                        /* 94 - EM_XTENSA */
1071         };
1072         /* If new machine is added, refuse to compile until we're updated */
1073 #if EM_NUM != 95
1074 #error "Number of known ELF machine constants has changed"
1075 #endif
1076 
1077         const char *str;
1078 
1079         if ((machine < EM_NONE) || (machine >= EM_NUM))
1080                 machine = EM_NONE;
1081 
1082         str = mach_str[machine];
1083         if (str)
1084                 (void) printf(" %s", str);
1085 }
1086 
1087 static void
1088 print_elf_datatype(int datatype)
1089 {
1090         switch (datatype) {
1091         case ELFDATA2LSB:
1092                 (void) printf(" LSB");
1093                 break;
1094         case ELFDATA2MSB:
1095                 (void) printf(" MSB");
1096                 break;
1097         default:
1098                 break;
1099         }
1100 }
1101 
1102 static void
1103 print_elf_class(int class)
1104 {
1105         switch (class) {
1106         case ELFCLASS32:
1107                 (void) printf(" %s", gettext("32-bit"));
1108                 break;
1109         case ELFCLASS64:
1110                 (void) printf(" %s", gettext("64-bit"));
1111                 break;
1112         default:
1113                 break;
1114         }
1115 }
1116 
1117 static void
1118 print_elf_flags(Elf_Info EI)
1119 {
1120         unsigned int flags;
1121 
1122         flags = EI.flags;
1123         switch (EI.machine) {
1124         case EM_SPARCV9:
1125                 if (flags & EF_SPARC_EXT_MASK) {
1126                         if (flags & EF_SPARC_SUN_US3) {
1127                                 (void) printf("%s", gettext(
1128                                     ", UltraSPARC3 Extensions Required"));
1129                         } else if (flags & EF_SPARC_SUN_US1) {
1130                                 (void) printf("%s", gettext(
1131                                     ", UltraSPARC1 Extensions Required"));
1132                         }
1133                         if (flags & EF_SPARC_HAL_R1)
1134                                 (void) printf("%s", gettext(
1135                                     ", HaL R1 Extensions Required"));
1136                 }
1137                 break;
1138         case EM_SPARC32PLUS:
1139                 if (flags & EF_SPARC_32PLUS)
1140                         (void) printf("%s", gettext(", V8+ Required"));
1141                 if (flags & EF_SPARC_SUN_US3) {
1142                         (void) printf("%s",
1143                             gettext(", UltraSPARC3 Extensions Required"));
1144                 } else if (flags & EF_SPARC_SUN_US1) {
1145                         (void) printf("%s",
1146                             gettext(", UltraSPARC1 Extensions Required"));
1147                 }
1148                 if (flags & EF_SPARC_HAL_R1)
1149                         (void) printf("%s",
1150                             gettext(", HaL R1 Extensions Required"));
1151                 break;
1152         default:
1153                 break;
1154         }
1155 }
1156 
1157 /*
1158  * check_ident: checks the ident field of the presumeably
1159  *              elf file. If check fails, this is not an
1160  *              elf file.
1161  */
1162 static int
1163 check_ident(unsigned char *ident, int fd)
1164 {
1165         int class;
1166         if (pread64(fd, ident, EI_NIDENT, 0) != EI_NIDENT)
1167                 return (ELF_READ_FAIL);
1168         class = ident[EI_CLASS];
1169         if (class != ELFCLASS32 && class != ELFCLASS64)
1170                 return (ELF_READ_FAIL);
1171         if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 ||
1172             ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3)
1173                 return (ELF_READ_FAIL);
1174 
1175         return (ELF_READ_OKAY);
1176 }
1177 
1178 static int
1179 elf_check(char *file)
1180 {
1181         Elf_Info EInfo;
1182         int class, version, format;
1183         unsigned char ident[EI_NIDENT];
1184 
1185         (void) memset(&EInfo, 0, sizeof (Elf_Info));
1186         EInfo.file = file;
1187 
1188         /*
1189          * Verify information in file indentifier.
1190          * Return quietly if not elf; Different type of file.
1191          */
1192         if (check_ident(ident, elffd) == ELF_READ_FAIL)
1193                 return (1);
1194 
1195         /*
1196          * Read the elf headers for processing and get the
1197          * get the needed information in Elf_Info struct.
1198          */
1199         class = ident[EI_CLASS];
1200         if (class == ELFCLASS32) {
1201                 if (elf_read32(elffd, &EInfo) == ELF_READ_FAIL) {
1202                         (void) fprintf(stderr, gettext("%s: %s: can't "
1203                             "read ELF header\n"), File, file);
1204                         return (1);
1205                 }
1206         } else if (class == ELFCLASS64) {
1207                 if (elf_read64(elffd, &EInfo) == ELF_READ_FAIL) {
1208                         (void) fprintf(stderr, gettext("%s: %s: can't "
1209                             "read ELF header\n"), File, file);
1210                         return (1);
1211                 }
1212         } else {
1213                 /* something wrong */
1214                 return (1);
1215         }
1216 
1217         /* version not in ident then 1 */
1218         version = ident[EI_VERSION] ? ident[EI_VERSION] : 1;
1219 
1220         format = ident[EI_DATA];
1221         (void) printf("%s", gettext("ELF"));
1222         print_elf_class(class);
1223         print_elf_datatype(format);
1224         print_elf_type(EInfo);
1225 
1226         if (EInfo.core_type != EC_NOTCORE) {
1227                 /* Print what kind of core is this */
1228                 if (EInfo.core_type == EC_OLDCORE)
1229                         (void) printf(" %s", gettext("pre-2.6 core file"));
1230                 else
1231                         (void) printf(" %s", gettext("core file"));
1232         }
1233 
1234         /* Print machine info */
1235         print_elf_machine(EInfo.machine);
1236 
1237         /* Print Version */
1238         if (version == 1)
1239                 (void) printf(" %s %d", gettext("Version"), version);
1240 
1241         /* Print Flags */
1242         print_elf_flags(EInfo);
1243 
1244         /* Last bit, if it is a core */
1245         if (EInfo.core_type != EC_NOTCORE) {
1246                 /* Print the program name that dumped this core */
1247                 (void) printf(gettext(", from '%s'"), EInfo.fname);
1248                 return (0);
1249         }
1250 
1251         /* Print Capabilities */
1252         if (EInfo.cap_str[0] != '\0')
1253                 (void) printf(" [%s]", EInfo.cap_str);
1254 
1255         if ((EInfo.type != ET_EXEC) && (EInfo.type != ET_DYN))
1256                 return (0);
1257 
1258         /* Print if it is dynamically linked */
1259         if (EInfo.dynamic)
1260                 (void) printf(gettext(", dynamically linked"));
1261         else
1262                 (void) printf(gettext(", statically linked"));
1263 
1264         /* Printf it it is stripped */
1265         if (EInfo.stripped & E_SYMTAB) {
1266                 (void) printf(gettext(", not stripped"));
1267                 if (!(EInfo.stripped & E_DBGINF)) {
1268                         (void) printf(gettext(
1269                             ", no debugging information available"));
1270                 }
1271         } else {
1272                 (void) printf(gettext(", stripped"));
1273         }
1274 
1275         return (0);
1276 }
1277 
1278 /*
1279  * is_rtld_config - If file is a runtime linker config file, prints
1280  * the description and returns True (1). Otherwise, silently returns
1281  * False (0).
1282  */
1283 int
1284 is_rtld_config(void)
1285 {
1286         Rtc_id *id;
1287 
1288         if ((fbsz >= sizeof (*id)) && RTC_ID_TEST(fbuf)) {
1289                 (void) printf(gettext("Runtime Linking Configuration"));
1290                 id = (Rtc_id *) fbuf;
1291                 print_elf_class(id->id_class);
1292                 print_elf_datatype(id->id_data);
1293                 print_elf_machine(id->id_machine);
1294                 (void) printf("\n");
1295                 return (1);
1296         }
1297 
1298         return (0);
1299 }
1300 
1301 /*
1302  * lookup -
1303  * Attempts to match one of the strings from a list, 'tab',
1304  * with what is in the file, starting at the current index position 'i'.
1305  * Looks past any initial whitespace and expects whitespace or other
1306  * delimiting characters to follow the matched string.
1307  * A match identifies the file as being 'assembler', 'fortran', 'c', etc.
1308  * Returns 1 for a successful match, 0 otherwise.
1309  */
1310 static int
1311 lookup(char **tab)
1312 {
1313         register char   r;
1314         register int    k, j, l;
1315 
1316         while (fbuf[i] == ' ' || fbuf[i] == '\t' || fbuf[i] == '\n')
1317                 i++;
1318         for (j = 0; tab[j] != 0; j++) {
1319                 l = 0;
1320                 for (k = i; ((r = tab[j][l++]) == fbuf[k] && r != '\0'); k++)
1321                         ;
1322                 if (r == '\0')
1323                         if (fbuf[k] == ' ' || fbuf[k] == '\n' ||
1324                             fbuf[k] == '\t' || fbuf[k] == '{' ||
1325                             fbuf[k] == '/') {
1326                                 i = k;
1327                                 return (1);
1328                         }
1329         }
1330         return (0);
1331 }
1332 
1333 /*
1334  * ccom -
1335  * Increments the current index 'i' into the file buffer 'fbuf' past any
1336  * whitespace lines and C-style comments found, starting at the current
1337  * position of 'i'.  Returns 1 as long as we don't increment i past the
1338  * size of fbuf (fbsz).  Otherwise, returns 0.
1339  */
1340 
1341 static int
1342 ccom(void)
1343 {
1344         register char   cc;
1345         int             len;
1346 
1347         while ((cc = fbuf[i]) == ' ' || cc == '\t' || cc == '\n')
1348                 if (i++ >= fbsz)
1349                         return (0);
1350         if (fbuf[i] == '/' && fbuf[i+1] == '*') {
1351                 i += 2;
1352                 while (fbuf[i] != '*' || fbuf[i+1] != '/') {
1353                         if (fbuf[i] == '\\')
1354                                 i++;
1355                         if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0)
1356                                 len = 1;
1357                         i += len;
1358                         if (i >= fbsz)
1359                                 return (0);
1360                 }
1361                 if ((i += 2) >= fbsz)
1362                         return (0);
1363         }
1364         if (fbuf[i] == '\n')
1365                 if (ccom() == 0)
1366                         return (0);
1367         return (1);
1368 }
1369 
1370 /*
1371  * ascom -
1372  * Increments the current index 'i' into the file buffer 'fbuf' past
1373  * consecutive assembler program comment lines starting with ASCOMCHAR,
1374  * starting at the current position of 'i'.
1375  * Returns 1 as long as we don't increment i past the
1376  * size of fbuf (fbsz).  Otherwise returns 0.
1377  */
1378 
1379 static int
1380 ascom(void)
1381 {
1382         while (fbuf[i] == ASCOMCHAR) {
1383                 i++;
1384                 while (fbuf[i++] != '\n')
1385                         if (i >= fbsz)
1386                                 return (0);
1387                 while (fbuf[i] == '\n')
1388                         if (i++ >= fbsz)
1389                                 return (0);
1390         }
1391         return (1);
1392 }
1393 
1394 static int
1395 sccs(void)
1396 {                               /* look for "1hddddd" where d is a digit */
1397         register int j;
1398 
1399         if (fbuf[0] == 1 && fbuf[1] == 'h') {
1400                 for (j = 2; j <= 6; j++) {
1401                         if (isdigit(fbuf[j]))
1402                                 continue;
1403                         else
1404                                 return (0);
1405                 }
1406         } else {
1407                 return (0);
1408         }
1409         return (1);
1410 }
1411 
1412 static int
1413 english(char *bp, int n)
1414 {
1415 #define NASC 128                /* number of ascii char ?? */
1416         register int    j, vow, freq, rare, len;
1417         register int    badpun = 0, punct = 0;
1418         int     ct[NASC];
1419 
1420         if (n < 50)
1421                 return (0); /* no point in statistics on squibs */
1422         for (j = 0; j < NASC; j++)
1423                 ct[j] = 0;
1424         for (j = 0; j < n; j += len) {
1425                 if ((unsigned char)bp[j] < NASC)
1426                         ct[bp[j]|040]++;
1427                 switch (bp[j]) {
1428                 case '.':
1429                 case ',':
1430                 case ')':
1431                 case '%':
1432                 case ';':
1433                 case ':':
1434                 case '?':
1435                         punct++;
1436                         if (j < n-1 && bp[j+1] != ' ' && bp[j+1] != '\n')
1437                                 badpun++;
1438                 }
1439                 if ((len = mblen(&bp[j], MB_CUR_MAX)) <= 0)
1440                         len = 1;
1441         }
1442         if (badpun*5 > punct)
1443                 return (0);
1444         vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u'];
1445         freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n'];
1446         rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z'];
1447         if (2*ct[';'] > ct['e'])
1448                 return (0);
1449         if ((ct['>'] + ct['<'] + ct['/']) > ct['e'])
1450                 return (0);     /* shell file test */
1451         return (vow * 5 >= n - ct[' '] && freq >= 10 * rare);
1452 }
1453 
1454 
1455 static int
1456 shellscript(char buf[], struct stat64 *sb)
1457 {
1458         char *tp, *cp, *xp, *up, *gp;
1459 
1460         cp = strchr(buf, '\n');
1461         if (cp == NULL || cp - fbuf > fbsz)
1462                 return (0);
1463         for (tp = buf; tp != cp && isspace((unsigned char)*tp); tp++)
1464                 if (!isascii(*tp))
1465                         return (0);
1466         for (xp = tp; tp != cp && !isspace((unsigned char)*tp); tp++)
1467                 if (!isascii(*tp))
1468                         return (0);
1469         if (tp == xp)
1470                 return (0);
1471         if (sb->st_mode & S_ISUID)
1472                 up = gettext("set-uid ");
1473         else
1474                 up = "";
1475 
1476         if (sb->st_mode & S_ISGID)
1477                 gp = gettext("set-gid ");
1478         else
1479                 gp = "";
1480 
1481         if (strncmp(xp, "/bin/sh", tp - xp) == 0)
1482                 xp = gettext("shell");
1483         else if (strncmp(xp, "/bin/csh", tp - xp) == 0)
1484                 xp = gettext("c-shell");
1485         else if (strncmp(xp, "/usr/sbin/dtrace", tp - xp) == 0)
1486                 xp = gettext("DTrace");
1487         else
1488                 *tp = '\0';
1489         /*
1490          * TRANSLATION_NOTE
1491          * This message is printed by file command for shell scripts.
1492          * The first %s is for the translation for "set-uid " (if the script
1493          *   has the set-uid bit set), or is for an empty string (if the
1494          *   script does not have the set-uid bit set).
1495          * Similarly, the second %s is for the translation for "set-gid ",
1496          *   or is for an empty string.
1497          * The third %s is for the translation for either: "shell", "c-shell",
1498          *   or "DTrace", or is for the pathname of the program the script
1499          *   executes.
1500          */
1501         (void) printf(gettext("%s%sexecutable %s script\n"), up, gp, xp);
1502         return (1);
1503 }
1504 
1505 static int
1506 get_door_target(char *file, char *buf, size_t bufsize)
1507 {
1508         int fd;
1509         door_info_t di;
1510         psinfo_t psinfo;
1511 
1512         if ((fd = open64(file, O_RDONLY)) < 0 ||
1513             door_info(fd, &di) != 0) {
1514                 if (fd >= 0)
1515                         (void) close(fd);
1516                 return (-1);
1517         }
1518         (void) close(fd);
1519 
1520         (void) sprintf(buf, "/proc/%ld/psinfo", di.di_target);
1521         if ((fd = open64(buf, O_RDONLY)) < 0 ||
1522             read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) {
1523                 if (fd >= 0)
1524                         (void) close(fd);
1525                 return (-1);
1526         }
1527         (void) close(fd);
1528 
1529         (void) snprintf(buf, bufsize, "%s[%ld]", psinfo.pr_fname, di.di_target);
1530         return (0);
1531 }
1532 
1533 /*
1534  * ZIP file header information
1535  */
1536 #define SIGSIZ          4
1537 #define LOCSIG          "PK\003\004"
1538 #define LOCHDRSIZ       30
1539 
1540 #define CH(b, n)        (((unsigned char *)(b))[n])
1541 #define SH(b, n)        (CH(b, n) | (CH(b, n+1) << 8))
1542 #define LG(b, n)        (SH(b, n) | (SH(b, n+2) << 16))
1543 
1544 #define LOCNAM(b)       (SH(b, 26))     /* filename size */
1545 #define LOCEXT(b)       (SH(b, 28))     /* extra field size */
1546 
1547 #define XFHSIZ          4               /* header id, data size */
1548 #define XFHID(b)        (SH(b, 0))      /* extract field header id */
1549 #define XFDATASIZ(b)    (SH(b, 2))      /* extract field data size */
1550 #define XFJAVASIG       0xcafe          /* java executables */
1551 
1552 static int
1553 zipfile(char *fbuf, int fd)
1554 {
1555         off_t xoff, xoff_end;
1556 
1557         if (strncmp(fbuf, LOCSIG, SIGSIZ) != 0)
1558                 return (0);
1559 
1560         xoff = LOCHDRSIZ + LOCNAM(fbuf);
1561         xoff_end = xoff + LOCEXT(fbuf);
1562 
1563         while (xoff < xoff_end) {
1564                 char xfhdr[XFHSIZ];
1565 
1566                 if (pread(fd, xfhdr, XFHSIZ, xoff) != XFHSIZ)
1567                         break;
1568 
1569                 if (XFHID(xfhdr) == XFJAVASIG) {
1570                         (void) printf("%s\n", gettext("java archive file"));
1571                         return (1);
1572                 }
1573                 xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr);
1574         }
1575 
1576         /*
1577          * We could just print "ZIP archive" here.
1578          *
1579          * However, customers may be using their own entries in
1580          * /etc/magic to distinguish one kind of ZIP file from another, so
1581          * let's defer the printing of "ZIP archive" to there.
1582          */
1583         return (0);
1584 }
1585 
1586 static int
1587 is_crash_dump(const char *buf, int fd)
1588 {
1589         /* LINTED: pointer cast may result in improper alignment */
1590         const dumphdr_t *dhp = (const dumphdr_t *)buf;
1591 
1592         /*
1593          * The current DUMP_MAGIC string covers Solaris 7 and later releases.
1594          * The utsname struct is only present in dumphdr_t's with dump_version
1595          * greater than or equal to 9.
1596          */
1597         if (dhp->dump_magic == DUMP_MAGIC) {
1598                 print_dumphdr(fd, dhp, return_uint32, NATIVE_ISA);
1599 
1600         } else if (dhp->dump_magic == swap_uint32(DUMP_MAGIC)) {
1601                 print_dumphdr(fd, dhp, swap_uint32, OTHER_ISA);
1602 
1603         } else if (dhp->dump_magic == OLD_DUMP_MAGIC ||
1604             dhp->dump_magic == swap_uint32(OLD_DUMP_MAGIC)) {
1605                 char *isa = (dhp->dump_magic == OLD_DUMP_MAGIC ?
1606                     NATIVE_ISA : OTHER_ISA);
1607                 (void) printf(gettext("SunOS 32-bit %s crash dump\n"), isa);
1608 
1609         } else {
1610                 return (0);
1611         }
1612 
1613         return (1);
1614 }
1615 
1616 static void
1617 print_dumphdr(const int fd, const dumphdr_t *dhp, uint32_t (*swap)(uint32_t),
1618     const char *isa)
1619 {
1620         dumphdr_t dh;
1621 
1622         /*
1623          * A dumphdr_t is bigger than FBSZ, so we have to manually read the
1624          * rest of it.
1625          */
1626         if (swap(dhp->dump_version) > 8 && pread(fd, &dh, sizeof (dumphdr_t),
1627             (off_t)0) == sizeof (dumphdr_t)) {
1628                 const char *c = swap(dh.dump_flags) & DF_COMPRESSED ?
1629                     "compressed " : "";
1630                 const char *l = swap(dh.dump_flags) & DF_LIVE ?
1631                     "live" : "crash";
1632 
1633                 (void) printf(gettext(
1634                     "%s %s %s %u-bit %s %s%s dump from '%s'\n"),
1635                     dh.dump_utsname.sysname, dh.dump_utsname.release,
1636                     dh.dump_utsname.version, swap(dh.dump_wordsize), isa,
1637                     c, l, dh.dump_utsname.nodename);
1638         } else {
1639                 (void) printf(gettext("SunOS %u-bit %s crash dump\n"),
1640                     swap(dhp->dump_wordsize), isa);
1641         }
1642 }
1643 
1644 static void
1645 usage(void)
1646 {
1647         (void) fprintf(stderr, gettext(
1648             "usage: file [-dh] [-M mfile] [-m mfile] [-f ffile] file ...\n"
1649             "       file [-dh] [-M mfile] [-m mfile] -f ffile\n"
1650             "       file -i [-h] [-f ffile] file ...\n"
1651             "       file -i [-h] -f ffile\n"
1652             "       file -c [-d] [-M mfile] [-m mfile]\n"));
1653         exit(2);
1654 }
1655 
1656 static uint32_t
1657 swap_uint32(uint32_t in)
1658 {
1659         uint32_t out;
1660 
1661         out = (in & 0x000000ff) << 24;
1662         out |= (in & 0x0000ff00) << 8; /* >> 8 << 16 */
1663         out |= (in & 0x00ff0000) >> 8; /* >> 16 << 8 */
1664         out |= (in & 0xff000000) >> 24;
1665 
1666         return (out);
1667 }
1668 
1669 static uint32_t
1670 return_uint32(uint32_t in)
1671 {
1672         return (in);
1673 }
1674 
1675 /*
1676  * Check if str is in the string list str_list.
1677  */
1678 int
1679 is_in_list(char *str)
1680 {
1681         int i;
1682 
1683         /*
1684          * Only need to compare the strlen(str_list[i]) bytes.
1685          * That way .stab will match on .stab* sections, and
1686          * .debug will match on .debug* sections.
1687          */
1688         for (i = 0; debug_sections[i] != NULL; i++) {
1689                 if (strncmp(debug_sections[i], str,
1690                     strlen(debug_sections[i])) == 0) {
1691                         return (1);
1692                 }
1693         }
1694         return (0);
1695 }
1696 
1697 /*
1698  * default_magic -
1699  *      allocate space for and create the default magic file
1700  *      name string.
1701  */
1702 
1703 static void
1704 default_magic(void)
1705 {
1706         const char *msg_locale = setlocale(LC_MESSAGES, NULL);
1707         struct stat     statbuf;
1708 
1709         if ((dfile = malloc(strlen(msg_locale) + 35)) == NULL) {
1710                 int err = errno;
1711                 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
1712                     File, strerror(err));
1713                 exit(2);
1714         }
1715         (void) snprintf(dfile, strlen(msg_locale) + 35,
1716             "/usr/lib/locale/%s/LC_MESSAGES/magic", msg_locale);
1717         if (stat(dfile, &statbuf) != 0) {
1718                 (void) strcpy(dfile, "/etc/magic");
1719         }
1720 }
1721 
1722 /*
1723  * add_to_mlist -
1724  *      Add the given magic_file filename string to the list of magic
1725  *      files (mlist).  This list of files will later be examined, and
1726  *      each magic file's entries will be added in order to
1727  *      the mtab table.
1728  *
1729  *      The first flag is set to 1 to add to the first list, mlist1.
1730  *      The first flag is set to 0 to add to the second list, mlist2.
1731  */
1732 
1733 static void
1734 add_to_mlist(char *magic_file, int first)
1735 {
1736         char    **mlist;        /* ordered list of magic files */
1737         size_t  mlist_sz;       /* number of pointers allocated  for mlist */
1738         char    **mlistp;       /* next entry in mlist */
1739         size_t mlistp_off;
1740 
1741         if (first) {
1742                 mlist = mlist1;
1743                 mlist_sz = mlist1_sz;
1744                 mlistp = mlist1p;
1745         } else {
1746                 mlist = mlist2;
1747                 mlist_sz = mlist2_sz;
1748                 mlistp = mlist2p;
1749         }
1750 
1751         if (mlist == NULL) {    /* initial mlist allocation */
1752                 if ((mlist = calloc(MLIST_SZ, sizeof (char *))) == NULL) {
1753                         int err = errno;
1754                         (void) fprintf(stderr, gettext("%s: malloc "
1755                             "failed: %s\n"), File, strerror(err));
1756                         exit(2);
1757                 }
1758                 mlist_sz = MLIST_SZ;
1759                 mlistp = mlist;
1760         }
1761         if ((mlistp - mlist) >= mlist_sz) {
1762                 mlistp_off = mlistp - mlist;
1763                 mlist_sz *= 2;
1764                 if ((mlist = realloc(mlist,
1765                     mlist_sz * sizeof (char *))) == NULL) {
1766                         int err = errno;
1767                         (void) fprintf(stderr, gettext("%s: malloc "
1768                             "failed: %s\n"), File, strerror(err));
1769                         exit(2);
1770                 }
1771                 mlistp = mlist + mlistp_off;
1772         }
1773         /*
1774          * now allocate memory for and copy the
1775          * magic file name string
1776          */
1777         if ((*mlistp = malloc(strlen(magic_file) + 1)) == NULL) {
1778                 int err = errno;
1779                 (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
1780                     File, strerror(err));
1781                 exit(2);
1782         }
1783         (void) strlcpy(*mlistp, magic_file, strlen(magic_file) + 1);
1784         mlistp++;
1785 
1786         if (first) {
1787                 mlist1 = mlist;
1788                 mlist1_sz = mlist_sz;
1789                 mlist1p = mlistp;
1790         } else {
1791                 mlist2 = mlist;
1792                 mlist2_sz = mlist_sz;
1793                 mlist2p = mlistp;
1794         }
1795 }
1796 
1797 static void
1798 fd_cleanup(void)
1799 {
1800         if (ifd != -1) {
1801                 (void) close(ifd);
1802                 ifd = -1;
1803         }
1804         if (elffd != -1) {
1805                 (void) close(elffd);
1806                 elffd = -1;
1807         }
1808 }