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