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