#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>
#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
#define EQ 0
#define GT 1
#define LT 2
#define STRC 3
#define ANY 4
#define AND 5
#define NSET 6
#define SUB 64
#define BSZ 128
#define NENT 200
struct entry {
char e_level;
off_t e_off;
uint32_t e_type;
char e_opcode;
uint64_t e_mask;
union {
uint64_t num;
char *str;
} e_value;
const char *e_str;
};
extern const char *File;
typedef struct entry Entry;
static Entry *mtab1;
static Entry *mtab2;
static Entry *mend1;
static Entry *mend2;
static Entry *ep1;
static Entry *ep2;
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')) {
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 {
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);
}
int
f_mkmtab(char *magfile, int cflg, int first)
{
Entry *mtab;
Entry *ep;
Entry *mend;
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;
}
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;
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;
if (*p == '>') {
ep->e_level = 1;
p++;
}
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++;
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);
} else {
ep->e_mask = 0ULL;
}
switch (*p) {
case 'd':
if (*(p+1) == '\0') {
ep->e_type = LONG;
} else if (*(p+2) == '\0') {
switch (*(p+1)) {
case 'C':
case '1':
ep->e_type = BYTE;
break;
case 'S':
case '2':
ep->e_type = SHORT;
break;
case 'I':
case 'L':
case '4':
ep->e_type = LONG;
break;
case '8':
ep->e_type = LLONG;
break;
default:
ep->e_type = LONG;
break;
}
}
break;
case 'l':
if (*(p+1) == 'l') {
ep->e_type = LLONG;
} else {
ep->e_type = LONG;
}
break;
case 's':
if (*(p+1) == 'h') {
ep->e_type = SHORT;
} else {
ep->e_type = STR;
}
break;
case 'u':
if (*(p+1) == '\0') {
ep->e_type = ULONG;
} else if (*(p+2) == '\0') {
switch (*(p+1)) {
case 'C':
case '1':
ep->e_type = UBYTE;
break;
case 'S':
case '2':
ep->e_type = USHORT;
break;
case 'I':
case 'L':
case '4':
ep->e_type = ULONG;
break;
case '8':
ep->e_type = ULLONG;
break;
default:
ep->e_type = ULONG;
break;
}
} else {
switch (*(p+1)) {
case 'b':
ep->e_type = UBYTE;
break;
case 's':
ep->e_type = USHORT;
break;
case 'l':
if (*(p+2) == 'l') {
ep->e_type = ULLONG;
} else {
ep->e_type = ULONG;
}
break;
default:
ep->e_type = ULONG;
break;
}
}
break;
default:
ep->e_type = BYTE;
break;
}
if (ep->e_type == 0) {
ep->e_type = BYTE;
}
while (*p2 == '\t')
p2++;
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:
p--;
}
}
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");
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++;
}
ep->e_off = -1L;
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);
}
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);
}
for (ep = mtab; ep->e_off != -1L; ep++) {
if (lev1) {
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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:
break;
default:
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
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
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
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
case UBYTE:
(void) printf(ep->e_str,
(uint8_t)u64_val);
break;
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:
(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);
}
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 {
(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);
}