blob: 64379f391923b99765228e1ea5cab98be52ec9c4 [file] [log] [blame]
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1987, 1988 Microsoft Corporation */
/* All Rights Reserved */
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2018, Joyent, Inc.
*/
#define _LARGEFILE64_SOURCE
/* Get definitions for the relocation types supported. */
#define ELF_TARGET_ALL
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <libelf.h>
#include <stdlib.h>
#include <limits.h>
#include <locale.h>
#include <wctype.h>
#include <string.h>
#include <errno.h>
#include <door.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/mkdev.h>
#include <sys/stat.h>
#include <sys/elf.h>
#include <procfs.h>
#include <sys/core.h>
#include <sys/dumphdr.h>
#include <netinet/in.h>
#include <gelf.h>
#include <elfcap.h>
#include <sgsrtcid.h>
#include "file.h"
#include "elf_read.h"
/*
* Misc
*/
#define FBSZ 512
#define MLIST_SZ 12
/*
* The 0x8FCA0102 magic string was used in crash dumps generated by releases
* prior to Solaris 7.
*/
#define OLD_DUMP_MAGIC 0x8FCA0102
#if defined(__sparc)
#define NATIVE_ISA "SPARC"
#define OTHER_ISA "Intel"
#else
#define NATIVE_ISA "Intel"
#define OTHER_ISA "SPARC"
#endif
/* Assembly language comment char */
#ifdef pdp11
#define ASCOMCHAR '/'
#else
#define ASCOMCHAR '!'
#endif
#pragma align 16(fbuf)
static char fbuf[FBSZ];
/*
* Magic file variables
*/
static intmax_t maxmagicoffset;
static intmax_t tmpmax;
static char *magicbuf;
static char *dfile;
static char *troff[] = { /* new troff intermediate lang */
"x", "T", "res", "init", "font", "202", "V0", "p1", 0};
static char *fort[] = { /* FORTRAN */
"function", "subroutine", "common", "dimension", "block",
"integer", "real", "data", "double",
"FUNCTION", "SUBROUTINE", "COMMON", "DIMENSION", "BLOCK",
"INTEGER", "REAL", "DATA", "DOUBLE", 0};
static char *asc[] = { /* Assembler Commands */
"sys", "mov", "tst", "clr", "jmp", "cmp", "set", "inc",
"dec", 0};
static char *c[] = { /* C Language */
"int", "char", "float", "double", "short", "long", "unsigned",
"register", "static", "struct", "extern", 0};
static char *as[] = { /* Assembler Pseudo Ops, prepended with '.' */
"globl", "global", "ident", "file", "byte", "even",
"text", "data", "bss", "comm", 0};
/*
* The line and debug section names are used by the strip command.
* Any changes in the strip implementation need to be reflected here.
*/
static char *debug_sections[] = { /* Debug sections in a ELF file */
".debug", ".stab", ".dwarf", ".line", NULL};
/* start for MB env */
static wchar_t wchar;
static int length;
static int IS_ascii;
static int Max;
/* end for MB env */
static int i; /* global index into first 'fbsz' bytes of file */
static int fbsz;
static int ifd = -1;
static int elffd = -1;
static int tret;
static int hflg;
static int dflg;
static int mflg;
static int M_flg;
static int iflg;
static struct stat64 mbuf;
static char **mlist1; /* 1st ordered list of magic files */
static char **mlist2; /* 2nd ordered list of magic files */
static size_t mlist1_sz; /* number of ptrs allocated for mlist1 */
static size_t mlist2_sz; /* number of ptrs allocated for mlist2 */
static char **mlist1p; /* next entry in mlist1 */
static char **mlist2p; /* next entry in mlist2 */
static ssize_t mread;
static void ar_coff_or_aout(int ifd);
static int type(char *file);
static int def_position_tests(char *file);
static void def_context_tests(void);
static int troffint(char *bp, int n);
static int lookup(char **tab);
static int ccom(void);
static int ascom(void);
static int sccs(void);
static int english(char *bp, int n);
static int shellscript(char buf[], struct stat64 *sb);
static int elf_check(char *file);
static int get_door_target(char *, char *, size_t);
static int zipfile(char *, int);
static int is_crash_dump(const char *, int);
static void print_dumphdr(const int, const dumphdr_t *, uint32_t (*)(uint32_t),
const char *);
static uint32_t swap_uint32(uint32_t);
static uint32_t return_uint32(uint32_t);
static void usage(void);
static void default_magic(void);
static void add_to_mlist(char *, int);
static void fd_cleanup(void);
static int is_rtld_config(void);
/* from elf_read.c */
int elf_read32(int elffd, Elf_Info *EInfo);
int elf_read64(int elffd, Elf_Info *EInfo);
#ifdef XPG4
/* SUSv3 requires a single <space> after the colon */
#define prf(x) (void) printf("%s: ", x);
#else /* !XPG4 */
#define prf(x) (void) printf("%s:%s", x, (int)strlen(x) > 6 ? "\t" : "\t\t");
#endif /* XPG4 */
/*
* Static program identifier - used to prevent localization of the name "file"
* within individual error messages.
*/
const char *File = "file";
int
main(int argc, char **argv)
{
char *p;
int ch;
FILE *fl;
int bflg = 0;
int cflg = 0;
int eflg = 0;
int fflg = 0;
char *ap = NULL;
int pathlen;
char **filep;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
#endif
(void) textdomain(TEXT_DOMAIN);
while ((ch = getopt(argc, argv, "M:bcdf:him:")) != EOF) {
switch (ch) {
case 'M':
add_to_mlist(optarg, !dflg);
M_flg++;
break;
case 'b':
bflg++;
break;
case 'c':
cflg++;
break;
case 'd':
if (!dflg) {
default_magic();
add_to_mlist(dfile, 0);
dflg++;
}
break;
case 'f':
fflg++;
errno = 0;
if ((fl = fopen(optarg, "r")) == NULL) {
int err = errno;
(void) fprintf(stderr, gettext("%s: cannot "
"open file %s: %s\n"), File, optarg,
err ? strerror(err) : "");
usage();
}
pathlen = pathconf("/", _PC_PATH_MAX);
if (pathlen == -1) {
int err = errno;
(void) fprintf(stderr, gettext("%s: cannot "
"determine maximum path length: %s\n"),
File, strerror(err));
exit(1);
}
pathlen += 2; /* for null and newline in fgets */
if ((ap = malloc(pathlen * sizeof (char))) == NULL) {
int err = errno;
(void) fprintf(stderr, gettext("%s: malloc "
"failed: %s\n"), File, strerror(err));
exit(2);
}
break;
case 'h':
hflg++;
break;
case 'i':
iflg++;
break;
case 'm':
add_to_mlist(optarg, !dflg);
mflg++;
break;
case '?':
eflg++;
break;
}
}
if (!cflg && !fflg && (eflg || optind == argc))
usage();
if (iflg && (dflg || mflg || M_flg)) {
usage();
}
if ((iflg && cflg) || (cflg && bflg)) {
usage();
}
if (!dflg && !mflg && !M_flg && !iflg) {
/* no -d, -m, nor -M option; also -i option doesn't need magic */
default_magic();
if (f_mkmtab(dfile, cflg, 0) == -1) {
exit(2);
}
}
else if (mflg && !M_flg && !dflg) {
/* -m specified without -d nor -M */
#ifdef XPG4 /* For SUSv3 only */
/*
* The default position-dependent magic file tests
* in /etc/magic will follow all the -m magic tests.
*/
for (filep = mlist1; filep < mlist1p; filep++) {
if (f_mkmtab(*filep, cflg, 1) == -1) {
exit(2);
}
}
default_magic();
if (f_mkmtab(dfile, cflg, 0) == -1) {
exit(2);
}
#else /* !XPG4 */
/*
* Retain Solaris file behavior for -m before SUSv3,
* when the new -d and -M options are not specified.
* Use the -m file specified in place of the default
* /etc/magic file. Solaris file will
* now allow more than one magic file to be specified
* with multiple -m options, for consistency with
* other behavior.
*
* Put the magic table(s) specified by -m into
* the second magic table instead of the first
* (as indicated by the last argument to f_mkmtab()),
* since they replace the /etc/magic tests and
* must be executed alongside the default
* position-sensitive tests.
*/
for (filep = mlist1; filep < mlist1p; filep++) {
if (f_mkmtab(*filep, cflg, 0) == -1) {
exit(2);
}
}
#endif /* XPG4 */
} else {
/*
* For any other combination of -d, -m, and -M,
* use the magic files in command-line order.
* Store the entries from the two separate lists of magic
* files, if any, into two separate magic file tables.
* mlist1: magic tests executed before default magic tests
* mlist2: default magic tests and after
*/
for (filep = mlist1; filep && (filep < mlist1p); filep++) {
if (f_mkmtab(*filep, cflg, 1) == -1) {
exit(2);
}
}
for (filep = mlist2; filep && (filep < mlist2p); filep++) {
if (f_mkmtab(*filep, cflg, 0) == -1) {
exit(2);
}
}
}
/* Initialize the magic file variables; check both magic tables */
tmpmax = f_getmaxoffset(1);
maxmagicoffset = f_getmaxoffset(0);
if (maxmagicoffset < tmpmax) {
maxmagicoffset = tmpmax;
}
if (maxmagicoffset < (intmax_t)FBSZ)
maxmagicoffset = (intmax_t)FBSZ;
if ((magicbuf = malloc(maxmagicoffset)) == NULL) {
int err = errno;
(void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
File, strerror(err));
exit(2);
}
if (cflg) {
f_prtmtab();
if (ferror(stdout) != 0) {
(void) fprintf(stderr, gettext("%s: error writing to "
"stdout\n"), File);
exit(1);
}
if (fclose(stdout) != 0) {
int err = errno;
(void) fprintf(stderr, gettext("%s: fclose "
"failed: %s\n"), File, strerror(err));
exit(1);
}
exit(0);
}
for (; fflg || optind < argc; optind += !fflg) {
register int l;
if (fflg) {
if ((p = fgets(ap, pathlen, fl)) == NULL) {
fflg = 0;
optind--;
continue;
}
l = strlen(p);
if (l > 0)
p[l - 1] = '\0';
} else
p = argv[optind];
if (!bflg)
prf(p); /* print "file_name:<tab>" */
if (type(p))
tret = 1;
}
if (ap != NULL)
free(ap);
if (tret != 0)
exit(tret);
if (ferror(stdout) != 0) {
(void) fprintf(stderr, gettext("%s: error writing to "
"stdout\n"), File);
exit(1);
}
if (fclose(stdout) != 0) {
int err = errno;
(void) fprintf(stderr, gettext("%s: fclose failed: %s\n"),
File, strerror(err));
exit(1);
}
return (0);
}
static int
type(char *file)
{
int cc;
char buf[BUFSIZ];
int (*statf)() = hflg ? lstat64 : stat64;
i = 0; /* reset index to beginning of file */
ifd = -1;
if ((*statf)(file, &mbuf) < 0) {
if (statf == lstat64 || lstat64(file, &mbuf) < 0) {
int err = errno;
(void) printf(gettext("cannot open: %s\n"),
strerror(err));
return (0); /* POSIX.2 */
}
}
switch (mbuf.st_mode & S_IFMT) {
case S_IFREG:
if (iflg) {
(void) printf(gettext("regular file\n"));
return (0);
}
break;
case S_IFCHR:
(void) printf(gettext("character"));
goto spcl;
case S_IFDIR:
(void) printf(gettext("directory\n"));
return (0);
case S_IFIFO:
(void) printf(gettext("fifo\n"));
return (0);
case S_IFLNK:
if ((cc = readlink(file, buf, BUFSIZ)) < 0) {
int err = errno;
(void) printf(gettext("readlink error: %s\n"),
strerror(err));
return (1);
}
buf[cc] = '\0';
(void) printf(gettext("symbolic link to %s\n"), buf);
return (0);
case S_IFBLK:
(void) printf(gettext("block"));
/* major and minor, see sys/mkdev.h */
spcl:
(void) printf(gettext(" special (%d/%d)\n"),
major(mbuf.st_rdev), minor(mbuf.st_rdev));
return (0);
case S_IFSOCK:
(void) printf("socket\n");
/* FIXME, should open and try to getsockname. */
return (0);
case S_IFDOOR:
if (get_door_target(file, buf, sizeof (buf)) == 0)
(void) printf(gettext("door to %s\n"), buf);
else
(void) printf(gettext("door\n"));
return (0);
}
if (elf_version(EV_CURRENT) == EV_NONE) {
(void) printf(gettext("libelf is out of date\n"));
return (1);
}
ifd = open64(file, O_RDONLY);
if (ifd < 0) {
int err = errno;
(void) printf(gettext("cannot open: %s\n"), strerror(err));
return (0); /* POSIX.2 */
}
/* need another fd for elf, since we might want to read the file too */
elffd = open64(file, O_RDONLY);
if (elffd < 0) {
int err = errno;
(void) printf(gettext("cannot open: %s\n"), strerror(err));
(void) close(ifd);
ifd = -1;
return (0); /* POSIX.2 */
}
if ((fbsz = read(ifd, fbuf, FBSZ)) == -1) {
int err = errno;
(void) printf(gettext("cannot read: %s\n"), strerror(err));
(void) close(ifd);
ifd = -1;
return (0); /* POSIX.2 */
}
if (fbsz == 0) {
(void) printf(gettext("empty file\n"));
fd_cleanup();
return (0);
}
/*
* First try user-specified position-dependent magic tests, if any,
* which need to execute before the default tests.
*/
if ((mread = pread(ifd, (void*)magicbuf, (size_t)maxmagicoffset,
(off_t)0)) == -1) {
int err = errno;
(void) printf(gettext("cannot read: %s\n"), strerror(err));
fd_cleanup();
return (0);
}
/*
* ChecK against Magic Table entries.
* Check first magic table for magic tests to be applied
* before default tests.
* If no default tests are to be applied, all magic tests
* should occur in this magic table.
*/
switch (f_ckmtab(magicbuf, mread, 1)) {
case -1: /* Error */
exit(2);
break;
case 0: /* Not magic */
break;
default: /* Switch is magic index */
(void) putchar('\n');
fd_cleanup();
return (0);
/* NOTREACHED */
break;
}
if (dflg || !M_flg) {
/*
* default position-dependent tests,
* plus non-default magic tests, if any
*/
switch (def_position_tests(file)) {
case -1: /* error */
fd_cleanup();
return (1);
case 1: /* matching type found */
fd_cleanup();
return (0);
/* NOTREACHED */
break;
case 0: /* no matching type found */
break;
}
/* default context-sensitive tests */
def_context_tests();
} else {
/* no more tests to apply; no match was found */
(void) printf(gettext("data\n"));
}
fd_cleanup();
return (0);
}
/*
* def_position_tests() - applies default position-sensitive tests,
* looking for values in specific positions in the file.
* These are followed by default (followed by possibly some
* non-default) magic file tests.
*
* All position-sensitive tests, default or otherwise, must
* be applied before context-sensitive tests, to avoid
* false context-sensitive matches.
*
* Returns -1 on error which should result in error (non-zero)
* exit status for the file utility.
* Returns 0 if no matching file type found.
* Returns 1 if matching file type found.
*/
static int
def_position_tests(char *file)
{
if (sccs()) { /* look for "1hddddd" where d is a digit */
(void) printf("sccs \n");
return (1);
}
if (fbuf[0] == '#' && fbuf[1] == '!' && shellscript(fbuf+2, &mbuf))
return (1);
if (elf_check(file) == 0) {
(void) putchar('\n');
return (1);
/* LINTED: pointer cast may result in improper alignment */
} else if (*(int *)fbuf == CORE_MAGIC) {
/* LINTED: pointer cast may result in improper alignment */
struct core *corep = (struct core *)fbuf;
(void) printf("a.out core file");
if (*(corep->c_cmdname) != '\0')
(void) printf(" from '%s'", corep->c_cmdname);
(void) putchar('\n');
return (1);
}
/*
* Runtime linker (ld.so.1) configuration file.
*/
if (is_rtld_config())
return (1);
/*
* ZIP files, JAR files, and Java executables
*/
if (zipfile(fbuf, ifd))
return (1);
if (is_crash_dump(fbuf, ifd))
return (1);
/*
* ChecK against Magic Table entries.
* The magic entries checked here always start with default
* magic tests and may be followed by other, non-default magic
* tests. If no default tests are to be executed, all the
* magic tests should have been in the first magic table.
*/
switch (f_ckmtab(magicbuf, mread, 0)) {
case -1: /* Error */
exit(2);
break;
case 0: /* Not magic */
return (0);
/* NOTREACHED */
break;
default: /* Switch is magic index */
/*
* f_ckmtab recognizes file type,
* check if it is PostScript.
* if not, check if elf or a.out
*/
if (magicbuf[0] == '%' && magicbuf[1] == '!') {
(void) putchar('\n');
} else {
/*
* Check that the file is executable (dynamic
* objects must be executable to be exec'ed,
* shared objects need not be, but by convention
* should be executable).
*
* Note that we should already have processed
* the file if it was an ELF file.
*/
ar_coff_or_aout(elffd);
(void) putchar('\n');
}
return (1);
/* NOTREACHED */
break;
}
return (0); /* file was not identified */
}
/*
* def_context_tests() - default context-sensitive tests.
* These are the last tests to be applied.
* If no match is found, prints out "data".
*/
static void
def_context_tests(void)
{
int j;
int nl;
char ch;
int len;
if (ccom() == 0)
goto notc;
while (fbuf[i] == '#') {
j = i;
while (fbuf[i++] != '\n') {
if (i - j > 255) {
(void) printf(gettext("data\n"));
return;
}
if (i >= fbsz)
goto notc;
}
if (ccom() == 0)
goto notc;
}
check:
if (lookup(c) == 1) {
while ((ch = fbuf[i]) != ';' && ch != '{') {
if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0)
len = 1;
i += len;
if (i >= fbsz)
goto notc;
}
(void) printf(gettext("c program text"));
goto outa;
}
nl = 0;
while (fbuf[i] != '(') {
if (fbuf[i] <= 0)
goto notas;
if (fbuf[i] == ';') {
i++;
goto check;
}
if (fbuf[i++] == '\n')
if (nl++ > 6)
goto notc;
if (i >= fbsz)
goto notc;
}
while (fbuf[i] != ')') {
if (fbuf[i++] == '\n')
if (nl++ > 6)
goto notc;
if (i >= fbsz)
goto notc;
}
while (fbuf[i] != '{') {
if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0)
len = 1;
if (fbuf[i] == '\n')
if (nl++ > 6)
goto notc;
i += len;
if (i >= fbsz)
goto notc;
}
(void) printf(gettext("c program text"));
goto outa;
notc:
i = 0; /* reset to begining of file again */
while (fbuf[i] == 'c' || fbuf[i] == 'C'|| fbuf[i] == '!' ||
fbuf[i] == '*' || fbuf[i] == '\n') {
while (fbuf[i++] != '\n')
if (i >= fbsz)
goto notfort;
}
if (lookup(fort) == 1) {
(void) printf(gettext("fortran program text"));
goto outa;
}
notfort: /* looking for assembler program */
i = 0; /* reset to beginning of file again */
if (ccom() == 0) /* assembler programs may contain */
/* c-style comments */
goto notas;
if (ascom() == 0)
goto notas;
j = i - 1;
if (fbuf[i] == '.') {
i++;
if (lookup(as) == 1) {
(void) printf(gettext("assembler program text"));
goto outa;
} else if (j != -1 && fbuf[j] == '\n' && isalpha(fbuf[j + 2])) {
(void) printf(
gettext("[nt]roff, tbl, or eqn input text"));
goto outa;
}
}
while (lookup(asc) == 0) {
if (ccom() == 0)
goto notas;
if (ascom() == 0)
goto notas;
while (fbuf[i] != '\n' && fbuf[i++] != ':') {
if (i >= fbsz)
goto notas;
}
while (fbuf[i] == '\n' || fbuf[i] == ' ' || fbuf[i] == '\t')
if (i++ >= fbsz)
goto notas;
j = i - 1;
if (fbuf[i] == '.') {
i++;
if (lookup(as) == 1) {
(void) printf(
gettext("assembler program text"));
goto outa;
} else if (fbuf[j] == '\n' && isalpha(fbuf[j+2])) {
(void) printf(
gettext("[nt]roff, tbl, or eqn input "
"text"));
goto outa;
}
}
}
(void) printf(gettext("assembler program text"));
goto outa;
notas:
/* start modification for multibyte env */
IS_ascii = 1;
if (fbsz < FBSZ)
Max = fbsz;
else
Max = FBSZ - MB_LEN_MAX; /* prevent cut of wchar read */
/* end modification for multibyte env */
for (i = 0; i < Max; /* null */)
if (fbuf[i] & 0200) {
IS_ascii = 0;
if (fbuf[0] == '\100' && fbuf[1] == '\357') {
(void) printf(gettext("troff output\n"));
return;
}
/* start modification for multibyte env */
if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX))
<= 0 || !iswprint(wchar)) {
(void) printf(gettext("data\n"));
return;
}
i += length;
}
else
i++;
i = fbsz;
/* end modification for multibyte env */
if (mbuf.st_mode&(S_IXUSR|S_IXGRP|S_IXOTH))
(void) printf(gettext("commands text"));
else if (troffint(fbuf, fbsz))
(void) printf(gettext("troff intermediate output text"));
else if (english(fbuf, fbsz))
(void) printf(gettext("English text"));
else if (IS_ascii)
(void) printf(gettext("ascii text"));
else
(void) printf(gettext("text")); /* for multibyte env */
outa:
/*
* This code is to make sure that no MB char is cut in half
* while still being used.
*/
fbsz = (fbsz < FBSZ ? fbsz : fbsz - MB_CUR_MAX + 1);
while (i < fbsz) {
if (isascii(fbuf[i])) {
i++;
continue;
} else {
if ((length = mbtowc(&wchar, &fbuf[i], MB_CUR_MAX))
<= 0 || !iswprint(wchar)) {
(void) printf(gettext(" with garbage\n"));
return;
}
i = i + length;
}
}
(void) printf("\n");
}
static int
troffint(char *bp, int n)
{
int k;
i = 0;
for (k = 0; k < 6; k++) {
if (lookup(troff) == 0)
return (0);
if (lookup(troff) == 0)
return (0);
while (i < n && bp[i] != '\n')
i++;
if (i++ >= n)
return (0);
}
return (1);
}
static void
ar_coff_or_aout(int elffd)
{
Elf *elf;
/*
* Get the files elf descriptor and process it as an elf or
* a.out (4.x) file.
*/
elf = elf_begin(elffd, ELF_C_READ, (Elf *)0);
switch (elf_kind(elf)) {
case ELF_K_AR :
(void) printf(gettext(", not a dynamic executable "
"or shared object"));
break;
case ELF_K_COFF:
(void) printf(gettext(", unsupported or unknown "
"file type"));
break;
default:
/*
* This is either an unknown file or an aout format
* At this time, we don't print dynamic/stripped
* info. on a.out or non-Elf binaries.
*/
break;
}
(void) elf_end(elf);
}
static void
print_elf_type(Elf_Info EI)
{
switch (EI.type) {
case ET_NONE:
(void) printf(" %s", gettext("unknown type"));
break;
case ET_REL:
(void) printf(" %s", gettext("relocatable"));
break;
case ET_EXEC:
(void) printf(" %s", gettext("executable"));
break;
case ET_DYN:
(void) printf(" %s", gettext("dynamic lib"));
break;
default:
break;
}
}
static void
print_elf_machine(int machine)
{
/*
* This table must be kept in sync with the EM_ constants
* in /usr/include/sys/elf.h.
*/
static const char *mach_str[EM_NUM] = {
[EM_NONE] = "unknown machine",
[EM_M32] = "WE32100",
[EM_SPARC] = "SPARC",
[EM_386] = "80386",
[EM_68K] = "M68000",
[EM_88K] = "M88000",
[EM_486] = "80486",
[EM_860] = "i860",
[EM_MIPS] = "MIPS RS3000 Big-Endian",
[EM_S370] = "S/370",
[EM_MIPS_RS3_LE] = "MIPS RS3000 Little-Endian",
[EM_RS6000] = "MIPS RS6000",
[EM_PA_RISC] = "PA-RISC",
[EM_nCUBE] = "nCUBE",
[EM_VPP500] = "VPP500",
[EM_SPARC32PLUS] = "SPARC32PLUS",
[EM_960] = "i960",
[EM_PPC] = "PowerPC",
[EM_PPC64] = "PowerPC64",
[EM_S390] = "S/390",
[EM_V800] = "V800",
[EM_FR20] = "FR20",
[EM_RH32] = "RH32",
[EM_RCE] = "RCE",
[EM_ARM] = "ARM",
[EM_ALPHA] = "Alpha",
[EM_SH] = "S/390",
[EM_SPARCV9] = "SPARCV9",
[EM_TRICORE] = "Tricore",
[EM_ARC] = "ARC",
[EM_H8_300] = "H8/300",
[EM_H8_300H] = "H8/300H",
[EM_H8S] = "H8S",
[EM_H8_500] = "H8/500",
[EM_IA_64] = "IA64",
[EM_MIPS_X] = "MIPS-X",
[EM_COLDFIRE] = "Coldfire",
[EM_68HC12] = "M68HC12",
[EM_MMA] = "MMA",
[EM_PCP] = "PCP",
[EM_NCPU] = "nCPU",
[EM_NDR1] = "NDR1",
[EM_STARCORE] = "Starcore",
[EM_ME16] = "ME16",
[EM_ST100] = "ST100",
[EM_TINYJ] = "TINYJ",
[EM_AMD64] = "AMD64",
[EM_PDSP] = "PDSP",
[EM_FX66] = "FX66",
[EM_ST9PLUS] = "ST9 PLUS",
[EM_ST7] = "ST7",
[EM_68HC16] = "68HC16",
[EM_68HC11] = "68HC11",
[EM_68HC08] = "68H08",
[EM_68HC05] = "68HC05",
[EM_SVX] = "SVX",
[EM_ST19] = "ST19",
[EM_VAX] = "VAX",
[EM_CRIS] = "CRIS",
[EM_JAVELIN] = "Javelin",
[EM_FIREPATH] = "Firepath",
[EM_ZSP] = "ZSP",
[EM_MMIX] = "MMIX",
[EM_HUANY] = "HUANY",
[EM_PRISM] = "Prism",
[EM_AVR] = "AVR",
[EM_FR30] = "FR30",
[EM_D10V] = "D10V",
[EM_D30V] = "D30V",
[EM_V850] = "V850",
[EM_M32R] = "M32R",
[EM_MN10300] = "MN10300",
[EM_MN10200] = "MN10200",
[EM_PJ] = "picoJava",
[EM_OPENRISC] = "OpenRISC",
[EM_ARC_A5] = "Tangent-A5",
[EM_XTENSA] = "Xtensa",
[EM_VIDEOCORE] = "Videocore",
[EM_TMM_GPP] = "TMM_GPP",
[EM_NS32K] = "NS32K",
[EM_TPC] = "TPC",
[EM_SNP1K] = "SNP1K",
[EM_ST200] = "ST200",
[EM_IP2K] = "IP2K",
[EM_MAX] = "MAX",
[EM_CR] = "CompactRISC",
[EM_F2MC16] = "F2MC16",
[EM_MSP430] = "MSP430",
[EM_BLACKFIN] = "Blackfin",
[EM_SE_C33] = "S1C33",
[EM_SEP] = "SEP",
[EM_ARCA] = "Arca",
[EM_UNICORE] = "Unicore",
[EM_EXCESS] = "eXcess",
[EM_DXP] = "DXP",
[EM_ALTERA_NIOS2] = "Nios 2",
[EM_CRX] = "CompactRISC CRX",
[EM_XGATE] = "XGATE",
[EM_C166] = "C16x/XC16x",
[EM_M16C] = "M16C",
[EM_DSPIC30F] = "dsPIC30F",
[EM_CE] = "CE RISC",
[EM_M32C] = "M32C",
[EM_TSK3000] = "TSK3000",
[EM_RS08] = "RS08",
[EM_SHARC] = "SHARC",
[EM_ECOG2] = "eCOG2",
[EM_SCORE7] = "SCORE7",
[EM_DSP24] = "DSP24",
[EM_VIDEOCORE3] = "Videocore III",
[EM_LATTICEMICO32] = "LATTICEMICO32",
[EM_SE_C17] = "SE_C17",
[EM_TI_C6000] = "TMS320C6000",
[EM_TI_C2000] = "TMS320C2000",
[EM_TI_C5500] = "TMS320C55x",
[EM_TI_ARP32] = "ASRP32",
[EM_TI_PRU] = "TI_PRU",
[EM_MMDSP_PLUS] = "MMDSP_PLUS",
[EM_CYPRESS_M8C] = "M8C",
[EM_R32C] = "R32C",
[EM_TRIMEDIA] = "TriMedia",
[EM_QDSP6] = "QDSP6",
[EM_8051] = "8051",
[EM_STXP7X] = "STxP7x",
[EM_NDS32] = "NDS32",
[EM_ECOG1] = "eCOG1X",
[EM_MAXQ30] = "MAXQ30",
[EM_XIMO16] = "XIMO16",
[EM_MANIK] = "M2000",
[EM_CRAYNV2] = "CRAYNV2",
[EM_RX] = "RX",
[EM_METAG] = "METAG",
[EM_MCST_ELBRUS] = "Elbrus",
[EM_ECOG16] = "eCOG16",
[EM_CR16] = "CR16",
[EM_ETPU] = "ETPU",
[EM_SLE9X] = "SLE9X",
[EM_L10M] = "L10M",
[EM_K10M] = "K10M",
[EM_AARCH64] = "aarch64",
[EM_AVR32] = "AVR32",
[EM_STM8] = "STM8",
[EM_TILE64] = "TILE64",
[EM_TILEPRO] = "TILEPRO",
[EM_MICROBLAZE] = "MicroBlaze",
[EM_CUDA] = "CUDA",
[EM_TILEGX] = "TILE-Gx",
[EM_CLOUDSHIELD] = "CloudShield",
[EM_COREA_1ST] = "CORE-A 1st",
[EM_COREA_2ND] = "CORE-A 2nd",
[EM_ARC_COMPACT2] = "ARCompact V2",
[EM_OPEN8] = "Open8",
[EM_RL78] = "RL78",
[EM_VIDEOCORE5] = "VideoCore V",
[EM_78KOR] = "78KOR",
[EM_56800EX] = "56800EX",
[EM_BA1] = "BA1",
[EM_BA2] = "BA2",
[EM_XCORE] = "xCORE",
[EM_MCHP_PIC] = "MCHP_PIC",
[EM_KM32] = "KM32",
[EM_KMX32] = "KMX32",
[EM_KMX16] = "KMX16",
[EM_KMX8] = "KMX8",
[EM_KVARC] = "KVARC",
[EM_CDP] = "CDP",
[EM_COGE] = "COGE",
[EM_COOL] = "CoolEngine",
[EM_NORC] = "NORC",
[EM_CSR_KALIMBA] = "Kalimba",
[EM_Z80] = "Zilog Z80",
[EM_VISIUM] = "VISIUMcore",
[EM_FT32] = "FT32",
[EM_MOXIE] = "Moxie",
[EM_AMDGPU] = "AMD GPU",
[EM_RISCV] = "RISC-V"
};
/* If new machine is added, refuse to compile until we're updated */
#if EM_NUM != 244
#error "Number of known ELF machine constants has changed"
#endif
const char *str;
if ((machine < EM_NONE) || (machine >= EM_NUM))
machine = EM_NONE;
str = mach_str[machine];
if (str)
(void) printf(" %s", str);
}
static void
print_elf_datatype(int datatype)
{
switch (datatype) {
case ELFDATA2LSB:
(void) printf(" LSB");
break;
case ELFDATA2MSB:
(void) printf(" MSB");
break;
default:
break;
}
}
static void
print_elf_class(int class)
{
switch (class) {
case ELFCLASS32:
(void) printf(" %s", gettext("32-bit"));
break;
case ELFCLASS64:
(void) printf(" %s", gettext("64-bit"));
break;
default:
break;
}
}
static void
print_elf_flags(Elf_Info EI)
{
unsigned int flags;
flags = EI.flags;
switch (EI.machine) {
case EM_SPARCV9:
if (flags & EF_SPARC_EXT_MASK) {
if (flags & EF_SPARC_SUN_US3) {
(void) printf("%s", gettext(
", UltraSPARC3 Extensions Required"));
} else if (flags & EF_SPARC_SUN_US1) {
(void) printf("%s", gettext(
", UltraSPARC1 Extensions Required"));
}
if (flags & EF_SPARC_HAL_R1)
(void) printf("%s", gettext(
", HaL R1 Extensions Required"));
}
break;
case EM_SPARC32PLUS:
if (flags & EF_SPARC_32PLUS)
(void) printf("%s", gettext(", V8+ Required"));
if (flags & EF_SPARC_SUN_US3) {
(void) printf("%s",
gettext(", UltraSPARC3 Extensions Required"));
} else if (flags & EF_SPARC_SUN_US1) {
(void) printf("%s",
gettext(", UltraSPARC1 Extensions Required"));
}
if (flags & EF_SPARC_HAL_R1)
(void) printf("%s",
gettext(", HaL R1 Extensions Required"));
break;
default:
break;
}
}
/*
* check_ident: checks the ident field of the presumeably
* elf file. If check fails, this is not an
* elf file.
*/
static int
check_ident(unsigned char *ident, int fd)
{
int class;
if (pread64(fd, ident, EI_NIDENT, 0) != EI_NIDENT)
return (ELF_READ_FAIL);
class = ident[EI_CLASS];
if (class != ELFCLASS32 && class != ELFCLASS64)
return (ELF_READ_FAIL);
if (ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 ||
ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3)
return (ELF_READ_FAIL);
return (ELF_READ_OKAY);
}
static int
elf_check(char *file)
{
Elf_Info EInfo;
int class, version, format;
unsigned char ident[EI_NIDENT];
(void) memset(&EInfo, 0, sizeof (Elf_Info));
EInfo.file = file;
/*
* Verify information in file indentifier.
* Return quietly if not elf; Different type of file.
*/
if (check_ident(ident, elffd) == ELF_READ_FAIL)
return (1);
/*
* Read the elf headers for processing and get the
* get the needed information in Elf_Info struct.
*/
class = ident[EI_CLASS];
if (class == ELFCLASS32) {
if (elf_read32(elffd, &EInfo) == ELF_READ_FAIL) {
(void) fprintf(stderr, gettext("%s: %s: can't "
"read ELF header\n"), File, file);
return (1);
}
} else if (class == ELFCLASS64) {
if (elf_read64(elffd, &EInfo) == ELF_READ_FAIL) {
(void) fprintf(stderr, gettext("%s: %s: can't "
"read ELF header\n"), File, file);
return (1);
}
} else {
/* something wrong */
return (1);
}
/* version not in ident then 1 */
version = ident[EI_VERSION] ? ident[EI_VERSION] : 1;
format = ident[EI_DATA];
(void) printf("%s", gettext("ELF"));
print_elf_class(class);
print_elf_datatype(format);
print_elf_type(EInfo);
if (EInfo.core_type != EC_NOTCORE) {
/* Print what kind of core is this */
if (EInfo.core_type == EC_OLDCORE)
(void) printf(" %s", gettext("pre-2.6 core file"));
else
(void) printf(" %s", gettext("core file"));
}
/* Print machine info */
print_elf_machine(EInfo.machine);
/* Print Version */
if (version == 1)
(void) printf(" %s %d", gettext("Version"), version);
/* Print Flags */
print_elf_flags(EInfo);
/* Last bit, if it is a core */
if (EInfo.core_type != EC_NOTCORE) {
/* Print the program name that dumped this core */
(void) printf(gettext(", from '%s'"), EInfo.fname);
return (0);
}
/* Print Capabilities */
if (EInfo.cap_str[0] != '\0')
(void) printf(" [%s]", EInfo.cap_str);
if ((EInfo.type != ET_EXEC) && (EInfo.type != ET_DYN))
return (0);
/* Print if it is dynamically linked */
if (EInfo.dynamic)
(void) printf(gettext(", dynamically linked"));
else
(void) printf(gettext(", statically linked"));
/* Printf it it is stripped */
if (EInfo.stripped & E_SYMTAB) {
(void) printf(gettext(", not stripped"));
if (!(EInfo.stripped & E_DBGINF)) {
(void) printf(gettext(
", no debugging information available"));
}
} else {
(void) printf(gettext(", stripped"));
}
return (0);
}
/*
* is_rtld_config - If file is a runtime linker config file, prints
* the description and returns True (1). Otherwise, silently returns
* False (0).
*/
int
is_rtld_config(void)
{
Rtc_id *id;
if ((fbsz >= sizeof (*id)) && RTC_ID_TEST(fbuf)) {
(void) printf(gettext("Runtime Linking Configuration"));
id = (Rtc_id *) fbuf;
print_elf_class(id->id_class);
print_elf_datatype(id->id_data);
print_elf_machine(id->id_machine);
(void) printf("\n");
return (1);
}
return (0);
}
/*
* lookup -
* Attempts to match one of the strings from a list, 'tab',
* with what is in the file, starting at the current index position 'i'.
* Looks past any initial whitespace and expects whitespace or other
* delimiting characters to follow the matched string.
* A match identifies the file as being 'assembler', 'fortran', 'c', etc.
* Returns 1 for a successful match, 0 otherwise.
*/
static int
lookup(char **tab)
{
register char r;
register int k, j, l;
while (fbuf[i] == ' ' || fbuf[i] == '\t' || fbuf[i] == '\n')
i++;
for (j = 0; tab[j] != 0; j++) {
l = 0;
for (k = i; ((r = tab[j][l++]) == fbuf[k] && r != '\0'); k++)
;
if (r == '\0')
if (fbuf[k] == ' ' || fbuf[k] == '\n' ||
fbuf[k] == '\t' || fbuf[k] == '{' ||
fbuf[k] == '/') {
i = k;
return (1);
}
}
return (0);
}
/*
* ccom -
* Increments the current index 'i' into the file buffer 'fbuf' past any
* whitespace lines and C-style comments found, starting at the current
* position of 'i'. Returns 1 as long as we don't increment i past the
* size of fbuf (fbsz). Otherwise, returns 0.
*/
static int
ccom(void)
{
register char cc;
int len;
while ((cc = fbuf[i]) == ' ' || cc == '\t' || cc == '\n')
if (i++ >= fbsz)
return (0);
if (fbuf[i] == '/' && fbuf[i+1] == '*') {
i += 2;
while (fbuf[i] != '*' || fbuf[i+1] != '/') {
if (fbuf[i] == '\\')
i++;
if ((len = mblen(&fbuf[i], MB_CUR_MAX)) <= 0)
len = 1;
i += len;
if (i >= fbsz)
return (0);
}
if ((i += 2) >= fbsz)
return (0);
}
if (fbuf[i] == '\n')
if (ccom() == 0)
return (0);
return (1);
}
/*
* ascom -
* Increments the current index 'i' into the file buffer 'fbuf' past
* consecutive assembler program comment lines starting with ASCOMCHAR,
* starting at the current position of 'i'.
* Returns 1 as long as we don't increment i past the
* size of fbuf (fbsz). Otherwise returns 0.
*/
static int
ascom(void)
{
while (fbuf[i] == ASCOMCHAR) {
i++;
while (fbuf[i++] != '\n')
if (i >= fbsz)
return (0);
while (fbuf[i] == '\n')
if (i++ >= fbsz)
return (0);
}
return (1);
}
static int
sccs(void)
{ /* look for "1hddddd" where d is a digit */
register int j;
if (fbuf[0] == 1 && fbuf[1] == 'h') {
for (j = 2; j <= 6; j++) {
if (isdigit(fbuf[j]))
continue;
else
return (0);
}
} else {
return (0);
}
return (1);
}
static int
english(char *bp, int n)
{
#define NASC 128 /* number of ascii char ?? */
register int j, vow, freq, rare, len;
register int badpun = 0, punct = 0;
int ct[NASC];
if (n < 50)
return (0); /* no point in statistics on squibs */
for (j = 0; j < NASC; j++)
ct[j] = 0;
for (j = 0; j < n; j += len) {
if ((unsigned char)bp[j] < NASC)
ct[bp[j]|040]++;
switch (bp[j]) {
case '.':
case ',':
case ')':
case '%':
case ';':
case ':':
case '?':
punct++;
if (j < n-1 && bp[j+1] != ' ' && bp[j+1] != '\n')
badpun++;
}
if ((len = mblen(&bp[j], MB_CUR_MAX)) <= 0)
len = 1;
}
if (badpun*5 > punct)
return (0);
vow = ct['a'] + ct['e'] + ct['i'] + ct['o'] + ct['u'];
freq = ct['e'] + ct['t'] + ct['a'] + ct['i'] + ct['o'] + ct['n'];
rare = ct['v'] + ct['j'] + ct['k'] + ct['q'] + ct['x'] + ct['z'];
if (2*ct[';'] > ct['e'])
return (0);
if ((ct['>'] + ct['<'] + ct['/']) > ct['e'])
return (0); /* shell file test */
return (vow * 5 >= n - ct[' '] && freq >= 10 * rare);
}
static int
shellscript(char buf[], struct stat64 *sb)
{
char *tp, *cp, *xp, *up, *gp;
cp = strchr(buf, '\n');
if (cp == NULL || cp - fbuf > fbsz)
return (0);
for (tp = buf; tp != cp && isspace((unsigned char)*tp); tp++)
if (!isascii(*tp))
return (0);
for (xp = tp; tp != cp && !isspace((unsigned char)*tp); tp++)
if (!isascii(*tp))
return (0);
if (tp == xp)
return (0);
if (sb->st_mode & S_ISUID)
up = gettext("set-uid ");
else
up = "";
if (sb->st_mode & S_ISGID)
gp = gettext("set-gid ");
else
gp = "";
if (strncmp(xp, "/bin/sh", tp - xp) == 0)
xp = gettext("shell");
else if (strncmp(xp, "/bin/csh", tp - xp) == 0)
xp = gettext("c-shell");
else if (strncmp(xp, "/usr/sbin/dtrace", tp - xp) == 0)
xp = gettext("DTrace");
else
*tp = '\0';
/*
* TRANSLATION_NOTE
* This message is printed by file command for shell scripts.
* The first %s is for the translation for "set-uid " (if the script
* has the set-uid bit set), or is for an empty string (if the
* script does not have the set-uid bit set).
* Similarly, the second %s is for the translation for "set-gid ",
* or is for an empty string.
* The third %s is for the translation for either: "shell", "c-shell",
* or "DTrace", or is for the pathname of the program the script
* executes.
*/
(void) printf(gettext("%s%sexecutable %s script\n"), up, gp, xp);
return (1);
}
static int
get_door_target(char *file, char *buf, size_t bufsize)
{
int fd;
door_info_t di;
psinfo_t psinfo;
if ((fd = open64(file, O_RDONLY)) < 0 ||
door_info(fd, &di) != 0) {
if (fd >= 0)
(void) close(fd);
return (-1);
}
(void) close(fd);
(void) sprintf(buf, "/proc/%ld/psinfo", di.di_target);
if ((fd = open64(buf, O_RDONLY)) < 0 ||
read(fd, &psinfo, sizeof (psinfo)) != sizeof (psinfo)) {
if (fd >= 0)
(void) close(fd);
return (-1);
}
(void) close(fd);
(void) snprintf(buf, bufsize, "%s[%ld]", psinfo.pr_fname, di.di_target);
return (0);
}
/*
* ZIP file header information
*/
#define SIGSIZ 4
#define LOCSIG "PK\003\004"
#define LOCHDRSIZ 30
#define CH(b, n) (((unsigned char *)(b))[n])
#define SH(b, n) (CH(b, n) | (CH(b, n+1) << 8))
#define LG(b, n) (SH(b, n) | (SH(b, n+2) << 16))
#define LOCNAM(b) (SH(b, 26)) /* filename size */
#define LOCEXT(b) (SH(b, 28)) /* extra field size */
#define XFHSIZ 4 /* header id, data size */
#define XFHID(b) (SH(b, 0)) /* extract field header id */
#define XFDATASIZ(b) (SH(b, 2)) /* extract field data size */
#define XFJAVASIG 0xcafe /* java executables */
static int
zipfile(char *fbuf, int fd)
{
off_t xoff, xoff_end;
if (strncmp(fbuf, LOCSIG, SIGSIZ) != 0)
return (0);
xoff = LOCHDRSIZ + LOCNAM(fbuf);
xoff_end = xoff + LOCEXT(fbuf);
while (xoff < xoff_end) {
char xfhdr[XFHSIZ];
if (pread(fd, xfhdr, XFHSIZ, xoff) != XFHSIZ)
break;
if (XFHID(xfhdr) == XFJAVASIG) {
(void) printf("%s\n", gettext("java archive file"));
return (1);
}
xoff += sizeof (xfhdr) + XFDATASIZ(xfhdr);
}
/*
* We could just print "ZIP archive" here.
*
* However, customers may be using their own entries in
* /etc/magic to distinguish one kind of ZIP file from another, so
* let's defer the printing of "ZIP archive" to there.
*/
return (0);
}
static int
is_crash_dump(const char *buf, int fd)
{
/* LINTED: pointer cast may result in improper alignment */
const dumphdr_t *dhp = (const dumphdr_t *)buf;
/*
* The current DUMP_MAGIC string covers Solaris 7 and later releases.
* The utsname struct is only present in dumphdr_t's with dump_version
* greater than or equal to 9.
*/
if (dhp->dump_magic == DUMP_MAGIC) {
print_dumphdr(fd, dhp, return_uint32, NATIVE_ISA);
} else if (dhp->dump_magic == swap_uint32(DUMP_MAGIC)) {
print_dumphdr(fd, dhp, swap_uint32, OTHER_ISA);
} else if (dhp->dump_magic == OLD_DUMP_MAGIC ||
dhp->dump_magic == swap_uint32(OLD_DUMP_MAGIC)) {
char *isa = (dhp->dump_magic == OLD_DUMP_MAGIC ?
NATIVE_ISA : OTHER_ISA);
(void) printf(gettext("SunOS 32-bit %s crash dump\n"), isa);
} else {
return (0);
}
return (1);
}
static void
print_dumphdr(const int fd, const dumphdr_t *dhp, uint32_t (*swap)(uint32_t),
const char *isa)
{
dumphdr_t dh;
/*
* A dumphdr_t is bigger than FBSZ, so we have to manually read the
* rest of it.
*/
if (swap(dhp->dump_version) > 8 && pread(fd, &dh, sizeof (dumphdr_t),
(off_t)0) == sizeof (dumphdr_t)) {
const char *c = swap(dh.dump_flags) & DF_COMPRESSED ?
"compressed " : "";
const char *l = swap(dh.dump_flags) & DF_LIVE ?
"live" : "crash";
(void) printf(gettext(
"%s %s %s %u-bit %s %s%s dump from '%s'\n"),
dh.dump_utsname.sysname, dh.dump_utsname.release,
dh.dump_utsname.version, swap(dh.dump_wordsize), isa,
c, l, dh.dump_utsname.nodename);
} else {
(void) printf(gettext("SunOS %u-bit %s crash dump\n"),
swap(dhp->dump_wordsize), isa);
}
}
static void
usage(void)
{
(void) fprintf(stderr, gettext(
"usage: file [-bdh] [-M mfile] [-m mfile] [-f ffile] file ...\n"
" file [-bdh] [-M mfile] [-m mfile] -f ffile\n"
" file -i [-bh] [-f ffile] file ...\n"
" file -i [-bh] -f ffile\n"
" file -c [-d] [-M mfile] [-m mfile]\n"));
exit(2);
}
static uint32_t
swap_uint32(uint32_t in)
{
uint32_t out;
out = (in & 0x000000ff) << 24;
out |= (in & 0x0000ff00) << 8; /* >> 8 << 16 */
out |= (in & 0x00ff0000) >> 8; /* >> 16 << 8 */
out |= (in & 0xff000000) >> 24;
return (out);
}
static uint32_t
return_uint32(uint32_t in)
{
return (in);
}
/*
* Check if str is in the string list str_list.
*/
int
is_in_list(char *str)
{
int i;
/*
* Only need to compare the strlen(str_list[i]) bytes.
* That way .stab will match on .stab* sections, and
* .debug will match on .debug* sections.
*/
for (i = 0; debug_sections[i] != NULL; i++) {
if (strncmp(debug_sections[i], str,
strlen(debug_sections[i])) == 0) {
return (1);
}
}
return (0);
}
/*
* default_magic -
* allocate space for and create the default magic file
* name string.
*/
static void
default_magic(void)
{
const char *msg_locale = setlocale(LC_MESSAGES, NULL);
struct stat statbuf;
if ((dfile = malloc(strlen(msg_locale) + 35)) == NULL) {
int err = errno;
(void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
File, strerror(err));
exit(2);
}
(void) snprintf(dfile, strlen(msg_locale) + 35,
"/usr/lib/locale/%s/LC_MESSAGES/magic", msg_locale);
if (stat(dfile, &statbuf) != 0) {
(void) strcpy(dfile, "/etc/magic");
}
}
/*
* add_to_mlist -
* Add the given magic_file filename string to the list of magic
* files (mlist). This list of files will later be examined, and
* each magic file's entries will be added in order to
* the mtab table.
*
* The first flag is set to 1 to add to the first list, mlist1.
* The first flag is set to 0 to add to the second list, mlist2.
*/
static void
add_to_mlist(char *magic_file, int first)
{
char **mlist; /* ordered list of magic files */
size_t mlist_sz; /* number of pointers allocated for mlist */
char **mlistp; /* next entry in mlist */
size_t mlistp_off;
if (first) {
mlist = mlist1;
mlist_sz = mlist1_sz;
mlistp = mlist1p;
} else {
mlist = mlist2;
mlist_sz = mlist2_sz;
mlistp = mlist2p;
}
if (mlist == NULL) { /* initial mlist allocation */
if ((mlist = calloc(MLIST_SZ, sizeof (char *))) == NULL) {
int err = errno;
(void) fprintf(stderr, gettext("%s: malloc "
"failed: %s\n"), File, strerror(err));
exit(2);
}
mlist_sz = MLIST_SZ;
mlistp = mlist;
}
if ((mlistp - mlist) >= mlist_sz) {
mlistp_off = mlistp - mlist;
mlist_sz *= 2;
if ((mlist = realloc(mlist,
mlist_sz * sizeof (char *))) == NULL) {
int err = errno;
(void) fprintf(stderr, gettext("%s: malloc "
"failed: %s\n"), File, strerror(err));
exit(2);
}
mlistp = mlist + mlistp_off;
}
/*
* now allocate memory for and copy the
* magic file name string
*/
if ((*mlistp = malloc(strlen(magic_file) + 1)) == NULL) {
int err = errno;
(void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
File, strerror(err));
exit(2);
}
(void) strlcpy(*mlistp, magic_file, strlen(magic_file) + 1);
mlistp++;
if (first) {
mlist1 = mlist;
mlist1_sz = mlist_sz;
mlist1p = mlistp;
} else {
mlist2 = mlist;
mlist2_sz = mlist_sz;
mlist2p = mlistp;
}
}
static void
fd_cleanup(void)
{
if (ifd != -1) {
(void) close(ifd);
ifd = -1;
}
if (elffd != -1) {
(void) close(elffd);
elffd = -1;
}
}