diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/file/magicutils.c | |
download | illumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/file/magicutils.c')
-rw-r--r-- | usr/src/cmd/file/magicutils.c | 1130 |
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); +} |