# # 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 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG= file XPG4PROG= file MAGIC= magic ELFCAP= $(SRC)/common/elfcap SGSRTCID= $(SRC)/common/sgsrtcid LOBJS= file.o elf_read32.o elf_read64.o magicutils.o OBJS= $(LOBJS) elfcap.o XPG4OBJS= $(OBJS:%.o=xpg4_%.o) SRCS= file.c elf_read.c magicutils.c $(ELFCAP)/elfcap.c include ../Makefile.cmd CSTD= $(CSTD_GNU99) CERRWARN += $(CNOWARN_UNINIT) CERRWARN += -Wno-type-limits POFILE= file_all.po POFILES= $(SRCS:%.c=%.po) LDLIBS += -lelf CPPFLAGS += -I$(ELFCAP) -I$(SGSRTCID) $(XPG4) : CFLAGS += -DXPG4 ROOTETCMAGIC= $(MAGIC:%=$(ROOTETC)/%) $(ROOTETCMAGIC) : FILEMODE = $(LIBFILEMODE) .PARALLEL: $(OBJS) $(XPG4OBJS) $(POFILES) .KEEP_STATE: all: $(PROG) $(XPG4) $(MAGIC) $(PROG) : $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) $(XPG4) : $(XPG4OBJS) $(LINK.c) $(XPG4OBJS) -o $@ $(LDLIBS) $(POST_PROCESS) %.o: %.c $(COMPILE.c) -o $@ $< %32.o: %.c $(COMPILE.c) -o $@ $< %64.o: %.c $(COMPILE.c) -D_ELF64 -o $@ $< xpg4_%.o: %.c $(COMPILE.c) -o $@ $< xpg4_%32.o: %.c $(COMPILE.c) -o $@ $< xpg4_%64.o: %.c $(COMPILE.c) -D_ELF64 -o $@ $< elfcap.o: $(ELFCAP)/elfcap.c $(COMPILE.c) -o $@ $(ELFCAP)/elfcap.c xpg4_elfcap.o: $(ELFCAP)/elfcap.c $(COMPILE.c) -o $@ $(ELFCAP)/elfcap.c $(POFILE): $(POFILES) $(RM) $@ cat $(POFILES) > $@ # Hammerhead: ROOTHASBIN = ROOTBIN (flattened), install binary directly. # Removed ../has/bin symlink (broken on 64-bit only system). install: all $(ROOTHASBINPROG) $(ROOTXPG4PROG) $(ROOTETCMAGIC) clean: $(RM) $(OBJS) $(XPG4OBJS) include ../Makefile.targ /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * ELF files can exceed 2GB in size. A standard 32-bit program * like 'file' cannot read past 2GB, and will be unable to see * the ELF section headers that typically are at the end of the * object. The simplest solution to this problem would be to make * the 'file' command a 64-bit application. However, as a matter of * policy, we do not want to require this. A simple command like * 'file' should not carry such a requirement, especially as we * support 32-bit only hardware. * * An alternative solution is to build this code as 32-bit * large file aware. The usual way to do this is to define a pair * of preprocessor definitions: * * _LARGEFILE64_SOURCE * Map standard I/O routines to their largefile aware versions. * * _FILE_OFFSET_BITS=64 * Map off_t to off64_t * * The problem with this solution is that libelf is not large file capable, * and the libelf header file will prevent compilation if * _FILE_OFFSET_BITS is set to 64. * * So, the solution used in this code is to define _LARGEFILE64_SOURCE * to get access to the 64-bit APIs, not to define _FILE_OFFSET_BITS, and to * use our own types in place of off_t, and size_t. We read all the file * data directly using pread64(), and avoid the use of libelf for anything * other than the xlate functionality. */ #define _LARGEFILE64_SOURCE #define FILE_ELF_OFF_T off64_t #define FILE_ELF_SIZE_T uint64_t #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "file.h" #include "elf_read.h" extern const char *File; static int get_class(void); static int get_version(void); static int get_format(void); static int process_shdr(Elf_Info *); static int process_phdr(Elf_Info *); static int file_xlatetom(Elf_Type, char *); static int xlatetom_nhdr(Elf_Nhdr *); static int get_phdr(Elf_Info *, int); static int get_shdr(Elf_Info *, int); static Elf_Ehdr EI_Ehdr; /* Elf_Ehdr to be stored */ static Elf_Word EI_Ehdr_shnum; /* # section headers */ static Elf_Word EI_Ehdr_phnum; /* # program headers */ static Elf_Word EI_Ehdr_shstrndx; /* Index of section hdr string table */ static Elf_Shdr EI_Shdr; /* recent Elf_Shdr to be stored */ static Elf_Phdr EI_Phdr; /* recent Elf_Phdr to be stored */ static int get_class(void) { return (EI_Ehdr.e_ident[EI_CLASS]); } static int get_version(void) { /* do as what libelf:_elf_config() does */ return (EI_Ehdr.e_ident[EI_VERSION] ? EI_Ehdr.e_ident[EI_VERSION] : 1); } static int get_format(void) { return (EI_Ehdr.e_ident[EI_DATA]); } /* * file_xlatetom: translate different headers from file * representation to memory representaion. */ #define HDRSZ 512 static int file_xlatetom(Elf_Type type, char *hdr) { Elf_Data src, dst; char *hbuf[HDRSZ]; int version, format; version = get_version(); format = get_format(); /* will convert only these types */ if (type != ELF_T_EHDR && type != ELF_T_PHDR && type != ELF_T_SHDR && type != ELF_T_WORD && type != ELF_T_CAP && type != ELF_T_DYN) return (ELF_READ_FAIL); src.d_buf = (Elf_Void *)hdr; src.d_type = type; src.d_version = version; dst.d_buf = (Elf_Void *)&hbuf; dst.d_version = EV_CURRENT; src.d_size = elf_fsize(type, 1, version); dst.d_size = elf_fsize(type, 1, EV_CURRENT); if (elf_xlatetom(&dst, &src, format) == NULL) return (ELF_READ_FAIL); (void) memcpy(hdr, &hbuf, dst.d_size); return (ELF_READ_OKAY); } /* * xlatetom_nhdr: There is no routine to convert Note header * so we convert each field of this header. */ static int xlatetom_nhdr(Elf_Nhdr *nhdr) { int r = ELF_READ_FAIL; r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_namesz); r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_descsz); r |= file_xlatetom(ELF_T_WORD, (char *)&nhdr->n_type); return (r); } /* * elf_read: reads elf header, program, section headers to * collect all information needed for file(1) * output and stores them in Elf_Info. */ int elf_read(int fd, Elf_Info *EI) { FILE_ELF_SIZE_T size; int ret = 1; Elf_Ehdr *ehdr = &EI_Ehdr; EI->elffd = fd; size = sizeof (Elf_Ehdr); if (pread64(EI->elffd, (void*)ehdr, size, 0) != size) ret = 0; if (file_xlatetom(ELF_T_EHDR, (char *)ehdr) == ELF_READ_FAIL) ret = 0; if (EI->file == NULL) return (ELF_READ_FAIL); /* * Extended section or program indexes in use? If so, special * values in the ELF header redirect us to get the real values * from shdr[0]. */ EI_Ehdr_shnum = EI_Ehdr.e_shnum; EI_Ehdr_phnum = EI_Ehdr.e_phnum; EI_Ehdr_shstrndx = EI_Ehdr.e_shstrndx; if (((EI_Ehdr_shnum == 0) || (EI_Ehdr_phnum == PN_XNUM)) && (EI_Ehdr.e_shoff != 0)) { if (get_shdr(EI, 0) == ELF_READ_FAIL) return (ELF_READ_FAIL); if (EI_Ehdr_shnum == 0) EI_Ehdr_shnum = EI_Shdr.sh_size; if ((EI_Ehdr_phnum == PN_XNUM) && (EI_Shdr.sh_info != 0)) EI_Ehdr_phnum = EI_Shdr.sh_info; if (EI_Ehdr_shstrndx == SHN_XINDEX) EI_Ehdr_shstrndx = EI_Shdr.sh_link; } EI->type = ehdr->e_type; EI->machine = ehdr->e_machine; EI->flags = ehdr->e_flags; if (ret == 0) { (void) fprintf(stderr, gettext("%s: %s: can't " "read ELF header\n"), File, EI->file); return (ELF_READ_FAIL); } if (process_phdr(EI) == ELF_READ_FAIL) return (ELF_READ_FAIL); /* We don't need section info for core files */ if (ehdr->e_type != ET_CORE) if (process_shdr(EI) == ELF_READ_FAIL) return (ELF_READ_FAIL); return (ELF_READ_OKAY); } /* * get_phdr: reads program header of specified index. */ static int get_phdr(Elf_Info *EI, int inx) { FILE_ELF_OFF_T off = 0; FILE_ELF_SIZE_T size; if (inx >= EI_Ehdr_phnum) return (ELF_READ_FAIL); size = sizeof (Elf_Phdr); off = (FILE_ELF_OFF_T)EI_Ehdr.e_phoff + (inx * size); if (pread64(EI->elffd, (void *)&EI_Phdr, size, off) != size) return (ELF_READ_FAIL); if (file_xlatetom(ELF_T_PHDR, (char *)&EI_Phdr) == ELF_READ_FAIL) return (ELF_READ_FAIL); return (ELF_READ_OKAY); } /* * get_shdr: reads section header of specified index. */ static int get_shdr(Elf_Info *EI, int inx) { FILE_ELF_OFF_T off = 0; FILE_ELF_SIZE_T size; /* * Prevent access to non-existent section headers. * * A value of 0 for e_shoff means that there is no section header * array in the file. A value of 0 for e_shndx does not necessarily * mean this - there can still be a 1-element section header array * to support extended section or program header indexes that * exceed the 16-bit fields used in the ELF header to represent them. */ if ((EI_Ehdr.e_shoff == 0) || ((inx > 0) && (inx >= EI_Ehdr_shnum))) return (ELF_READ_FAIL); size = sizeof (Elf_Shdr); off = (FILE_ELF_OFF_T)EI_Ehdr.e_shoff + (inx * size); if (pread64(EI->elffd, (void *)&EI_Shdr, size, off) != size) return (ELF_READ_FAIL); if (file_xlatetom(ELF_T_SHDR, (char *)&EI_Shdr) == ELF_READ_FAIL) return (ELF_READ_FAIL); return (ELF_READ_OKAY); } /* * process_phdr: Read Program Headers and see if it is a core * file of either new or (pre-restructured /proc) * type, read the name of the file that dumped this * core, else see if this is a dynamically linked. */ static int process_phdr(Elf_Info *EI) { register int inx; Elf_Nhdr Nhdr, *nhdr; /* note header just read */ Elf_Phdr *phdr = &EI_Phdr; FILE_ELF_SIZE_T nsz, nmsz, dsz; FILE_ELF_OFF_T offset; int class; int ntype; char *psinfo, *fname; nsz = sizeof (Elf_Nhdr); nhdr = &Nhdr; class = get_class(); for (inx = 0; inx < EI_Ehdr_phnum; inx++) { if (get_phdr(EI, inx) == ELF_READ_FAIL) return (ELF_READ_FAIL); /* read the note if it is a core */ if (phdr->p_type == PT_NOTE && EI_Ehdr.e_type == ET_CORE) { /* * If the next segment is also a note, use it instead. */ if (get_phdr(EI, inx+1) == ELF_READ_FAIL) return (ELF_READ_FAIL); if (phdr->p_type != PT_NOTE) { /* read the first phdr back */ if (get_phdr(EI, inx) == ELF_READ_FAIL) return (ELF_READ_FAIL); } offset = phdr->p_offset; if (pread64(EI->elffd, (void *)nhdr, nsz, offset) != nsz) return (ELF_READ_FAIL); /* Translate the ELF note header */ if (xlatetom_nhdr(nhdr) == ELF_READ_FAIL) return (ELF_READ_FAIL); ntype = nhdr->n_type; nmsz = nhdr->n_namesz; dsz = nhdr->n_descsz; offset += nsz + ((nmsz + 0x03) & ~0x3); if ((psinfo = malloc(dsz)) == NULL) { int err = errno; (void) fprintf(stderr, gettext("%s: malloc " "failed: %s\n"), File, strerror(err)); exit(1); } if (pread64(EI->elffd, psinfo, dsz, offset) != dsz) return (ELF_READ_FAIL); /* * We want to print the string contained * in psinfo->pr_fname[], where 'psinfo' * is either an old NT_PRPSINFO structure * or a new NT_PSINFO structure. * * Old core files have only type NT_PRPSINFO. * New core files have type NT_PSINFO. * * These structures are also different by * virtue of being contained in a core file * of either 32-bit or 64-bit type. * * To further complicate matters, we ourself * might be compiled either 32-bit or 64-bit. * * For these reason, we just *know* the offsets of * pr_fname[] into the four different structures * here, regardless of how we are compiled. */ if (class == ELFCLASS32) { /* 32-bit core file, 32-bit structures */ if (ntype == NT_PSINFO) fname = psinfo + 88; else /* old: NT_PRPSINFO */ fname = psinfo + 84; } else if (class == ELFCLASS64) { /* 64-bit core file, 64-bit structures */ if (ntype == NT_PSINFO) fname = psinfo + 136; else /* old: NT_PRPSINFO */ fname = psinfo + 120; } EI->core_type = (ntype == NT_PRPSINFO)? EC_OLDCORE : EC_NEWCORE; (void) memcpy(EI->fname, fname, strlen(fname)); free(psinfo); } if (phdr->p_type == PT_DYNAMIC) { EI->dynamic = B_TRUE; } } return (ELF_READ_OKAY); } /* * process_shdr: Read Section Headers to attempt to get HW/SW * capabilities by looking at the SUNW_cap * section and set string in Elf_Info. * Also look for symbol tables and debug * information sections. Set the "stripped" field * in Elf_Info with corresponding flags. */ static int process_shdr(Elf_Info *EI) { int mac; int i, idx; char *strtab; size_t strtab_sz; uint64_t j; Elf_Shdr *shdr = &EI_Shdr; mac = EI_Ehdr.e_machine; /* if there are no sections, return success anyway */ if (EI_Ehdr.e_shoff == 0 && EI_Ehdr_shnum == 0) return (ELF_READ_OKAY); /* read section names from String Section */ if (get_shdr(EI, EI_Ehdr_shstrndx) == ELF_READ_FAIL) return (ELF_READ_FAIL); if ((strtab = malloc(shdr->sh_size)) == NULL) return (ELF_READ_FAIL); if (pread64(EI->elffd, strtab, shdr->sh_size, shdr->sh_offset) != shdr->sh_size) return (ELF_READ_FAIL); strtab_sz = shdr->sh_size; /* read all the sections and process them */ for (idx = 1, i = 0; i < EI_Ehdr_shnum; idx++, i++) { char *shnam; if (get_shdr(EI, i) == ELF_READ_FAIL) return (ELF_READ_FAIL); if (shdr->sh_type == SHT_NULL) { idx--; continue; } if (shdr->sh_type == SHT_SUNW_cap) { char capstr[128]; Elf_Cap Chdr; FILE_ELF_OFF_T cap_off; FILE_ELF_SIZE_T csize; uint64_t capn; cap_off = shdr->sh_offset; csize = sizeof (Elf_Cap); if (shdr->sh_size == 0 || shdr->sh_entsize == 0) { (void) fprintf(stderr, ELF_ERR_ELFCAP1, File, EI->file); return (ELF_READ_FAIL); } capn = (shdr->sh_size / shdr->sh_entsize); for (j = 0; j < capn; j++) { /* * read cap and xlate the values */ if ((pread64(EI->elffd, &Chdr, csize, cap_off) != csize) || file_xlatetom(ELF_T_CAP, (char *)&Chdr) == 0) { (void) fprintf(stderr, ELF_ERR_ELFCAP2, File, EI->file); return (ELF_READ_FAIL); } cap_off += csize; /* * Each capatibility group is terminated with * CA_SUNW_NULL. Groups other than the first * represent symbol capabilities, and aren't * interesting here. */ if (Chdr.c_tag == CA_SUNW_NULL) break; (void) elfcap_tag_to_str(ELFCAP_STYLE_UC, Chdr.c_tag, Chdr.c_un.c_val, capstr, sizeof (capstr), ELFCAP_FMT_SNGSPACE, mac); if ((*EI->cap_str != '\0') && (*capstr != '\0')) (void) strlcat(EI->cap_str, " ", sizeof (EI->cap_str)); (void) strlcat(EI->cap_str, capstr, sizeof (EI->cap_str)); } } else if (shdr->sh_type == SHT_DYNAMIC) { Elf_Dyn dyn; FILE_ELF_SIZE_T dsize; FILE_ELF_OFF_T doff; uint64_t dynn; doff = shdr->sh_offset; dsize = sizeof (Elf_Dyn); if (shdr->sh_size == 0 || shdr->sh_entsize == 0) { (void) fprintf(stderr, ELF_ERR_DYNAMIC1, File, EI->file); return (ELF_READ_FAIL); } dynn = (shdr->sh_size / shdr->sh_entsize); for (j = 0; j < dynn; j++) { if (pread64(EI->elffd, &dyn, dsize, doff) != dsize || file_xlatetom(ELF_T_DYN, (char *)&dyn) == 0) { (void) fprintf(stderr, ELF_ERR_DYNAMIC2, File, EI->file); return (ELF_READ_FAIL); } doff += dsize; if ((dyn.d_tag == DT_SUNW_KMOD) && (dyn.d_un.d_val == 1)) { EI->kmod = B_TRUE; } } } /* * Definition time: * - "not stripped" means that an executable file * contains a Symbol Table (.symtab) * - "stripped" means that an executable file * does not contain a Symbol Table. * When strip -l or strip -x is run, it strips the * debugging information (.line section name (strip -l), * .line, .debug*, .stabs*, .dwarf* section names * and SHT_SUNW_DEBUGSTR and SHT_SUNW_DEBUG * section types (strip -x), however the Symbol * Table will still be present. * Therefore, if * - No Symbol Table present, then report * "stripped" * - Symbol Table present with debugging * information (line number or debug section names, * or SHT_SUNW_DEBUGSTR or SHT_SUNW_DEBUG section * types) then report: * "not stripped" * - Symbol Table present with no debugging * information (line number or debug section names, * or SHT_SUNW_DEBUGSTR or SHT_SUNW_DEBUG section * types) then report: * "not stripped, no debugging information * available" */ if ((EI->stripped & E_NOSTRIP) == E_NOSTRIP) continue; if (!(EI->stripped & E_SYMTAB) && (shdr->sh_type == SHT_SYMTAB)) { EI->stripped |= E_SYMTAB; continue; } if (shdr->sh_name >= strtab_sz) shnam = NULL; else shnam = &strtab[shdr->sh_name]; if (!(EI->stripped & E_DBGINF) && ((shdr->sh_type == SHT_SUNW_DEBUG) || (shdr->sh_type == SHT_SUNW_DEBUGSTR) || (shnam != NULL && is_in_list(shnam)))) { EI->stripped |= E_DBGINF; } } free(strtab); return (ELF_READ_OKAY); } /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ELF_READ_H #define _ELF_READ_H #define BUFSZ 128 typedef struct Elf_Info { boolean_t dynamic; /* dymanically linked? */ unsigned core_type; /* core? what type of core? */ unsigned stripped; /* symtab, debug info */ unsigned flags; /* e_flags */ unsigned machine; /* e_machine */ unsigned type; /* e_type */ int elffd; /* fd of file being processed */ char fname[PRFNSZ]; /* name of process that dumped core */ char cap_str[BUFSZ]; /* hw/sw capabilities */ char *file; /* file being processed */ boolean_t kmod; } Elf_Info; /* values for Elf_Info.stripped */ #define E_DBGINF 0x01 #define E_SYMTAB 0x02 #define E_NOSTRIP 0x03 /* values for Elf_Info.core_type; */ #define EC_NOTCORE 0x0 #define EC_OLDCORE 0x1 #define EC_NEWCORE 0x2 /* elf file processing errors */ #define ELF_ERR_ELFCAP1 gettext("%s: %s zero size or zero entry ELF " \ "section - ELF capabilities ignored\n") #define ELF_ERR_ELFCAP2 gettext("%s: %s: can't read ELF capabilities " \ "data - ELF capabilities ignored\n") #define ELF_ERR_DYNAMIC1 gettext("%s: %s zero size or zero entry ELF " \ "section - ELF dynamic tags ignored\n") #define ELF_ERR_DYNAMIC2 gettext("%s: %s: can't read ELF dynamic " \ "data - ELF dynamic tags ignored\n") extern int is_in_list(char *str); /* return status for elf_read and its helper functions */ #define ELF_READ_OKAY 1 #define ELF_READ_FAIL 0 #if defined(_ELF64) #define Elf_Ehdr Elf64_Ehdr #define Elf_Shdr Elf64_Shdr #define Elf_Phdr Elf64_Phdr #define Elf_Cap Elf64_Cap #define Elf_Nhdr Elf64_Nhdr #define Elf_Word Elf64_Word #define Elf_Dyn Elf64_Dyn #define elf_read elf_read64 #define elf_xlatetom elf64_xlatetom #define elf_fsize elf64_fsize #define get_class get_class64 #define get_version get_version64 #define get_format get_format64 #else #define Elf_Ehdr Elf32_Ehdr #define Elf_Shdr Elf32_Shdr #define Elf_Phdr Elf32_Phdr #define Elf_Cap Elf32_Cap #define Elf_Nhdr Elf32_Nhdr #define Elf_Word Elf32_Word #define Elf_Dyn Elf32_Dyn #define elf_read elf_read32 #define elf_xlatetom elf32_xlatetom #define elf_fsize elf32_fsize #define get_class get_class32 #define get_version get_version32 #define get_format get_format32 #endif /* so lint can understand elf_read64 is defined */ #ifdef lint #define elf_read64 elf_read #endif /* lint */ #endif /* _ELF_READ_H */ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 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:" */ 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); } else if (*(int *)fbuf == CORE_MAGIC) { #if !defined(_LP64) struct core *corep = (struct core *)fbuf; #endif (void) printf("a.out core file"); #if !defined(_LP64) if (*(corep->c_cmdname) != '\0') (void) printf(" from '%s'", corep->c_cmdname); #endif (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') && ((uchar_t)fbuf[1] == (uchar_t)'\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", [EM_LANAI] = "Lanai", [EM_CEVA] = "CEVA", [EM_CEVA_X2] = "CEVA X2", [EM_BPF] = "Linux BPF", [EM_GRAPHCORE_IPU] = "Graphcore IPU", [EM_IMG1] = "Imagination Technologies", [EM_NFP] = "Netronome Flow Processor", [EM_VE] = "NEC Vector Engine", [EM_CSKY] = "C-SKY", [EM_ARC_COMPACT3_64] = "ARCv2.3 (64-bit)", [EM_MCS6502] = "MCS6502", [EM_ARC_COMPACT3] = "ARCv2.3 (32-bit)", [EM_KVX] = "Kalray KVX", [EM_65816] = "WDC 65816/65C816", [EM_LOONGARCH] = "Loongarch", [EM_KF32] = "KungFu32", [EM_U16_U8CORE] = "nX-U16/U8", [EM_TACHYUM] = "Tachyum", [EM_56800EF] = "NXP 56800EF", [EM_SBF] = "Solana Bytecode", [EM_AIENGINE] = "AMD/Xilinx AIEngine", [EM_SIMA_MLA] = "SiMa MLA", [EM_BANG] = "BANG", [EM_LOONGGPU] = "LoongGPU", [EM_SW64] = "SW64", [EM_AIECTRLCODE] = "AMD/Xilinx AIEngine ctrlcode", }; /* If new machine is added, refuse to compile until we're updated */ #if EM_NUM != (EM_AIECTRLCODE + 1) #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); if (EInfo.kmod) { (void) printf(", %s", gettext("kernel module")); } /* 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); } /* look for "1hddddd" where d is a digit */ static int sccs(void) { 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; } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _FILE_H #define _FILE_H /* * header for the file command */ #ifdef __cplusplus extern "C" { #endif extern int f_mkmtab(char *, int, int); extern int f_ckmtab(char *, int, int); extern void f_prtmtab(void); extern intmax_t f_getmaxoffset(int); #ifdef __cplusplus } #endif #endif /* _FILE_H */ # # Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2020 OmniOS Community Edition (OmniOSce) Association. # # 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 # # This file contains the dictionary of file format identifiers (magic strings) # used by file(1). The fields of this file are as follows: # # (1) byte offset # (2) value type # (3) optional operator (= by default) # (4) value to match (numeric or string) # (5) string to be printed # # Numeric values may be decimal, octal, or hex. Also note that the last string # may have one printf format specifier. The '>' in occassional column 1's is # magic: it forces file(1) to continue scanning and matching additional lines. # The first line afterwards not so marked terminates the search. # # The entries for ELF are not needed anymore, as file(1) now uses the elf(3ELF) # routines to look at ELF files. They remain, commented out, for reference. # #0 string \177ELF ELF #>4 byte 1 32-bit #>5 byte 1 LSB #>5 byte 2 MSB #>16 short 0 unknown type #>16 short 1 relocatable #>16 short 2 executable #>16 short 3 dynamic lib #>16 short 4 core file #>18 short 0 unknown machine #>18 short 1 WE32100 #>18 short 2 SPARC #>18 short 3 80386 #>18 short 4 M68000 #>18 short 5 M88000 #>18 short 6 i80486 #>18 short 7 i860 #>18 short 8 RS3000_BE #>18 short 9 UNKNOWN #>18 short 10 RS3000_LE #>18 short 11 RS6000 #>18 short 12 UNKNOWN #>18 short 13 UNKNOWN #>18 short 14 UNKNOWN #>18 short 15 PA_RISC #>18 short 16 nCUBE #>18 short 17 VPP500 #>18 short 18 SPARC32PLUS #>18 short 19 UNKNOWN #>18 short 20 PowerPC #>20 long 1 Version 1 #>36 long 1 MAU Required 257 string ustar USTAR tar archive >156 byte 88 extended format 0 short 070701 cpio archive 0 string 070701 ASCII cpio archive 0 short 070702 cpio archive - CRC header 0 string 070702 ASCII cpio archive - CRC header 0 short 070707 cpio archive - CHR (-c) header 0 string 070707 ASCII cpio archive - CHR (-c) header 0 long 0177555 obsolete ar archive 0 short 0177545 pdp11/pre System V ar archive 0 long 0100554 apl workspace 0 short 017037 packed data 0 string System V Release 1 ar archive 0 string ! current ar archive 0 short 0407 pdp11/pre System V vax executable >8 ushort >0 not stripped >15 ubyte >0 - version %ld 0 short 0401 unix-rt ldp 0 short 0405 pdp11 overlay 0 short 0410 pdp11/pre System V vax pure executable >8 ushort >0 not stripped >15 ubyte >0 - version %ld 0 short 0411 pdp11 separate I&D >8 ushort >0 not stripped >15 ubyte >0 - version %ld 0 short 015001 Compiled Terminfo Entry # little-endian entry 0 short 0432 Compiled Terminfo Entry 0 short 0433 Curses screen image 0 short 0434 Curses screen image 0 short 0437 pdp11 kernel overlay 0 short 0570 vax executable >12 long >0 not stripped >22 ushort >0 - version %ld 0 short 0575 vax pure executable >12 long >0 not stripped >22 ushort >0 - version %ld 0 short 0502 basic-16 executable >12 long >0 not stripped >22 ushort >0 - version %ld 0 short 0503 basic-16 executable (TV) >12 long >0 not stripped >22 ushort >0 - version %ld 0 short 0510 x86 executable >12 long >0 not stripped 0 short 0511 x86 executable (TV) >12 long >0 not stripped 0 short 0550 3b20 executable >12 long >0 not stripped >22 ushort >0 - version %ld 0 short 0551 3b20 executable (TV) >12 long >0 not stripped >22 ushort >0 - version %ld 0 short 0560 WE32000 executable >12 long >0 not stripped >18 short ^00010000 - N/A on 3b2/300 w/paging >18 short &00020000 - 32100 required >18 short &00040000 and mau hardware required >20 short 0443 (target shared library) >20 short 0410 (swapped) >20 short 0413 (paged) >22 ushort >0 - version %ld 0 short 0561 WE32000 executable (TV) >12 long >0 not stripped >18 short &00020000 - 32100 required >18 short &00040000 and mau hardware required >22 ushort >0 - version %ld 0 short =0512 iAPX 286 executable small model (COFF) >12 long >0 not stripped >22 ushort >0 - version %ld 0 short =0522 iAPX 286 executable large model (COFF) >12 long >0 not stripped >22 ushort >0 - version %ld 0 short 0514 iAPX 386 executable (COFF) (deprecated) >12 long >0 not stripped >22 ushort >0 - version %ld 0 short 0520 mc68k executable >12 long >0 not stripped 0 short 0521 mc68k executable (shared) >12 long >0 not stripped 0 short 0522 mc68k executable (shared demand paged) >12 long >0 not stripped # big-endian entries for pure executables 2 short 0410 pure >1 byte 0 sun2 executable >1 byte 1 mc68010 executable >1 byte 2 mc68020 executable >1 byte 3 SPARC executable >0 ubyte >077 dynamically linked # little-endian entries for pure executables 2 short 04001 pure >1 byte 0 sun2 executable >1 byte 1 mc68010 executable >1 byte 2 mc68020 executable >1 byte 3 SPARC executable >0 ubyte >077 dynamically linked # big-endian entries for impure executables 2 short 0407 impure >1 byte 0 sun2 executable >1 byte 1 mc68010 executable >1 byte 2 mc68020 executable >1 byte 3 SPARC executable >0 ubyte >077 dynamically linked # little-endian entries for impure executables 2 short 03401 impure >1 byte 0 sun2 executable >1 byte 1 mc68010 executable >1 byte 2 mc68020 executable >1 byte 3 SPARC executable >0 ubyte >077 dynamically linked # big-endian entries for Sun demand paged executables 2 short 0413 Sun demand paged >1 byte 0 sun2 executable >1 byte 1 mc68010 executable >1 byte 2 mc68020 executable >1 byte 3 SPARC executable >0 ubyte >077 dynamically linked # little-endian entries for Sun demand paged executables 2 short 05401 Sun demand paged >1 byte 0 sun2 executable >1 byte 1 mc68010 executable >1 byte 2 mc68020 executable >1 byte 3 SPARC executable >0 ubyte >077 dynamically linked 0 short 0x8001 Adobe PostScript Type 1 binary font (PFB) 0 short 0x0180 Adobe PostScript Type 1 binary font (PFB) 0 long 0x00010000 TrueType font file version 1.0 (TTF) 0 long 0x00000100 TrueType font file version 1.0 (TTF) 0 long 0xf00000ff extended accounting file # little-endian entry 0 long 0xff0000f0 extended accounting file 0 byte 0x80 8086 relocatable (Microsoft) 0 byte 0xf0 MS-DOS library 0 short 0xff65 x.out >2 string __.SYMDEF randomized >0 byte x archive 0 short 0x206 Microsoft a.out >0x1e short &0x10 overlay >0x1e short &0x2 separate >0x1e short &0x4 pure >0x1e short &0x800 segmented >0x1e short &0x400 standalone >0x1e short &0x8 fixed-stack >0x1c byte &0x80 byte-swapped >0x1c byte &0x40 word-swapped >0x10 long >0 not-stripped >0x1e short ^0xc000 pre-SysV >0x1c byte &0x4 86 >0x1c byte &0x9 286 >0x1c byte &0xa 386 >0x1e short &0x1 executable >0x1e short ^0x1 object file >0x1e short &0x40 Large Text >0x1e short &0x20 Large Data >0x1e short &0x120 Huge Objects Enabled 0 short 0x10b VAX demand load format a.out object file >0x10 long >0 not stripped 0 short 0x140 old Microsoft 8086 x.out >0x3 byte &0x4 separate >0x3 byte &0x2 pure >0 byte &0x1 executable >0 byte ^0x1 relocatable >0x14 long >0 not stripped 0 long 0x10b VAX demand load format a.out object file >0x10 long >0 not stripped 0 long 0x140 old Microsoft 8086 x.out >0x3 byte &0x4 separate >0x3 byte &0x2 pure >0 byte &0x1 executable >0 byte ^0x1 relocatable >0x14 long >0 not stripped 0 long 0xe807 object file (z8000 a.out) 0 long 0xe808 pure object file (z8000 a.out) 0 long 0xe809 separate object file (z8000 a.out) 0 long 0xe805 overlay object file (z8000 a.out) 0 long 0x178 Bell 5.0 executable 2 short 0410 Sun read-only text executable >2 short 0407 Sun old executable >1 byte 3 (SPARC) >1 byte 2 (68020) >1 byte 1 (68010) >1 byte 0 (Sun2) 0 short 0143561 byte-swapped cpio archive 0 long 0101555 PDP-11 single precision APL workspace 0 long 0101554 PDP-11 double precision APL workspace 0 long 0101557 VAX single precision APL workspace 0 long 0101556 VAX double precision APL workspace 0 short 017437 old packed data 0 string \037\036 packed data 0 string \377\037 compacted data 0 string \037\235 compressed data >2 byte&0x80 >0 block compressed >2 byte&0x1f x %d bits 0 string \037\213 gzip compressed data >2 byte 8 - deflate method >3 byte &0x1 , ascii >3 byte &0x2 , continuation >3 byte &0x4 , extra field >3 byte &0x8 , original file name >3 byte &0x10 , comment >3 byte &0x20 , encrypted >8 byte 2 , max compression >8 byte 4 , max speed 0 string !\n__.SYMDEF archive random library 0 long 0x1010101 MMDF mailbox 0 string 0 string GKSM Metafile 0 string GKSM GKS Metafile # version number follows, in the form 0 string %!PS-AdobeFont Adobe PostScript ASCII font (PFA) 0 string %! PostScript document >2 string PS-Adobe conforming to level >10 string -1.0 1.0 >10 string -2.0 2.0 >10 string -3.0 3.0 # Handle Microsoft PostScript files (CTRL-D%!) 0 string \004%! PostScript document text # version ID follows, in the form PS-Adobe-nn 0 string Interpress/Xerox Interpress document # version ID follows, in the form /n.n 0 string StartFontMetrics Adobe font metrics 0 string StartFont Adobe font bits 0 long 0x137A2944 NeWS bitmap font 0 long 0x137A2947 NeWS font family 8 long 0x137A2B45 X11/NeWS bitmap font 8 long 0x137A2B48 X11/NeWS font family # snoop files are always big-endian # big-endian entries, with ullong equivalent of string "snoop" 0 ullong 0x736e6f6f70000000 Snoop capture file >8 long >0 - version %ld # little-endian entries, with ullong equivalent of string "snoop" 0 ullong 0x000000706f6f6e73 Snoop capture file >11 long >0 - version %ld 0 short 0436 vfont definition 0 string 12 long 1 8-bit u-law, >12 long 2 8-bit linear PCM, >12 long 3 16-bit linear PCM, >12 long 4 24-bit linear PCM, >12 long 5 32-bit linear PCM, >12 long 6 32-bit floating point, >12 long 7 64-bit floating point, >12 long 23 compressed (4-bit G.721 ADPCM), >12 long 24 compressed (8-bit G.722 ADPCM), >12 long 25 compressed (3-bit G.723 ADPCM), >12 long 26 compressed (5-bit G.723 ADPCM), >12 long 27 8-bit A-law, >20 long 1 mono, >20 long 2 stereo, >20 long 4 quad, >16 long x %d Hz # # little-endian entries # 0 long 0x646e732e audio data: >12 long 0x01000000 8-bit u-law, >12 long 0x02000000 8-bit linear PCM, >12 long 0x03000000 16-bit linear PCM, >12 long 0x04000000 24-bit linear PCM, >12 long 0x05000000 32-bit linear PCM, >12 long 0x06000000 32-bit floating point, >12 long 0x07000000 64-bit floating point, >12 long 0x17000000 compressed (4-bit G.721 ADPCM), >12 long 0x18000000 compressed (8-bit G.722 ADPCM), >12 long 0x19000000 compressed (3-bit G.723 ADPCM), >12 long 0x1a000000 compressed (5-bit G.723 ADPCM), >12 long 0x1b000000 8-bit A-law, >20 long 0x01000000 mono, >20 long 0x02000000 stereo, >20 long 0x04000000 quad, >16 long 0x401f0000 8000 Hz >16 long 0x80250000 9600 Hz >16 long 0x112b0000 11025 Hz >16 long 0x803e0000 16000 Hz >16 long 0xd4490000 18900 Hz >16 long 0x22560000 22050 Hz >16 long 0x007d0000 32000 Hz >16 long 0xa8930000 37800 Hz >16 long 0x44ac0000 44100 Hz >16 long 0x80bb0000 48000 Hz # .wav files are always little-endian # .wav big-endian entries, starting with long value for the string "RIFF" 0 long 0x52494646 audio data: >34 short 0x0800 8-bit >34 short 0x1000 16-bit >20 short 0x0100 linear PCM, >20 short 0x0200 MS ADPCM, >20 short 0x0600 A-law, >20 short 0x0700 u-law, >20 short 0x1100 DVI ADPCM, >22 short 0x0100 mono >22 short 0x0200 stereo # .wav little-endian entries, starting with long value for the string "RIFF" 0 long 0x46464952 audio data: >34 short 0x0008 8-bit >34 short 0x0010 16-bit >20 short 0x0001 linear PCM, >20 short 0x0002 MS ADPCM, >20 short 0x0006 A-law, >20 short 0x0007 u-law, >20 short 0x0011 DVI ADPCM, >22 short 0x0001 mono >22 short 0x0002 stereo # .aiff files are always big-endian # .aiff big-endian entries, starting with long value for the string "FORM" 0 long 0x464f524d audio data: >26 short 0x0008 8-bit linear PCM, >26 short 0x0010 16-bit linear PCM, >20 short 0x0001 mono >20 short 0x0002 stereo # .aiff little-endian entries, starting with long value for the string "FORM" 0 long 0x4d524f46 audio data: >26 short 0x0800 8-bit linear PCM, >26 short 0x1000 16-bit linear PCM, >20 short 0x0100 mono >20 short 0x0200 stereo # .mid files are always big-endian # .mid big-endian entries, starting with long value for the string "MThd" 0 long 0x4d546864 MIDI data: >8 short x type %u, >10 short x %u track(s) # .mid little-endian entry (the string "MThd") # can't translate big-endian type and track information 0 long 0x6468544d MIDI data # 0 short 0x1010 PEX Binary Archive # rasterfiles are big-endian # big-endian rasterfile entries 0 long 0x59a66a95 rasterfile, >4 long >0 %ld x >8 long >0 %ld x >12 long >0 %ld >20 long 0 old format image >20 long 1 standard format image >20 long 2 run-length byte encoded image >20 long 3 XRGB or RGB format image >20 long 4 tiff format image >20 long 5 iff (TAAC format) image >20 long 0xffff experimental format image # little-endian rasterfile entries # cannot translate resolution stored as big-endian longs 0 long 0x956aa659 rasterfile, >23 long 0 old format image >23 long 1 standard format image >23 long 2 run-length byte encoded image >23 long 3 XRGB or RGB format image >23 long 4 tiff format image >23 long 5 iff (TAAC format) image >20 long 0xffff experimental format image 0 long 0x884f5053 Interleaf fast-saved document 0 long 0x2a535441 Aster*x >7 long 0x574f5244 Words Document >7 long 0x47524150 Graphic >7 long 0x53505245 Spreadsheet >7 long 0x4d414352 Macro 0 long 0x32323738 Aster*x Version 2 >29 byte 0x36 Words Document >29 byte 0x35 Graphic >29 byte 0x32 Spreadsheet >29 byte 0x38 Macro 4 string pgscriptver IslandWrite document 13 string DrawFile IslandDraw document 0 string P1 PBM ascii file 0 string P2 PGM ascii file 0 string P3 PPM ascii file 0 string P4 PBM raw file 0 string P5 PGM raw file 0 string P6 PPM raw file 0 string \115\115 TIFF file, big-endian 0 string \111\111 TIFF file, little-endian 0 string GIF87a GIF file, v87 0 string GIF89a GIF file, v89 0 string \377\330\377\340 JPEG file 0 string \377\330\377\341 JPEG file 0 string \377\330\377\356 JPG file 8 string ILBM IFF ILBM file 0 string \312\376\272\276 java class file 36 string acsp Kodak Color Management System, ICC Profile 0 string %PDF Adobe Portable Document Format (PDF) >4 string -1.0 v1.0 >4 string -1.1 v1.1 >4 string -1.2 v1.2 >4 string -1.3 v1.3 >4 string -1.4 v1.4 >4 string -1.5 v1.5 0 string 13 string -1.0 1.0 >13 string -2.0 2.0 38 string application/vnd.sun.xml.writer StarOffice 7 Text Document 38 string application/vnd.sun.xml.calc StarOffice 7 Spreadsheet 38 string application/vnd.sun.xml.draw StarOffice 7 Drawing 38 string application/vnd.sun.xml.impress StarOffice 7 Presentation 38 string application/vnd.sun.xml.math StarOffice 7 Formula 38 string application/vnd.oasis.opendocument.chart OpenDocument Chart 38 string application/vnd.oasis.opendocument.database OpenDocument Database 38 string application/vnd.sun.xml.base OpenDocument Database 38 string application/vnd.oasis.opendocument.formula OpenDocument Formula 38 string application/vnd.oasis.opendocument.image OpenDocument Image 38 string application/vnd.oasis.opendocument.text-web HTML Document Template 38 string application/vnd.oasis.opendocument.text- OpenDocument >78 string template Text Template >78 string master Master Document 38 string application/vnd.oasis.opendocument.text OpenDocument Text 38 string application/vnd.oasis.opendocument.graphics OpenDocument Drawing >81 string -template Template 38 string application/vnd.oasis.opendocument.presentation OpenDocument Presentation >85 string -template Template 38 string application/vnd.oasis.opendocument.spreadsheet OpenDocument Spreadsheet >84 string -template Template 0 string PK\003\004 ZIP archive 0 string MZ DOS executable (EXE) 0 string LZ DOS built-in 0 byte 0xe9 DOS executable (COM) 0 byte 0xeb DOS executable (COM) 0 string \013\023\010\000 ksh compiled shell script executable 24 long 60012 ufsdump archive file 0 string TZif zoneinfo timezone data file 0 string BZh bzip2 compressed data >3 byte >47 , block size = %c00k 0 ulong 0xfd2fb528 Zstandard compressed file 0 string SUNWcpch Sun C compiler precompiled header 0 string SUNWCpch Sun C++ compiler precompiled header 0 string \043\040PaCkAgE\040DaTaStReAm package datastream 0 short 0xcff1 CTF data file 0 string \177DOF DTrace DOF data file 0 string \177FCF fmd(8) checkpoint file 0 string EFT\0 Fault tree file, >4 ushort x v%u >6 ushort x rev %u, >8 ushort x from esc v%u >10 ushort x rev %u 0 string _SM_ DMTF SMBIOS image >6 byte x version %u >7 byte x .%u 0 byte 0x11 Solaris Audit File 0 byte 0x78 Solaris Audit File # ZFS send stream entries 8 ullong 0x00000002f5bacbac ZFS snapshot stream # little endian stream 8 ullong 0xaccbbaf502000000 ZFS snapshot stream # Video files 2 string \001\272\041 MPEG Movie file 0 string \377\375 MPEG-1 Audio Layer 2 0 string \377\373 MPEG-1 Audio Layer 3 0 string \377\372 MPEG-1 Audio Layer 3 0 string \111\104\063 MPEG-1 Layer 3 with ID3v2 # AVI and GVI files 20 string hdrlavih RIFF Avi Video >36 ulong >0 %u Max Bps, >64 ushort x %u X >68 ushort x %u, >48 ulong x %u frames 20 string goog RIFF gvi >88 ulong >0 %u Max Bps >116 ushort x %u X >120 ushort x %u, >100 ulong x %u frames # JPEG 2000 - jp2 image file. 3 string \014\152\120\040\040 JPEG 2000 Image file # iso 9660 CD-ROM image and El Torito Bootable standard 32769 string CD\0 ISO 9660 filesystem image >34823 string EL\040TORITO - El Torito # Palm Pilot files .pdb and .prc of some type. 0x3c string TEXtREAd Palm DOC file 0x3c string SDocSilX iSilo 3 Doc file for PalmPilot 0x3c string applSil iSilo Application file 0x3c string appl Palm Pilot Application 0x3c string ToGoToGo iSilo Doc file for Palm Pilot #SGI files with .rgb extention 0 string \001\332 SGI Image data, >2 byte 1 RLE, >2 byte 0 Verbatim, >5 ubyte x %u-D >7 ubyte x %u x >9 ubyte x %u, >11 ubyte x %u channel(s) 2048 string PCD_IPI Kodak Photo CD image pack file >0xe02 byte&0x03 0x00 , landscape mode >0xe02 byte&0x03 0x01 , portrait mode >0xe02 byte&0x03 0x02 , landscape mode >0xe02 byte&0x03 0x03 , portrait mode 0 string PCD_OPA Kodak Photo CD overview pack file # MS Documents. Not much info available. 0 string \320\317\021\340\241\261\032\341 Microsoft >546 string bjbj Word >0 byte <0 Document 0 string {\\rtf Microsoft Rich Text Format Document # mp4 media format with different media files embedded in it 4 string ftyp MPEG-4 >8 string isom Base Media v1 [IS0 14496-12:2003] >8 string iso2 Base Media v2 [ISO 14496-12:2005] >8 string m4a\040 Apple iTunes AAC-LC (.M4A) Audio >8 string m4v\040 Apple iTunes (.M4V) Video >8 string qt Apple QuickTime (.MOV/QT) >8 string jp2 JPEG 2000 Image >8 string jpm JPEG 2000 Compound Image (.JPM) [ISO 15444-6] >8 string jpx JPEG 2000 w/ extensions (.JPX) [ISO 15444-2] >8 string mp42 v2 [ISO 14496-14] 4 string moov QuickTime MOV file 0 string \375\067\172\130\132\000 xz compressed data /* * 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 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* Copyright (c) 1987, 1988 Microsoft Corporation */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include /* * Types */ #define BYTE 1 #define SHORT 2 #define LONG 4 #define LLONG 8 #define UBYTE 16 #define USHORT 32 #define ULONG 64 #define ULLONG 128 #define STR 256 /* * Opcodes */ #define EQ 0 #define GT 1 #define LT 2 #define STRC 3 /* string compare */ #define ANY 4 #define AND 5 #define NSET 6 /* True if bit is not set */ #define SUB 64 /* or'ed in, SUBstitution string, for example */ /* %ld, %s, %lo mask: with bit 6 on, used to locate */ /* print formats */ /* * Misc */ #define BSZ 128 #define NENT 200 /* * Structure of magic file entry */ struct entry { char e_level; /* 0 or 1 */ off_t e_off; /* in bytes */ uint32_t e_type; /* BYTE, SHORT, STR, et al */ char e_opcode; /* EQ, GT, LT, ANY, AND, NSET */ uint64_t e_mask; /* if non-zero, mask value with this */ union { uint64_t num; char *str; } e_value; const char *e_str; }; /* Non-localized string giving name of command. Defined in file.c */ extern const char *File; typedef struct entry Entry; static Entry *mtab1; /* 1st magic table, applied before default tests */ /* * 2nd magic table, includes default tests and magic entries * to be applied after default position-sensitive tests */ static Entry *mtab2; static Entry *mend1; /* one past last-allocated entry in mtab1 */ static Entry *mend2; /* one past last-allocated entry in mtab2 */ static Entry *ep1; /* current entry in mtab1 */ static Entry *ep2; /* current entry in mtab2 */ static char * getstr(char *p, char *file) { char *newstr; char *s; long val; int base; newstr = (char *)malloc((strlen(p) + 1) * sizeof (char)); if (newstr == NULL) { int err = errno; (void) fprintf(stderr, gettext("%s: malloc failed: %s\n"), File, strerror(err)); return (NULL); } s = newstr; while (*p != '\0') { if (*p != '\\') { *s++ = *p++; continue; } p++; if (*p == '\0') break; if (isdigit(*p)) { if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) { /* hex */ base = 16; } else { base = 8; } errno = 0; val = strtol(p, &p, base); if (val > UCHAR_MAX || val < 0 || errno != 0) { (void) fprintf(stderr, gettext("%s: %s: magic " "table invalid string value\n"), File, file); return (NULL); } *s++ = (char)val; } else { /* escape the character */ switch (*p) { case 'n': *s = '\n'; break; case 'r': *s = '\r'; break; case 'a': *s = '\a'; break; case 'b': *s = '\b'; break; case 'f': *s = '\f'; break; case 't': *s = '\t'; break; case 'v': *s = '\v'; break; default: *s = *p; break; } p++; s++; } } *s = '\0'; return (newstr); } /* * f_mkmtab - fills mtab array of magic table entries with * values from the file magfile. * May be called more than once if multiple magic * files were specified. * Stores entries sequentially in one of two magic * tables: mtab1, if first = 1; mtab2 otherwise. * * If -c option is specified, cflg is non-zero, and * f_mkmtab() reports on errors in the magic file. * * Two magic tables may need to be created. The first * one (mtab1) contains magic entries to be checked before * the programmatic default position-sensitive tests in * def_position_tests(). * The second one (mtab2) should start with the default * /etc/magic file entries and is to be checked after * the programmatic default position-sensitive tests in * def_position_tests(). The parameter "first" would * be 1 for the former set of tables, 0 for the latter * set of magic tables. * No mtab2 should be created if file will not be * applying default tests; in that case, all magic table * entries should be in mtab1. * * f_mkmtab returns 0 on success, -1 on error. The calling * program is not expected to proceed after f_mkmtab() * returns an error. */ int f_mkmtab(char *magfile, int cflg, int first) { Entry *mtab; /* generic magic table pointer */ Entry *ep; /* current magic table entry */ Entry *mend; /* one past last-allocated entry of mtab */ FILE *fp; int lcnt = 0; char buf[BSZ]; size_t tbsize; size_t oldsize; if (first) { mtab = mtab1; mend = mend1; ep = ep1; } else { mtab = mtab2; mend = mend2; ep = ep2; } /* mtab may have been allocated on a previous f_mkmtab call */ if (mtab == (Entry *)NULL) { if ((mtab = calloc(NENT, sizeof (Entry))) == NULL) { int err = errno; (void) fprintf(stderr, gettext("%s: malloc " "failed: %s\n"), File, strerror(err)); return (-1); } ep = mtab; mend = &mtab[NENT]; } errno = 0; if ((fp = fopen(magfile, "r")) == NULL) { int err = errno; (void) fprintf(stderr, gettext("%s: %s: cannot open magic " "file: %s\n"), File, magfile, err ? strerror(err) : ""); return (-1); } while (fgets(buf, BSZ, fp) != NULL) { char *p = buf; char *p2; char *p3; char opc; /* * ensure we have one extra entry allocated * to mark end of the table, after the while loop */ if (ep >= (mend - 1)) { oldsize = mend - mtab; tbsize = (NENT + oldsize) * sizeof (Entry); if ((mtab = realloc(mtab, tbsize)) == NULL) { int err = errno; (void) fprintf(stderr, gettext("%s: malloc " "failed: %s\n"), File, strerror(err)); return (-1); } else { (void) memset(mtab + oldsize, 0, sizeof (Entry) * NENT); mend = &mtab[tbsize / sizeof (Entry)]; ep = &mtab[oldsize-1]; } } lcnt++; if (*p == '\n' || *p == '#') continue; /* LEVEL */ if (*p == '>') { ep->e_level = 1; p++; } /* OFFSET */ p2 = strchr(p, '\t'); if (p2 == NULL) { if (cflg) (void) fprintf(stderr, gettext("%s: %s: format " "error, no tab after %s on line %d\n"), File, magfile, p, lcnt); continue; } *p2++ = '\0'; ep->e_off = strtol((const char *)p, (char **)NULL, 0); while (*p2 == '\t') p2++; /* TYPE */ p = p2; p2 = strchr(p, '\t'); if (p2 == NULL) { if (cflg) (void) fprintf(stderr, gettext("%s: %s: format " "error, no tab after %s on line %d\n"), File, magfile, p, lcnt); continue; } *p2++ = '\0'; p3 = strchr(p, '&'); if (p3 != NULL) { *p3++ = '\0'; ep->e_mask = strtoull((const char *)p3, (char **)NULL, 0); /* returns 0 or ULLONG_MAX on error */ } else { ep->e_mask = 0ULL; } switch (*p) { case 'd': if (*(p+1) == '\0') { /* d */ ep->e_type = LONG; } else if (*(p+2) == '\0') { /* d? */ switch (*(p+1)) { case 'C': case '1': /* dC, d1 */ ep->e_type = BYTE; break; case 'S': case '2': /* dS, d2 */ ep->e_type = SHORT; break; case 'I': case 'L': case '4': /* dI, dL, d4 */ ep->e_type = LONG; break; case '8': /* d8 */ ep->e_type = LLONG; break; default: ep->e_type = LONG; break; } } break; case 'l': if (*(p+1) == 'l') { /* llong */ ep->e_type = LLONG; } else { /* long */ ep->e_type = LONG; } break; case 's': if (*(p+1) == 'h') { /* short */ ep->e_type = SHORT; } else { /* s or string */ ep->e_type = STR; } break; case 'u': if (*(p+1) == '\0') { /* u */ ep->e_type = ULONG; } else if (*(p+2) == '\0') { /* u? */ switch (*(p+1)) { case 'C': case '1': /* uC, u1 */ ep->e_type = UBYTE; break; case 'S': case '2': /* uS, u2 */ ep->e_type = USHORT; break; case 'I': case 'L': case '4': /* uI, uL, u4 */ ep->e_type = ULONG; break; case '8': /* u8 */ ep->e_type = ULLONG; break; default: ep->e_type = ULONG; break; } } else { /* u?* */ switch (*(p+1)) { case 'b': /* ubyte */ ep->e_type = UBYTE; break; case 's': /* ushort */ ep->e_type = USHORT; break; case 'l': if (*(p+2) == 'l') { /* ullong */ ep->e_type = ULLONG; } else { /* ulong */ ep->e_type = ULONG; } break; default: /* default, same as "u" */ ep->e_type = ULONG; break; } } break; default: /* retain (undocumented) default type */ ep->e_type = BYTE; break; } if (ep->e_type == 0) { ep->e_type = BYTE; /* default */ } while (*p2 == '\t') p2++; /* OP-VALUE */ p = p2; p2 = strchr(p, '\t'); if (p2 == NULL) { if (cflg) (void) fprintf(stderr, gettext("%s: %s: format " "error, no tab after %s on line %d\n"), File, magfile, p, lcnt); continue; } *p2++ = '\0'; if (ep->e_type != STR) { opc = *p++; switch (opc) { case '=': ep->e_opcode = EQ; break; case '>': ep->e_opcode = GT; break; case '<': ep->e_opcode = LT; break; case 'x': ep->e_opcode = ANY; break; case '&': ep->e_opcode = AND; break; case '^': ep->e_opcode = NSET; break; default: /* EQ (i.e. 0) is default */ p--; /* since global ep->e_opcode=0 */ } } if (ep->e_opcode != ANY) { if (ep->e_type != STR) { ep->e_value.num = strtoull((const char *)p, (char **)NULL, 0); } else if ((ep->e_value.str = getstr(p, magfile)) == NULL) { return (-1); } } p2 += strspn(p2, "\t"); /* STRING */ if ((ep->e_str = strdup(p2)) == NULL) { int err = errno; (void) fprintf(stderr, gettext("%s: malloc " "failed: %s\n"), File, strerror(err)); return (-1); } else { if ((p = strchr(ep->e_str, '\n')) != NULL) *p = '\0'; if (strchr(ep->e_str, '%') != NULL) ep->e_opcode |= SUB; } ep++; } /* end while (fgets) */ ep->e_off = -1L; /* mark end of table */ if (first) { mtab1 = mtab; mend1 = mend; ep1 = ep; } else { mtab2 = mtab; mend2 = mend; ep2 = ep; } if (fclose(fp) != 0) { int err = errno; (void) fprintf(stderr, gettext("%s: fclose failed: %s\n"), File, strerror(err)); return (-1); } return (0); } /* * Check for Magic Table entries in the file. * * Since there may be two sets of magic tables, first = 1 * for the first magic table (mtab1) and 0 for the second magic * table (mtab2). */ int f_ckmtab(char *buf, int bufsize, int first) { int result; Entry *mtab; Entry *ep; char *p; int lev1 = 0; uint16_t u16_val; uint32_t u32_val; uint64_t u64_val; if (first) { mtab = mtab1; } else { mtab = mtab2; } if (mtab == (Entry *)NULL) { return (0); /* no magic file tests in this table */ } for (ep = mtab; ep->e_off != -1L; ep++) { /* -1 offset marks end of */ if (lev1) { /* valid magic file entries */ if (ep->e_level != 1) break; } else if (ep->e_level == 1) { continue; } if (ep->e_off > (off_t)bufsize) continue; p = &buf[ep->e_off]; switch (ep->e_type) { case STR: { if (strncmp(p, ep->e_value.str, strlen(ep->e_value.str))) continue; if (lev1) { (void) putchar(' '); } if (ep->e_opcode & SUB) (void) printf(ep->e_str, ep->e_value.str); else (void) printf(ep->e_str); lev1 = 1; continue; /* * We've matched the string and printed the message; * no STR processing occurs beyond this point. */ } case BYTE: case UBYTE: u64_val = (uint64_t)(uint8_t)(*p); break; case SHORT: case USHORT: (void) memcpy(&u16_val, p, sizeof (uint16_t)); u64_val = (uint64_t)u16_val; break; case LONG: case ULONG: (void) memcpy(&u32_val, p, sizeof (uint32_t)); u64_val = (uint64_t)u32_val; break; case LLONG: case ULLONG: (void) memcpy(&(u64_val), p, sizeof (uint64_t)); break; } if (ep->e_mask) { u64_val &= ep->e_mask; } /* * Compare the values according to the size and sign * of the type. For =, &, and ^ operators, the sign * does not have any effect, so these are always compared * unsigned. Only for < and > operators is the * sign significant. * If the file value was masked, the compare should * be unsigned. */ switch (ep->e_opcode & ~SUB) { case EQ: switch (ep->e_type) { case BYTE: case UBYTE: if ((uint8_t)u64_val != (uint8_t)(ep->e_value.num)) continue; break; case SHORT: case USHORT: if ((uint16_t)u64_val != (uint16_t)(ep->e_value.num)) continue; break; case LONG: case ULONG: if ((uint32_t)u64_val != (uint32_t)(ep->e_value.num)) continue; break; case LLONG: case ULLONG: if (u64_val != ep->e_value.num) continue; break; default: continue; } break; case GT: switch (ep->e_type) { case BYTE: if (ep->e_mask == 0) { if ((int8_t)u64_val <= (int8_t)(ep->e_value.num)) continue; break; } /*FALLTHROUGH*/ case UBYTE: if ((uint8_t)u64_val <= (uint8_t)(ep->e_value.num)) continue; break; case SHORT: if (ep->e_mask == 0) { if ((int16_t)u64_val <= (int16_t)(ep->e_value.num)) continue; break; } /*FALLTHROUGH*/ case USHORT: if ((uint16_t)u64_val <= (uint16_t)(ep->e_value.num)) continue; break; case LONG: if (ep->e_mask == 0) { if ((int32_t)u64_val <= (int32_t)(ep->e_value.num)) continue; break; } /*FALLTHROUGH*/ case ULONG: if ((uint32_t)u64_val <= (uint32_t)(ep->e_value.num)) continue; break; case LLONG: if (ep->e_mask == 0) { if ((int64_t)u64_val <= (int64_t)(ep->e_value.num)) continue; break; } /*FALLTHROUGH*/ case ULLONG: if (u64_val <= ep->e_value.num) continue; break; default: continue; } break; case LT: switch (ep->e_type) { case BYTE: if (ep->e_mask == 0) { if ((int8_t)u64_val >= (int8_t)(ep->e_value.num)) continue; break; } /*FALLTHROUGH*/ case UBYTE: if ((uint8_t)u64_val >= (uint8_t)(ep->e_value.num)) continue; break; case SHORT: if (ep->e_mask == 0) { if ((int16_t)u64_val >= (int16_t)(ep->e_value.num)) continue; break; } /*FALLTHROUGH*/ case USHORT: if ((uint16_t)u64_val >= (uint16_t)(ep->e_value.num)) continue; break; case LONG: if (ep->e_mask == 0) { if ((int32_t)u64_val >= (int32_t)(ep->e_value.num)) continue; break; } /*FALLTHROUGH*/ case ULONG: if ((uint32_t)u64_val >= (uint32_t)(ep->e_value.num)) continue; break; case LLONG: if (ep->e_mask == 0) { if ((int64_t)u64_val >= (int64_t)(ep->e_value.num)) continue; break; } /*FALLTHROUGH*/ case ULLONG: if (u64_val >= ep->e_value.num) continue; break; default: continue; } break; case AND: switch (ep->e_type) { case BYTE: case UBYTE: if (((uint8_t)u64_val & (uint8_t)(ep->e_value.num)) == (uint8_t)(ep->e_value.num)) break; continue; case SHORT: case USHORT: if (((uint16_t)u64_val & (uint16_t)(ep->e_value.num)) == (uint16_t)(ep->e_value.num)) break; continue; case LONG: case ULONG: if (((uint32_t)u64_val & (uint32_t)(ep->e_value.num)) == (uint32_t)(ep->e_value.num)) break; continue; case LLONG: case ULLONG: if ((u64_val & ep->e_value.num) == ep->e_value.num) break; continue; default: continue; } break; case NSET: switch (ep->e_type) { case BYTE: case UBYTE: if (((uint8_t)u64_val & (uint8_t)(ep->e_value.num)) != (uint8_t)(ep->e_value.num)) break; continue; case SHORT: case USHORT: if (((uint16_t)u64_val & (uint16_t)(ep->e_value.num)) != (uint16_t)(ep->e_value.num)) break; continue; case LONG: case ULONG: if (((uint32_t)u64_val & (uint32_t)(ep->e_value.num)) != (uint32_t)(ep->e_value.num)) break; continue; case LLONG: case ULLONG: if ((u64_val & ep->e_value.num) != ep->e_value.num) break; continue; default: continue; } break; case ANY: /* matches anything */ break; default: /* shouldn't occur; ignore it */ continue; } if (lev1) (void) putchar(' '); if (ep->e_opcode & SUB) { switch (ep->e_type) { case LLONG: #ifdef XPG4 if (ep->e_mask == 0) { (void) printf(ep->e_str, (int64_t)u64_val); break; } #endif /* XPG4 */ /*FALLTHROUGH*/ case ULLONG: (void) printf(ep->e_str, u64_val); break; case LONG: #ifdef XPG4 if (ep->e_mask == 0) { (void) printf(ep->e_str, (int32_t)u64_val); break; } #endif /* XPG4 */ /*FALLTHROUGH*/ case ULONG: (void) printf(ep->e_str, (uint32_t)u64_val); break; case SHORT: #ifdef XPG4 if (ep->e_mask == 0) { (void) printf(ep->e_str, (int16_t)u64_val); break; } #endif /* XPG4 */ /*FALLTHROUGH*/ case USHORT: (void) printf(ep->e_str, (uint16_t)u64_val); break; case BYTE: #ifdef XPG4 if (ep->e_mask == 0) { (void) printf(ep->e_str, (int8_t)u64_val); break; } #endif /* XPG4 */ /*FALLTHROUGH*/ case UBYTE: (void) printf(ep->e_str, (uint8_t)u64_val); break; case STR: /* * Note: Currently can't get type * STR here because we already * did a 'continue' out of the * loop earlier for case STR */ break; } } else (void) printf(ep->e_str); lev1 = 1; } result = lev1 ? (int)(1 + ep - mtab) : 0; return (result); } static void showstr(char *s, int width) { char c; while ((c = *s++) != '\0') if (c >= 040 && c < 0176) { (void) putchar(c); width--; } else { (void) putchar('\\'); switch (c) { case '\n': (void) putchar('n'); width -= 2; break; case '\r': (void) putchar('r'); width -= 2; break; case '\a': (void) putchar('a'); width -= 2; break; case '\b': (void) putchar('b'); width -= 2; break; case '\t': (void) putchar('t'); width -= 2; break; case '\f': (void) putchar('f'); width -= 2; break; case '\v': (void) putchar('v'); width -= 2; break; default: (void) printf("%.3o", c & 0377); width -= 4; break; } } while (width >= 0) { (void) putchar(' '); width--; }; } static char * type_to_name(Entry *ep) { static char buf[20]; char *s; switch (ep->e_type) { case BYTE: s = "byte"; break; case SHORT: s = "short"; break; case LONG: s = "long"; break; case LLONG: s = "llong"; break; case UBYTE: s = "ubyte"; break; case USHORT: s = "ushort"; break; case ULONG: s = "ulong"; break; case ULLONG: s = "ullong"; break; case STR: return ("string"); default: /* more of an emergency measure .. */ (void) sprintf(buf, "%d", ep->e_type); return (buf); } if (ep->e_mask) { (void) snprintf(buf, sizeof (buf), "%s&0x%llx", s, ep->e_mask); return (buf); } else return (s); } static char op_to_name(char op) { char c; switch (op & ~SUB) { case EQ: case STRC: c = '='; break; case GT: c = '>'; break; case LT: c = '<'; break; case ANY: c = 'x'; break; case AND: c = '&'; break; case NSET: c = '^'; break; default: c = '?'; break; } return (c); } /* * f_prtmtab - Prints out a header, then entries from both magic * tables, mtab1 and mtab2, if any exist. */ void f_prtmtab(void) { Entry *mtab; Entry *ep; int count; (void) printf("%-7s %-7s %-10s %-7s %-11s %s\n", "level", "off", "type", "opcode", "value", "string"); for (mtab = mtab1, count = 1; count <= 2; count++, mtab = mtab2) { if (mtab == (Entry *)NULL) { continue; } for (ep = mtab; ep->e_off != -1L; ep++) { (void) printf("%-7d %-7ld %-10s %-7c ", ep->e_level, ep->e_off, type_to_name(ep), op_to_name(ep->e_opcode)); if (ep->e_type == STR) { showstr(ep->e_value.str, 10); } else { /* numeric */ (void) printf("%-#11llo", ep->e_value.num); } (void) printf(" %s", ep->e_str); if (ep->e_opcode & SUB) (void) printf("\tsubst"); (void) printf("\n"); } } } intmax_t f_getmaxoffset(int first) { Entry *mtab; Entry *ep; intmax_t cur; intmax_t max = 0; if (first) { mtab = mtab1; } else { mtab = mtab2; } if (mtab == (Entry *)NULL) { return (0); } for (ep = mtab; ep->e_off != -1L; ep++) { cur = ep->e_off; switch (ep->e_type) { case STR: cur += strlen(ep->e_value.str); break; case BYTE: case UBYTE: cur += sizeof (uchar_t); break; case SHORT: case USHORT: cur += sizeof (uint16_t); break; case LONG: case ULONG: cur += sizeof (uint32_t); break; case LLONG: case ULLONG: cur += sizeof (uint64_t); break; } if (cur <= INT_MAX && cur > max) { max = cur; } } return (max); } #!/bin/sh # # 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 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # echo_file usr/src/common/elfcap/elfcap.h echo_file usr/src/common/elfcap/elfcap.c echo_file usr/src/common/sgsrtcid/sgsrtcid.h