summaryrefslogtreecommitdiff
path: root/usr/src/cmd/file/magicutils.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/file/magicutils.c
downloadillumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/file/magicutils.c')
-rw-r--r--usr/src/cmd/file/magicutils.c1130
1 files changed, 1130 insertions, 0 deletions
diff --git a/usr/src/cmd/file/magicutils.c b/usr/src/cmd/file/magicutils.c
new file mode 100644
index 0000000000..b6a2c7d3f0
--- /dev/null
+++ b/usr/src/cmd/file/magicutils.c
@@ -0,0 +1,1130 @@
+/*
+ * 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 2004 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 */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <libintl.h>
+
+/*
+ * 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;
+};
+
+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 *newstr;
+ char *s;
+ long val;
+ int base;
+
+ newstr = (char *)malloc((strlen(p) + 1) * sizeof (char));
+ if (newstr == NULL) {
+ perror(gettext("magic table string allocation"));
+ 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) {
+ perror(gettext("magic table invalid "
+ "string value"));
+ 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) {
+ mtab = (Entry *) calloc(sizeof (Entry), NENT);
+ if (mtab == (Entry *)NULL) {
+ (void) fprintf(stderr,
+ gettext("no memory for magic table\n"));
+ return (-1);
+ }
+
+ ep = mtab;
+ mend = &mtab[NENT];
+ }
+
+ fp = fopen(magfile, "r");
+ if (fp == NULL) {
+ (void) fprintf(stderr,
+ gettext("cannot open magic file <%s>.\n"),
+ magfile);
+ 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) {
+ perror(gettext("magic table overflow"));
+ 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("fmt error, no tab after %s on "
+ "line %d of %s\n"), p, lcnt, magfile);
+ continue;
+ }
+ *p2++ = NULL;
+ 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("fmt error, no tab after %s on "
+ "line %d of %s\n"), p, lcnt, magfile);
+ continue;
+ }
+ *p2++ = NULL;
+ 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) == NULL) {
+ /* d */
+ ep->e_type = LONG;
+ } else if (*(p+2) == NULL) { /* 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) == NULL) {
+ /* u */
+ ep->e_type = ULONG;
+ } else if (*(p+2) == NULL) { /* 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("fmt error, no tab after %s on "
+ "line %d of %s\n"), p, lcnt, magfile);
+ continue;
+ }
+ *p2++ = NULL;
+ 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)) == NULL) {
+ return (-1);
+ }
+ }
+ p2 += strspn(p2, "\t");
+ /* STRING */
+ if ((ep->e_str = strdup(p2)) == NULL) {
+ perror(gettext("magic table message allocation"));
+ 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) == EOF) {
+ perror(magfile);
+ 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);
+}