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.
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.
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]
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
25 /* Copyright (c) 1987, 1988 Microsoft Corporation */
26 /* All Rights Reserved */
29 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
30 * Use is subject to license terms.
33 #define _LARGEFILE64_SOURCE
35 /* Get definitions for the relocation types supported. */
36 #define ELF_TARGET_ALL
51 #include <sys/param.h>
52 #include <sys/types.h>
53 #include <sys/mkdev.h>
58 #include <sys/dumphdr.h>
59 #include <netinet/in.h>
74 * The 0x8FCA0102 magic string was used in crash dumps generated by releases
77 #define OLD_DUMP_MAGIC 0x8FCA0102
80 #define NATIVE_ISA "SPARC"
81 #define OTHER_ISA "Intel"
83 #define NATIVE_ISA "Intel"
84 #define OTHER_ISA "SPARC"
87 /* Assembly language comment char */
94 #pragma align 16(fbuf)
95 static char fbuf
[FBSZ
];
98 * Magic file variables
100 static intmax_t maxmagicoffset
;
101 static intmax_t tmpmax
;
102 static char *magicbuf
;
105 static char *troff
[] = { /* new troff intermediate lang */
106 "x", "T", "res", "init", "font", "202", "V0", "p1", 0};
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};
114 static char *asc
[] = { /* Assembler Commands */
115 "sys", "mov", "tst", "clr", "jmp", "cmp", "set", "inc",
118 static char *c
[] = { /* C Language */
119 "int", "char", "float", "double", "short", "long", "unsigned",
120 "register", "static", "struct", "extern", 0};
122 static char *as
[] = { /* Assembler Pseudo Ops, prepended with '.' */
123 "globl", "global", "ident", "file", "byte", "even",
124 "text", "data", "bss", "comm", 0};
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.
130 static char *debug_sections
[] = { /* Debug sections in a ELF file */
131 ".debug", ".stab", ".dwarf", ".line", NULL
};
133 /* start for MB env */
134 static wchar_t wchar
;
139 static int i
; /* global index into first 'fbsz' bytes of file */
142 static int elffd
= -1;
149 static struct stat64 mbuf
;
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 */
158 static ssize_t mread
;
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),
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);
185 /* from elf_read.c */
186 int elf_read32(int elffd
, Elf_Info
*EInfo
);
187 int elf_read64(int elffd
, Elf_Info
*EInfo
);
190 /* SUSv3 requires a single <space> after the colon */
191 #define prf(x) (void) printf("%s: ", x);
193 #define prf(x) (void) printf("%s:%s", x, (int)strlen(x) > 6 ? "\t" : "\t\t");
197 * Static program identifier - used to prevent localization of the name "file"
198 * within individual error messages.
200 const char *File
= "file";
203 main(int argc
, char **argv
)
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 */
220 (void) textdomain(TEXT_DOMAIN
);
222 while ((ch
= getopt(argc
, argv
, "M:bcdf:him:")) != EOF
) {
226 add_to_mlist(optarg
, !dflg
);
241 add_to_mlist(dfile
, 0);
249 if ((fl
= fopen(optarg
, "r")) == NULL
) {
251 (void) fprintf(stderr
, gettext("%s: cannot "
252 "open file %s: %s\n"), File
, optarg
,
253 err
? strerror(err
) : "");
256 pathlen
= pathconf("/", _PC_PATH_MAX
);
259 (void) fprintf(stderr
, gettext("%s: cannot "
260 "determine maximum path length: %s\n"),
261 File
, strerror(err
));
264 pathlen
+= 2; /* for null and newline in fgets */
265 if ((ap
= malloc(pathlen
* sizeof (char))) == NULL
) {
267 (void) fprintf(stderr
, gettext("%s: malloc "
268 "failed: %s\n"), File
, strerror(err
));
282 add_to_mlist(optarg
, !dflg
);
291 if (!cflg
&& !fflg
&& (eflg
|| optind
== argc
))
293 if (iflg
&& (dflg
|| mflg
|| M_flg
)) {
296 if ((iflg
&& cflg
) || (cflg
&& bflg
)) {
300 if (!dflg
&& !mflg
&& !M_flg
&& !iflg
) {
301 /* no -d, -m, nor -M option; also -i option doesn't need magic */
303 if (f_mkmtab(dfile
, cflg
, 0) == -1) {
308 else if (mflg
&& !M_flg
&& !dflg
) {
309 /* -m specified without -d nor -M */
311 #ifdef XPG4 /* For SUSv3 only */
314 * The default position-dependent magic file tests
315 * in /etc/magic will follow all the -m magic tests.
318 for (filep
= mlist1
; filep
< mlist1p
; filep
++) {
319 if (f_mkmtab(*filep
, cflg
, 1) == -1) {
324 if (f_mkmtab(dfile
, cflg
, 0) == -1) {
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
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.
345 for (filep
= mlist1
; filep
< mlist1p
; filep
++) {
346 if (f_mkmtab(*filep
, cflg
, 0) == -1) {
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
360 for (filep
= mlist1
; filep
&& (filep
< mlist1p
); filep
++) {
361 if (f_mkmtab(*filep
, cflg
, 1) == -1) {
365 for (filep
= mlist2
; filep
&& (filep
< mlist2p
); filep
++) {
366 if (f_mkmtab(*filep
, cflg
, 0) == -1) {
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
;
378 if (maxmagicoffset
< (intmax_t)FBSZ
)
379 maxmagicoffset
= (intmax_t)FBSZ
;
380 if ((magicbuf
= malloc(maxmagicoffset
)) == NULL
) {
382 (void) fprintf(stderr
, gettext("%s: malloc failed: %s\n"),
383 File
, strerror(err
));
389 if (ferror(stdout
) != 0) {
390 (void) fprintf(stderr
, gettext("%s: error writing to "
394 if (fclose(stdout
) != 0) {
396 (void) fprintf(stderr
, gettext("%s: fclose "
397 "failed: %s\n"), File
, strerror(err
));
403 for (; fflg
|| optind
< argc
; optind
+= !fflg
) {
407 if ((p
= fgets(ap
, pathlen
, fl
)) == NULL
) {
419 prf(p
); /* print "file_name:<tab>" */
429 if (ferror(stdout
) != 0) {
430 (void) fprintf(stderr
, gettext("%s: error writing to "
434 if (fclose(stdout
) != 0) {
436 (void) fprintf(stderr
, gettext("%s: fclose failed: %s\n"),
437 File
, strerror(err
));
448 int (*statf
)() = hflg
? lstat64
: stat64
;
450 i
= 0; /* reset index to beginning of file */
452 if ((*statf
)(file
, &mbuf
) < 0) {
453 if (statf
== lstat64
|| lstat64(file
, &mbuf
) < 0) {
455 (void) printf(gettext("cannot open: %s\n"),
457 return (0); /* POSIX.2 */
460 switch (mbuf
.st_mode
& S_IFMT
) {
463 (void) printf(gettext("regular file\n"));
468 (void) printf(gettext("character"));
472 (void) printf(gettext("directory\n"));
476 (void) printf(gettext("fifo\n"));
480 if ((cc
= readlink(file
, buf
, BUFSIZ
)) < 0) {
482 (void) printf(gettext("readlink error: %s\n"),
487 (void) printf(gettext("symbolic link to %s\n"), buf
);
491 (void) printf(gettext("block"));
492 /* major and minor, see sys/mkdev.h */
494 (void) printf(gettext(" special (%d/%d)\n"),
495 major(mbuf
.st_rdev
), minor(mbuf
.st_rdev
));
499 (void) printf("socket\n");
500 /* FIXME, should open and try to getsockname. */
504 if (get_door_target(file
, buf
, sizeof (buf
)) == 0)
505 (void) printf(gettext("door to %s\n"), buf
);
507 (void) printf(gettext("door\n"));
512 if (elf_version(EV_CURRENT
) == EV_NONE
) {
513 (void) printf(gettext("libelf is out of date\n"));
517 ifd
= open64(file
, O_RDONLY
);
520 (void) printf(gettext("cannot open: %s\n"), strerror(err
));
521 return (0); /* POSIX.2 */
524 /* need another fd for elf, since we might want to read the file too */
525 elffd
= open64(file
, O_RDONLY
);
528 (void) printf(gettext("cannot open: %s\n"), strerror(err
));
531 return (0); /* POSIX.2 */
533 if ((fbsz
= read(ifd
, fbuf
, FBSZ
)) == -1) {
535 (void) printf(gettext("cannot read: %s\n"), strerror(err
));
538 return (0); /* POSIX.2 */
541 (void) printf(gettext("empty file\n"));
547 * First try user-specified position-dependent magic tests, if any,
548 * which need to execute before the default tests.
550 if ((mread
= pread(ifd
, (void*)magicbuf
, (size_t)maxmagicoffset
,
553 (void) printf(gettext("cannot read: %s\n"), strerror(err
));
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.
565 switch (f_ckmtab(magicbuf
, mread
, 1)) {
569 case 0: /* Not magic */
571 default: /* Switch is magic index */
572 (void) putchar('\n');
579 if (dflg
|| !M_flg
) {
581 * default position-dependent tests,
582 * plus non-default magic tests, if any
584 switch (def_position_tests(file
)) {
588 case 1: /* matching type found */
593 case 0: /* no matching type found */
596 /* default context-sensitive tests */
599 /* no more tests to apply; no match was found */
600 (void) printf(gettext("data\n"));
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.
612 * All position-sensitive tests, default or otherwise, must
613 * be applied before context-sensitive tests, to avoid
614 * false context-sensitive matches.
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.
623 def_position_tests(char *file
)
625 if (sccs()) { /* look for "1hddddd" where d is a digit */
626 (void) printf("sccs \n");
629 if (fbuf
[0] == '#' && fbuf
[1] == '!' && shellscript(fbuf
+2, &mbuf
))
632 if (elf_check(file
) == 0) {
633 (void) putchar('\n');
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
;
640 (void) printf("a.out core file");
642 if (*(corep
->c_cmdname
) != '\0')
643 (void) printf(" from '%s'", corep
->c_cmdname
);
644 (void) putchar('\n');
649 * Runtime linker (ld.so.1) configuration file.
651 if (is_rtld_config())
655 * ZIP files, JAR files, and Java executables
657 if (zipfile(fbuf
, ifd
))
660 if (is_crash_dump(fbuf
, ifd
))
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.
670 switch (f_ckmtab(magicbuf
, mread
, 0)) {
674 case 0: /* Not magic */
678 default: /* Switch is magic index */
681 * f_ckmtab recognizes file type,
682 * check if it is PostScript.
683 * if not, check if elf or a.out
685 if (magicbuf
[0] == '%' && magicbuf
[1] == '!') {
686 (void) putchar('\n');
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).
695 * Note that we should already have processed
696 * the file if it was an ELF file.
698 ar_coff_or_aout(elffd
);
699 (void) putchar('\n');
706 return (0); /* file was not identified */
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".
716 def_context_tests(void)
725 while (fbuf
[i
] == '#') {
727 while (fbuf
[i
++] != '\n') {
729 (void) printf(gettext("data\n"));
739 if (lookup(c
) == 1) {
740 while ((ch
= fbuf
[i
]) != ';' && ch
!= '{') {
741 if ((len
= mblen(&fbuf
[i
], MB_CUR_MAX
)) <= 0)
747 (void) printf(gettext("c program text"));
751 while (fbuf
[i
] != '(') {
754 if (fbuf
[i
] == ';') {
758 if (fbuf
[i
++] == '\n')
764 while (fbuf
[i
] != ')') {
765 if (fbuf
[i
++] == '\n')
771 while (fbuf
[i
] != '{') {
772 if ((len
= mblen(&fbuf
[i
], MB_CUR_MAX
)) <= 0)
781 (void) printf(gettext("c program text"));
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')
791 if (lookup(fort
) == 1) {
792 (void) printf(gettext("fortran program text"));
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 */
803 if (fbuf
[i
] == '.') {
805 if (lookup(as
) == 1) {
806 (void) printf(gettext("assembler program text"));
808 } else if (j
!= -1 && fbuf
[j
] == '\n' && isalpha(fbuf
[j
+ 2])) {
810 gettext("[nt]roff, tbl, or eqn input text"));
814 while (lookup(asc
) == 0) {
819 while (fbuf
[i
] != '\n' && fbuf
[i
++] != ':') {
823 while (fbuf
[i
] == '\n' || fbuf
[i
] == ' ' || fbuf
[i
] == '\t')
827 if (fbuf
[i
] == '.') {
829 if (lookup(as
) == 1) {
831 gettext("assembler program text"));
833 } else if (fbuf
[j
] == '\n' && isalpha(fbuf
[j
+2])) {
835 gettext("[nt]roff, tbl, or eqn input "
841 (void) printf(gettext("assembler program text"));
844 /* start modification for multibyte env */
849 Max
= FBSZ
- MB_LEN_MAX
; /* prevent cut of wchar read */
850 /* end modification for multibyte env */
852 for (i
= 0; i
< Max
; /* null */)
853 if (fbuf
[i
] & 0200) {
855 if (fbuf
[0] == '\100' && fbuf
[1] == '\357') {
856 (void) printf(gettext("troff output\n"));
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"));
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"));
878 (void) printf(gettext("ascii text"));
880 (void) printf(gettext("text")); /* for multibyte env */
883 * This code is to make sure that no MB char is cut in half
884 * while still being used.
886 fbsz
= (fbsz
< FBSZ
? fbsz
: fbsz
- MB_CUR_MAX
+ 1);
888 if (isascii(fbuf
[i
])) {
892 if ((length
= mbtowc(&wchar
, &fbuf
[i
], MB_CUR_MAX
))
893 <= 0 || !iswprint(wchar
)) {
894 (void) printf(gettext(" with garbage\n"));
904 troffint(char *bp
, int n
)
909 for (k
= 0; k
< 6; k
++) {
910 if (lookup(troff
) == 0)
912 if (lookup(troff
) == 0)
914 while (i
< n
&& bp
[i
] != '\n')
923 ar_coff_or_aout(int elffd
)
928 * Get the files elf descriptor and process it as an elf or
932 elf
= elf_begin(elffd
, ELF_C_READ
, (Elf
*)0);
933 switch (elf_kind(elf
)) {
935 (void) printf(gettext(", not a dynamic executable "
936 "or shared object"));
939 (void) printf(gettext(", unsupported or unknown "
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.
955 print_elf_type(Elf_Info EI
)
959 (void) printf(" %s", gettext("unknown type"));
962 (void) printf(" %s", gettext("relocatable"));
965 (void) printf(" %s", gettext("executable"));
968 (void) printf(" %s", gettext("dynamic lib"));
976 print_elf_machine(int machine
)
979 * This table must be kept in sync with the EM_ constants
980 * in /usr/include/sys/elf.h.
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 */
1079 /* If new machine is added, refuse to compile until we're updated */
1081 #error "Number of known ELF machine constants has changed"
1086 if ((machine
< EM_NONE
) || (machine
>= EM_NUM
))
1089 str
= mach_str
[machine
];
1091 (void) printf(" %s", str
);
1095 print_elf_datatype(int datatype
)
1099 (void) printf(" LSB");
1102 (void) printf(" MSB");
1110 print_elf_class(int class)
1114 (void) printf(" %s", gettext("32-bit"));
1117 (void) printf(" %s", gettext("64-bit"));
1125 print_elf_flags(Elf_Info EI
)
1130 switch (EI
.machine
) {
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"));
1140 if (flags
& EF_SPARC_HAL_R1
)
1141 (void) printf("%s", gettext(
1142 ", HaL R1 Extensions Required"));
1145 case EM_SPARC32PLUS
:
1146 if (flags
& EF_SPARC_32PLUS
)
1147 (void) printf("%s", gettext(", V8+ Required"));
1148 if (flags
& EF_SPARC_SUN_US3
) {
1150 gettext(", UltraSPARC3 Extensions Required"));
1151 } else if (flags
& EF_SPARC_SUN_US1
) {
1153 gettext(", UltraSPARC1 Extensions Required"));
1155 if (flags
& EF_SPARC_HAL_R1
)
1157 gettext(", HaL R1 Extensions Required"));
1165 * check_ident: checks the ident field of the presumeably
1166 * elf file. If check fails, this is not an
1170 check_ident(unsigned char *ident
, int fd
)
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
);
1182 return (ELF_READ_OKAY
);
1186 elf_check(char *file
)
1189 int class, version
, format
;
1190 unsigned char ident
[EI_NIDENT
];
1192 (void) memset(&EInfo
, 0, sizeof (Elf_Info
));
1196 * Verify information in file indentifier.
1197 * Return quietly if not elf; Different type of file.
1199 if (check_ident(ident
, elffd
) == ELF_READ_FAIL
)
1203 * Read the elf headers for processing and get the
1204 * get the needed information in Elf_Info struct.
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
);
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
);
1220 /* something wrong */
1224 /* version not in ident then 1 */
1225 version
= ident
[EI_VERSION
] ? ident
[EI_VERSION
] : 1;
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
);
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"));
1238 (void) printf(" %s", gettext("core file"));
1241 /* Print machine info */
1242 print_elf_machine(EInfo
.machine
);
1246 (void) printf(" %s %d", gettext("Version"), version
);
1249 print_elf_flags(EInfo
);
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
);
1258 /* Print Capabilities */
1259 if (EInfo
.cap_str
[0] != '\0')
1260 (void) printf(" [%s]", EInfo
.cap_str
);
1262 if ((EInfo
.type
!= ET_EXEC
) && (EInfo
.type
!= ET_DYN
))
1265 /* Print if it is dynamically linked */
1267 (void) printf(gettext(", dynamically linked"));
1269 (void) printf(gettext(", statically linked"));
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"));
1279 (void) printf(gettext(", stripped"));
1286 * is_rtld_config - If file is a runtime linker config file, prints
1287 * the description and returns True (1). Otherwise, silently returns
1291 is_rtld_config(void)
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");
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.
1321 register int k
, j
, l
;
1323 while (fbuf
[i
] == ' ' || fbuf
[i
] == '\t' || fbuf
[i
] == '\n')
1325 for (j
= 0; tab
[j
] != 0; j
++) {
1327 for (k
= i
; ((r
= tab
[j
][l
++]) == fbuf
[k
] && r
!= '\0'); k
++)
1330 if (fbuf
[k
] == ' ' || fbuf
[k
] == '\n' ||
1331 fbuf
[k
] == '\t' || fbuf
[k
] == '{' ||
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.
1354 while ((cc
= fbuf
[i
]) == ' ' || cc
== '\t' || cc
== '\n')
1357 if (fbuf
[i
] == '/' && fbuf
[i
+1] == '*') {
1359 while (fbuf
[i
] != '*' || fbuf
[i
+1] != '/') {
1360 if (fbuf
[i
] == '\\')
1362 if ((len
= mblen(&fbuf
[i
], MB_CUR_MAX
)) <= 0)
1368 if ((i
+= 2) >= fbsz
)
1371 if (fbuf
[i
] == '\n')
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.
1389 while (fbuf
[i
] == ASCOMCHAR
) {
1391 while (fbuf
[i
++] != '\n')
1394 while (fbuf
[i
] == '\n')
1403 { /* look for "1hddddd" where d is a digit */
1406 if (fbuf
[0] == 1 && fbuf
[1] == 'h') {
1407 for (j
= 2; j
<= 6; j
++) {
1408 if (isdigit(fbuf
[j
]))
1420 english(char *bp
, int n
)
1422 #define NASC 128 /* number of ascii char ?? */
1423 register int j
, vow
, freq
, rare
, len
;
1424 register int badpun
= 0, punct
= 0;
1428 return (0); /* no point in statistics on squibs */
1429 for (j
= 0; j
< NASC
; j
++)
1431 for (j
= 0; j
< n
; j
+= len
) {
1432 if ((unsigned char)bp
[j
] < NASC
)
1443 if (j
< n
-1 && bp
[j
+1] != ' ' && bp
[j
+1] != '\n')
1446 if ((len
= mblen(&bp
[j
], MB_CUR_MAX
)) <= 0)
1449 if (badpun
*5 > punct
)
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'])
1456 if ((ct
['>'] + ct
['<'] + ct
['/']) > ct
['e'])
1457 return (0); /* shell file test */
1458 return (vow
* 5 >= n
- ct
[' '] && freq
>= 10 * rare
);
1463 shellscript(char buf
[], struct stat64
*sb
)
1465 char *tp
, *cp
, *xp
, *up
, *gp
;
1467 cp
= strchr(buf
, '\n');
1468 if (cp
== NULL
|| cp
- fbuf
> fbsz
)
1470 for (tp
= buf
; tp
!= cp
&& isspace((unsigned char)*tp
); tp
++)
1473 for (xp
= tp
; tp
!= cp
&& !isspace((unsigned char)*tp
); tp
++)
1478 if (sb
->st_mode
& S_ISUID
)
1479 up
= gettext("set-uid ");
1483 if (sb
->st_mode
& S_ISGID
)
1484 gp
= gettext("set-gid ");
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");
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
1508 (void) printf(gettext("%s%sexecutable %s script\n"), up
, gp
, xp
);
1513 get_door_target(char *file
, char *buf
, size_t bufsize
)
1519 if ((fd
= open64(file
, O_RDONLY
)) < 0 ||
1520 door_info(fd
, &di
) != 0) {
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
)) {
1536 (void) snprintf(buf
, bufsize
, "%s[%ld]", psinfo
.pr_fname
, di
.di_target
);
1541 * ZIP file header information
1544 #define LOCSIG "PK\003\004"
1545 #define LOCHDRSIZ 30
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))
1551 #define LOCNAM(b) (SH(b, 26)) /* filename size */
1552 #define LOCEXT(b) (SH(b, 28)) /* extra field size */
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 */
1560 zipfile(char *fbuf
, int fd
)
1562 off_t xoff
, xoff_end
;
1564 if (strncmp(fbuf
, LOCSIG
, SIGSIZ
) != 0)
1567 xoff
= LOCHDRSIZ
+ LOCNAM(fbuf
);
1568 xoff_end
= xoff
+ LOCEXT(fbuf
);
1570 while (xoff
< xoff_end
) {
1573 if (pread(fd
, xfhdr
, XFHSIZ
, xoff
) != XFHSIZ
)
1576 if (XFHID(xfhdr
) == XFJAVASIG
) {
1577 (void) printf("%s\n", gettext("java archive file"));
1580 xoff
+= sizeof (xfhdr
) + XFDATASIZ(xfhdr
);
1584 * We could just print "ZIP archive" here.
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.
1594 is_crash_dump(const char *buf
, int fd
)
1596 /* LINTED: pointer cast may result in improper alignment */
1597 const dumphdr_t
*dhp
= (const dumphdr_t
*)buf
;
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.
1604 if (dhp
->dump_magic
== DUMP_MAGIC
) {
1605 print_dumphdr(fd
, dhp
, return_uint32
, NATIVE_ISA
);
1607 } else if (dhp
->dump_magic
== swap_uint32(DUMP_MAGIC
)) {
1608 print_dumphdr(fd
, dhp
, swap_uint32
, OTHER_ISA
);
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
);
1624 print_dumphdr(const int fd
, const dumphdr_t
*dhp
, uint32_t (*swap
)(uint32_t),
1630 * A dumphdr_t is bigger than FBSZ, so we have to manually read the
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
?
1637 const char *l
= swap(dh
.dump_flags
) & DF_LIVE
?
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
);
1646 (void) printf(gettext("SunOS %u-bit %s crash dump\n"),
1647 swap(dhp
->dump_wordsize
), isa
);
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"));
1664 swap_uint32(uint32_t in
)
1668 out
= (in
& 0x000000ff) << 24;
1669 out
|= (in
& 0x0000ff00) << 8; /* >> 8 << 16 */
1670 out
|= (in
& 0x00ff0000) >> 8; /* >> 16 << 8 */
1671 out
|= (in
& 0xff000000) >> 24;
1677 return_uint32(uint32_t in
)
1683 * Check if str is in the string list str_list.
1686 is_in_list(char *str
)
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.
1695 for (i
= 0; debug_sections
[i
] != NULL
; i
++) {
1696 if (strncmp(debug_sections
[i
], str
,
1697 strlen(debug_sections
[i
])) == 0) {
1706 * allocate space for and create the default magic file
1713 const char *msg_locale
= setlocale(LC_MESSAGES
, NULL
);
1714 struct stat statbuf
;
1716 if ((dfile
= malloc(strlen(msg_locale
) + 35)) == NULL
) {
1718 (void) fprintf(stderr
, gettext("%s: malloc failed: %s\n"),
1719 File
, strerror(err
));
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");
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
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.
1741 add_to_mlist(char *magic_file
, int first
)
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 */
1750 mlist_sz
= mlist1_sz
;
1754 mlist_sz
= mlist2_sz
;
1758 if (mlist
== NULL
) { /* initial mlist allocation */
1759 if ((mlist
= calloc(MLIST_SZ
, sizeof (char *))) == NULL
) {
1761 (void) fprintf(stderr
, gettext("%s: malloc "
1762 "failed: %s\n"), File
, strerror(err
));
1765 mlist_sz
= MLIST_SZ
;
1768 if ((mlistp
- mlist
) >= mlist_sz
) {
1769 mlistp_off
= mlistp
- mlist
;
1771 if ((mlist
= realloc(mlist
,
1772 mlist_sz
* sizeof (char *))) == NULL
) {
1774 (void) fprintf(stderr
, gettext("%s: malloc "
1775 "failed: %s\n"), File
, strerror(err
));
1778 mlistp
= mlist
+ mlistp_off
;
1781 * now allocate memory for and copy the
1782 * magic file name string
1784 if ((*mlistp
= malloc(strlen(magic_file
) + 1)) == NULL
) {
1786 (void) fprintf(stderr
, gettext("%s: malloc failed: %s\n"),
1787 File
, strerror(err
));
1790 (void) strlcpy(*mlistp
, magic_file
, strlen(magic_file
) + 1);
1795 mlist1_sz
= mlist_sz
;
1799 mlist2_sz
= mlist_sz
;
1812 (void) close(elffd
);