1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27/*	  All Rights Reserved  	*/
28
29/*	Copyright (c) 1987, 1988 Microsoft Corporation	*/
30/*	  All Rights Reserved	*/
31
32#pragma ident	"%Z%%M%	%I%	%E% SMI"
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <ctype.h>
38#include <errno.h>
39#include <limits.h>
40#include <inttypes.h>
41#include <sys/types.h>
42#include <libintl.h>
43
44/*
45 *	Types
46 */
47
48#define	BYTE	1
49#define	SHORT	2
50#define	LONG	4
51#define	LLONG	8
52#define	UBYTE	16
53#define	USHORT	32
54#define	ULONG	64
55#define	ULLONG	128
56#define	STR	256
57
58/*
59 *	Opcodes
60 */
61
62#define	EQ	0
63#define	GT	1
64#define	LT	2
65#define	STRC	3	/* string compare */
66#define	ANY	4
67#define	AND	5
68#define	NSET	6	/* True if bit is not set */
69#define	SUB	64	/* or'ed in, SUBstitution string, for example */
70			/* %ld, %s, %lo mask: with bit 6 on, used to locate */
71			/* print formats */
72/*
73 *	Misc
74 */
75
76#define	BSZ	128
77#define	NENT	200
78
79/*
80 *	Structure of magic file entry
81 */
82
83struct	entry	{
84	char		e_level;	/* 0 or 1 */
85	off_t		e_off;		/* in bytes */
86	uint32_t	e_type;		/* BYTE, SHORT, STR, et al */
87	char		e_opcode;	/* EQ, GT, LT, ANY, AND, NSET */
88	uint64_t	e_mask;		/* if non-zero, mask value with this */
89	union	{
90		uint64_t	num;
91		char		*str;
92	}	e_value;
93	const char	*e_str;
94};
95
96/* Non-localized string giving name of command.  Defined in file.c */
97extern const char	*File;
98
99typedef	struct entry	Entry;
100
101static Entry	*mtab1;	/* 1st magic table, applied before default tests */
102
103	/*
104	 * 2nd magic table, includes default tests and magic entries
105	 * to be applied after default position-sensitive tests
106	 */
107static Entry	*mtab2;
108
109static Entry	*mend1;	/* one past last-allocated entry in mtab1 */
110static Entry	*mend2;	/* one past last-allocated entry in mtab2 */
111
112static Entry	*ep1;	/* current entry in mtab1 */
113static Entry	*ep2;	/* current entry in mtab2 */
114
115static char *
116getstr(char *p, char *file)
117{
118	char	*newstr;
119	char	*s;
120	long	val;
121	int	base;
122
123	newstr = (char *)malloc((strlen(p) + 1) * sizeof (char));
124	if (newstr == NULL) {
125		int err = errno;
126		(void) fprintf(stderr, gettext("%s: malloc failed: %s\n"),
127		    File, strerror(err));
128		return (NULL);
129	}
130
131	s = newstr;
132	while (*p != '\0') {
133		if (*p != '\\') {
134			*s++ = *p++;
135			continue;
136		}
137		p++;
138		if (*p == '\0')
139			break;
140		if (isdigit(*p)) {
141			if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) {
142				/* hex */
143				base = 16;
144			} else {
145				base = 8;
146			}
147			errno = 0;
148			val = strtol(p, &p, base);
149			if (val > UCHAR_MAX || val < 0 || errno != 0) {
150				(void) fprintf(stderr, gettext("%s: %s: magic "
151				    "table invalid string value\n"), File,
152				    file);
153				return (NULL);
154			}
155			*s++ = (char)val;
156		} else {
157			/* escape the character */
158			switch (*p) {
159			case 'n':
160				*s = '\n';
161				break;
162			case 'r':
163				*s = '\r';
164				break;
165			case 'a':
166				*s = '\a';
167				break;
168			case 'b':
169				*s = '\b';
170				break;
171			case 'f':
172				*s = '\f';
173				break;
174			case 't':
175				*s = '\t';
176				break;
177			case 'v':
178				*s = '\v';
179				break;
180			default:
181				*s = *p;
182				break;
183			}
184			p++;
185			s++;
186		}
187	}
188	*s = '\0';
189	return (newstr);
190}
191
192/*
193 * f_mkmtab - fills mtab array of magic table entries with
194 *	values from the file magfile.
195 *	May be called more than once if multiple magic
196 * 	files were specified.
197 *	Stores entries sequentially in one of two magic
198 *	tables: mtab1, if first = 1; mtab2 otherwise.
199 *
200 *	If -c option is specified, cflg is non-zero, and
201 *	f_mkmtab() reports on errors in the magic file.
202 *
203 *	Two magic tables may need to be created.  The first
204 *	one (mtab1) contains magic entries to be checked before
205 *	the programmatic default position-sensitive tests in
206 *	def_position_tests().
207 *	The second one (mtab2) should start with the default
208 *	/etc/magic file entries and is to be checked after
209 *	the programmatic default position-sensitive tests in
210 *	def_position_tests().  The parameter "first" would
211 *	be 1 for the former set of tables, 0 for the latter
212 *	set of magic tables.
213 *	No mtab2 should be created if file will not be
214 *	applying default tests; in that case, all magic table
215 *	entries should be in mtab1.
216 *
217 *	f_mkmtab returns 0 on success, -1 on error.  The calling
218 *	program is not expected to proceed after f_mkmtab()
219 *	returns an error.
220 */
221
222int
223f_mkmtab(char *magfile, int cflg, int first)
224{
225	Entry	*mtab;	/* generic magic table pointer */
226	Entry	*ep;	/* current magic table entry */
227	Entry	*mend;	/* one past last-allocated entry of mtab */
228	FILE	*fp;
229	int	lcnt = 0;
230	char	buf[BSZ];
231	size_t	tbsize;
232	size_t	oldsize;
233
234	if (first) {
235		mtab = mtab1;
236		mend = mend1;
237		ep = ep1;
238	} else {
239		mtab = mtab2;
240		mend = mend2;
241		ep = ep2;
242	}
243
244	/* mtab may have been allocated on a previous f_mkmtab call */
245	if (mtab == (Entry *)NULL) {
246		if ((mtab = calloc(sizeof (Entry), NENT)) == NULL) {
247			int err = errno;
248			(void) fprintf(stderr, gettext("%s: malloc "
249			    "failed: %s\n"), File, strerror(err));
250			return (-1);
251		}
252
253		ep = mtab;
254		mend = &mtab[NENT];
255	}
256
257	errno = 0;
258	if ((fp = fopen(magfile, "r")) == NULL) {
259		int err = errno;
260		(void) fprintf(stderr, gettext("%s: %s: cannot open magic "
261		    "file: %s\n"), File, magfile, err ? strerror(err) : "");
262		return (-1);
263	}
264	while (fgets(buf, BSZ, fp) != NULL) {
265		char	*p = buf;
266		char	*p2;
267		char	*p3;
268		char	opc;
269
270		/*
271		 * ensure we have one extra entry allocated
272		 * to mark end of the table, after the while loop
273		 */
274		if (ep >= (mend - 1)) {
275			oldsize = mend - mtab;
276			tbsize = (NENT + oldsize) * sizeof (Entry);
277			if ((mtab = realloc(mtab, tbsize)) == NULL) {
278				int err = errno;
279				(void) fprintf(stderr, gettext("%s: malloc "
280				    "failed: %s\n"), File, strerror(err));
281				return (-1);
282			} else {
283				(void) memset(mtab + oldsize, 0,
284				    sizeof (Entry) * NENT);
285				mend = &mtab[tbsize / sizeof (Entry)];
286				ep = &mtab[oldsize-1];
287			}
288		}
289
290		lcnt++;
291		if (*p == '\n' || *p == '#')
292			continue;
293
294
295			/* LEVEL */
296		if (*p == '>') {
297			ep->e_level = 1;
298			p++;
299		}
300			/* OFFSET */
301		p2 = strchr(p, '\t');
302		if (p2 == NULL) {
303			if (cflg)
304				(void) fprintf(stderr, gettext("%s: %s: format "
305				    "error, no tab after %s on line %d\n"),
306				    File, magfile, p, lcnt);
307			continue;
308		}
309		*p2++ = NULL;
310		ep->e_off = strtol((const char *)p, (char **)NULL, 0);
311		while (*p2 == '\t')
312			p2++;
313			/* TYPE */
314		p = p2;
315		p2 = strchr(p, '\t');
316		if (p2 == NULL) {
317			if (cflg)
318				(void) fprintf(stderr, gettext("%s: %s: format "
319				    "error, no tab after %s on line %d\n"),
320				    File, magfile, p, lcnt);
321			continue;
322		}
323		*p2++ = NULL;
324		p3 = strchr(p, '&');
325		if (p3 != NULL) {
326			*p3++ = '\0';
327			ep->e_mask = strtoull((const char *)p3, (char **)NULL,
328			    0);	/* returns 0 or ULLONG_MAX on error */
329		} else {
330			ep->e_mask = 0ULL;
331		}
332		switch (*p) {
333			case 'd':
334				if (*(p+1) == NULL) {
335					/* d */
336					ep->e_type = LONG;
337				} else if (*(p+2) == NULL) {	/* d? */
338					switch (*(p+1)) {
339						case 'C':
340						case '1':
341							/* dC, d1 */
342							ep->e_type = BYTE;
343							break;
344						case 'S':
345						case '2':
346							/* dS, d2 */
347							ep->e_type = SHORT;
348							break;
349						case 'I':
350						case 'L':
351						case '4':
352							/* dI, dL, d4 */
353							ep->e_type = LONG;
354							break;
355						case '8':
356							/* d8 */
357							ep->e_type = LLONG;
358							break;
359						default:
360							ep->e_type = LONG;
361							break;
362					}
363				}
364				break;
365			case 'l':
366				if (*(p+1) == 'l') {	/* llong */
367					ep->e_type = LLONG;
368				} else { 		/* long */
369					ep->e_type = LONG;
370				}
371				break;
372			case 's':
373				if (*(p+1) == 'h') {
374					/* short */
375					ep->e_type = SHORT;
376				} else {
377					/* s or string */
378					ep->e_type = STR;
379				}
380				break;
381			case 'u':
382				if (*(p+1) == NULL) {
383					/* u */
384					ep->e_type = ULONG;
385				} else if (*(p+2) == NULL) {	/* u? */
386					switch (*(p+1)) {
387						case 'C':
388						case '1':
389							/* uC, u1 */
390							ep->e_type = UBYTE;
391							break;
392						case 'S':
393						case '2':
394							/* uS, u2 */
395							ep->e_type = USHORT;
396							break;
397						case 'I':
398						case 'L':
399						case '4':
400							/* uI, uL, u4 */
401							ep->e_type = ULONG;
402							break;
403						case '8':
404							/* u8 */
405							ep->e_type = ULLONG;
406							break;
407						default:
408							ep->e_type = ULONG;
409							break;
410					}
411				} else { /* u?* */
412					switch (*(p+1)) {
413					case 'b':	/* ubyte */
414						ep->e_type = UBYTE;
415						break;
416					case 's':	/* ushort */
417						ep->e_type = USHORT;
418						break;
419					case 'l':
420						if (*(p+2) == 'l') {
421							/* ullong */
422							ep->e_type = ULLONG;
423						} else {
424							/* ulong */
425							ep->e_type = ULONG;
426						}
427						break;
428					default:
429						/* default, same as "u" */
430						ep->e_type = ULONG;
431						break;
432					}
433				}
434				break;
435			default:
436				/* retain (undocumented) default type */
437				ep->e_type = BYTE;
438				break;
439		}
440		if (ep->e_type == 0) {
441			ep->e_type = BYTE;	/* default */
442		}
443		while (*p2 == '\t')
444			p2++;
445			/* OP-VALUE */
446		p = p2;
447		p2 = strchr(p, '\t');
448		if (p2 == NULL) {
449			if (cflg)
450				(void) fprintf(stderr, gettext("%s: %s: format "
451				    "error, no tab after %s on line %d\n"),
452				    File, magfile, p, lcnt);
453			continue;
454		}
455		*p2++ = NULL;
456		if (ep->e_type != STR) {
457			opc = *p++;
458			switch (opc) {
459			case '=':
460				ep->e_opcode = EQ;
461				break;
462
463			case '>':
464				ep->e_opcode = GT;
465				break;
466
467			case '<':
468				ep->e_opcode = LT;
469				break;
470
471			case 'x':
472				ep->e_opcode = ANY;
473				break;
474
475			case '&':
476				ep->e_opcode = AND;
477				break;
478
479			case '^':
480				ep->e_opcode = NSET;
481				break;
482			default:	/* EQ (i.e. 0) is default	*/
483				p--;	/* since global ep->e_opcode=0	*/
484			}
485		}
486		if (ep->e_opcode != ANY) {
487			if (ep->e_type != STR) {
488				ep->e_value.num = strtoull((const char *)p,
489				    (char **)NULL, 0);
490			} else if ((ep->e_value.str =
491			    getstr(p, magfile)) == NULL) {
492				return (-1);
493			}
494		}
495		p2 += strspn(p2, "\t");
496			/* STRING */
497		if ((ep->e_str = strdup(p2)) == NULL) {
498			int err = errno;
499			(void) fprintf(stderr, gettext("%s: malloc "
500			    "failed: %s\n"), File, strerror(err));
501			return (-1);
502		} else {
503			if ((p = strchr(ep->e_str, '\n')) != NULL)
504				*p = '\0';
505			if (strchr(ep->e_str, '%') != NULL)
506				ep->e_opcode |= SUB;
507		}
508		ep++;
509	}	/* end while (fgets) */
510
511	ep->e_off = -1L;	/* mark end of table */
512	if (first) {
513		mtab1 = mtab;
514		mend1 = mend;
515		ep1 = ep;
516	} else {
517		mtab2 = mtab;
518		mend2 = mend;
519		ep2 = ep;
520	}
521	if (fclose(fp) != 0) {
522		int err = errno;
523		(void) fprintf(stderr, gettext("%s: fclose failed: %s\n"),
524		    File, strerror(err));
525		return (-1);
526	}
527	return (0);
528}
529
530/*
531 * Check for Magic Table entries in the file.
532 *
533 * Since there may be two sets of magic tables, first = 1
534 * for the first magic table (mtab1) and 0 for the second magic
535 * table (mtab2).
536 */
537int
538f_ckmtab(char *buf, int bufsize, int first)
539{
540	int 		result;
541	Entry		*mtab;
542	Entry		*ep;
543	char		*p;
544	int		lev1 = 0;
545
546	uint16_t	u16_val;
547	uint32_t	u32_val;
548	uint64_t	u64_val;
549
550	if (first) {
551		mtab = mtab1;
552	} else {
553		mtab = mtab2;
554	}
555
556	if (mtab == (Entry *)NULL) {
557		return (0);	/* no magic file tests in this table */
558	}
559
560	for (ep = mtab; ep->e_off != -1L; ep++) {  /* -1 offset marks end of */
561		if (lev1) {			/* valid magic file entries */
562			if (ep->e_level != 1)
563				break;
564		} else if (ep->e_level == 1) {
565			continue;
566		}
567		if (ep->e_off > (off_t)bufsize)
568			continue;
569		p = &buf[ep->e_off];
570		switch (ep->e_type) {
571		case STR:
572		{
573			if (strncmp(p, ep->e_value.str,
574			    strlen(ep->e_value.str)))
575				continue;
576			if (lev1) {
577				(void) putchar(' ');
578			}
579			if (ep->e_opcode & SUB)
580				(void) printf(ep->e_str,
581				    ep->e_value.str);
582			else
583				(void) printf(ep->e_str);
584			lev1 = 1;
585			continue;
586			/*
587			 * We've matched the string and printed the message;
588			 * no STR processing occurs beyond this point.
589			 */
590		}
591
592		case BYTE:
593		case UBYTE:
594			u64_val = (uint64_t)(uint8_t)(*p);
595			break;
596
597		case SHORT:
598		case USHORT:
599			(void) memcpy(&u16_val, p, sizeof (uint16_t));
600			u64_val = (uint64_t)u16_val;
601			break;
602
603		case LONG:
604		case ULONG:
605			(void) memcpy(&u32_val, p, sizeof (uint32_t));
606			u64_val = (uint64_t)u32_val;
607			break;
608
609		case LLONG:
610		case ULLONG:
611			(void) memcpy(&(u64_val), p, sizeof (uint64_t));
612			break;
613
614		}
615
616		if (ep->e_mask) {
617			u64_val &= ep->e_mask;
618		}
619
620		/*
621		 * Compare the values according to the size and sign
622		 * of the type.  For =, &, and ^ operators, the sign
623		 * does not have any effect, so these are always compared
624		 * unsigned.  Only for < and > operators is the
625		 * sign significant.
626		 * If the file value was masked, the compare should
627		 * be unsigned.
628		 */
629		switch (ep->e_opcode & ~SUB) {
630		case EQ:
631			switch (ep->e_type) {
632			case BYTE:
633			case UBYTE:
634				if ((uint8_t)u64_val !=
635				    (uint8_t)(ep->e_value.num))
636					continue;
637				break;
638			case SHORT:
639			case USHORT:
640				if ((uint16_t)u64_val !=
641				    (uint16_t)(ep->e_value.num))
642					continue;
643				break;
644			case LONG:
645			case ULONG:
646				if ((uint32_t)u64_val !=
647				    (uint32_t)(ep->e_value.num))
648					continue;
649				break;
650			case LLONG:
651			case ULLONG:
652				if (u64_val != ep->e_value.num)
653					continue;
654				break;
655			default:
656				continue;
657			}
658			break;
659		case GT:
660			switch (ep->e_type) {
661			case BYTE:
662				if (ep->e_mask == 0) {
663					if ((int8_t)u64_val <=
664					    (int8_t)(ep->e_value.num))
665						continue;
666					break;
667				}
668				/*FALLTHROUGH*/
669			case UBYTE:
670				if ((uint8_t)u64_val <=
671				    (uint8_t)(ep->e_value.num))
672					continue;
673				break;
674			case SHORT:
675				if (ep->e_mask == 0) {
676					if ((int16_t)u64_val <=
677					    (int16_t)(ep->e_value.num))
678						continue;
679					break;
680				}
681				/*FALLTHROUGH*/
682			case USHORT:
683				if ((uint16_t)u64_val <=
684				    (uint16_t)(ep->e_value.num))
685					continue;
686				break;
687			case LONG:
688				if (ep->e_mask == 0) {
689					if ((int32_t)u64_val <=
690					    (int32_t)(ep->e_value.num))
691						continue;
692					break;
693				}
694				/*FALLTHROUGH*/
695			case ULONG:
696				if ((uint32_t)u64_val <=
697				    (uint32_t)(ep->e_value.num))
698					continue;
699				break;
700			case LLONG:
701				if (ep->e_mask == 0) {
702					if ((int64_t)u64_val <=
703					    (int64_t)(ep->e_value.num))
704						continue;
705					break;
706				}
707				/*FALLTHROUGH*/
708			case ULLONG:
709				if (u64_val <= ep->e_value.num)
710					continue;
711				break;
712			default:
713				continue;
714			}
715			break;
716		case LT:
717			switch (ep->e_type) {
718			case BYTE:
719				if (ep->e_mask == 0) {
720					if ((int8_t)u64_val >=
721					    (int8_t)(ep->e_value.num))
722						continue;
723					break;
724				}
725				/*FALLTHROUGH*/
726			case UBYTE:
727				if ((uint8_t)u64_val >=
728				    (uint8_t)(ep->e_value.num))
729					continue;
730				break;
731			case SHORT:
732				if (ep->e_mask == 0) {
733					if ((int16_t)u64_val >=
734					    (int16_t)(ep->e_value.num))
735						continue;
736					break;
737				}
738				/*FALLTHROUGH*/
739			case USHORT:
740				if ((uint16_t)u64_val >=
741				    (uint16_t)(ep->e_value.num))
742					continue;
743				break;
744			case LONG:
745				if (ep->e_mask == 0) {
746					if ((int32_t)u64_val >=
747					    (int32_t)(ep->e_value.num))
748						continue;
749					break;
750				}
751				/*FALLTHROUGH*/
752			case ULONG:
753				if ((uint32_t)u64_val >=
754				    (uint32_t)(ep->e_value.num))
755					continue;
756				break;
757			case LLONG:
758				if (ep->e_mask == 0) {
759					if ((int64_t)u64_val >=
760					    (int64_t)(ep->e_value.num))
761						continue;
762					break;
763				}
764				/*FALLTHROUGH*/
765			case ULLONG:
766				if (u64_val >= ep->e_value.num)
767					continue;
768				break;
769			default:
770				continue;
771			}
772			break;
773		case AND:
774			switch (ep->e_type) {
775			case BYTE:
776			case UBYTE:
777				if (((uint8_t)u64_val &
778				    (uint8_t)(ep->e_value.num)) ==
779				    (uint8_t)(ep->e_value.num))
780					break;
781				continue;
782			case SHORT:
783			case USHORT:
784				if (((uint16_t)u64_val &
785				    (uint16_t)(ep->e_value.num)) ==
786				    (uint16_t)(ep->e_value.num))
787					break;
788				continue;
789			case LONG:
790			case ULONG:
791				if (((uint32_t)u64_val &
792				    (uint32_t)(ep->e_value.num)) ==
793				    (uint32_t)(ep->e_value.num))
794					break;
795				continue;
796			case LLONG:
797			case ULLONG:
798				if ((u64_val & ep->e_value.num) ==
799				    ep->e_value.num)
800					break;
801				continue;
802			default:
803				continue;
804			}
805			break;
806		case NSET:
807			switch (ep->e_type) {
808			case BYTE:
809			case UBYTE:
810				if (((uint8_t)u64_val &
811				    (uint8_t)(ep->e_value.num)) !=
812				    (uint8_t)(ep->e_value.num))
813					break;
814				continue;
815			case SHORT:
816			case USHORT:
817				if (((uint16_t)u64_val &
818				    (uint16_t)(ep->e_value.num)) !=
819				    (uint16_t)(ep->e_value.num))
820					break;
821				continue;
822			case LONG:
823			case ULONG:
824				if (((uint32_t)u64_val &
825				    (uint32_t)(ep->e_value.num)) !=
826				    (uint32_t)(ep->e_value.num))
827					break;
828				continue;
829			case LLONG:
830			case ULLONG:
831				if ((u64_val & ep->e_value.num) !=
832				    ep->e_value.num)
833					break;
834				continue;
835			default:
836				continue;
837			}
838			break;
839		case ANY:	/* matches anything */
840			break;
841		default:	/* shouldn't occur; ignore it */
842			continue;
843		}
844		if (lev1)
845			(void) putchar(' ');
846		if (ep->e_opcode & SUB) {
847			switch (ep->e_type) {
848			case LLONG:
849#ifdef XPG4
850				if (ep->e_mask == 0) {
851					(void) printf(ep->e_str,
852						(int64_t)u64_val);
853					break;
854				}
855#endif	/* XPG4 */
856				/*FALLTHROUGH*/
857			case ULLONG:
858				(void) printf(ep->e_str, u64_val);
859				break;
860			case LONG:
861#ifdef XPG4
862				if (ep->e_mask == 0) {
863					(void) printf(ep->e_str,
864						(int32_t)u64_val);
865					break;
866				}
867#endif	/* XPG4 */
868				/*FALLTHROUGH*/
869			case ULONG:
870				(void) printf(ep->e_str,
871				    (uint32_t)u64_val);
872				break;
873			case SHORT:
874#ifdef XPG4
875				if (ep->e_mask == 0) {
876					(void) printf(ep->e_str,
877						(int16_t)u64_val);
878					break;
879				}
880#endif	/* XPG4 */
881				/*FALLTHROUGH*/
882			case USHORT:
883				(void) printf(ep->e_str,
884				    (uint16_t)u64_val);
885				break;
886			case BYTE:
887#ifdef XPG4
888				if (ep->e_mask == 0) {
889					(void) printf(ep->e_str,
890						(int8_t)u64_val);
891					break;
892				}
893#endif	/* XPG4 */
894				/*FALLTHROUGH*/
895			case UBYTE:
896				(void) printf(ep->e_str,
897				    (uint8_t)u64_val);
898				break;
899			case STR:
900				/*
901				 * Note: Currently can't get type
902				 * STR here because we already
903				 * did a 'continue' out of the
904				 * loop earlier for case STR
905				 */
906				break;
907			}
908		} else
909			(void) printf(ep->e_str);
910		lev1 = 1;
911	}
912	result = lev1 ? (int)(1 + ep - mtab) : 0;
913
914	return (result);
915}
916
917static void
918showstr(char *s, int width)
919{
920	char c;
921
922	while ((c = *s++) != '\0')
923		if (c >= 040 && c < 0176) {
924			(void) putchar(c);
925			width--;
926		} else {
927			(void) putchar('\\');
928			switch (c) {
929
930			case '\n':
931				(void) putchar('n');
932				width -= 2;
933				break;
934
935			case '\r':
936				(void) putchar('r');
937				width -= 2;
938				break;
939
940			case '\a':
941				(void) putchar('a');
942				width -= 2;
943				break;
944
945			case '\b':
946				(void) putchar('b');
947				width -= 2;
948				break;
949
950			case '\t':
951				(void) putchar('t');
952				width -= 2;
953				break;
954
955			case '\f':
956				(void) putchar('f');
957				width -= 2;
958				break;
959
960			case '\v':
961				(void) putchar('v');
962				width -= 2;
963				break;
964
965			default:
966				(void) printf("%.3o", c & 0377);
967				width -= 4;
968				break;
969			}
970		}
971	while (width >= 0) {
972		(void) putchar(' ');
973		width--;
974	};
975}
976
977static char *
978type_to_name(Entry *ep)
979{
980	static char buf[20];
981	char	*s;
982
983	switch (ep->e_type) {
984	case BYTE:
985		s = "byte";
986		break;
987	case SHORT:
988		s = "short";
989		break;
990	case LONG:
991		s = "long";
992		break;
993	case LLONG:
994		s = "llong";
995		break;
996	case UBYTE:
997		s = "ubyte";
998		break;
999	case USHORT:
1000		s = "ushort";
1001		break;
1002	case ULONG:
1003		s = "ulong";
1004		break;
1005	case ULLONG:
1006		s = "ullong";
1007		break;
1008	case STR:
1009		return ("string");
1010	default:
1011		/* more of an emergency measure .. */
1012		(void) sprintf(buf, "%d", ep->e_type);
1013		return (buf);
1014	}
1015	if (ep->e_mask) {
1016		(void) snprintf(buf, sizeof (buf), "%s&0x%llx", s, ep->e_mask);
1017		return (buf);
1018	} else
1019		return (s);
1020}
1021
1022static char
1023op_to_name(char op)
1024{
1025	char c;
1026
1027	switch (op & ~SUB) {
1028
1029	case EQ:
1030	case STRC:
1031		c = '=';
1032		break;
1033
1034	case GT:
1035		c = '>';
1036		break;
1037
1038	case LT:
1039		c = '<';
1040		break;
1041
1042	case ANY:
1043		c = 'x';
1044		break;
1045
1046	case AND:
1047		c = '&';
1048		break;
1049
1050	case NSET:
1051		c = '^';
1052		break;
1053
1054	default:
1055		c = '?';
1056		break;
1057	}
1058
1059	return (c);
1060}
1061
1062/*
1063 * f_prtmtab - Prints out a header, then entries from both magic
1064 *	tables, mtab1 and mtab2, if any exist.
1065 */
1066void
1067f_prtmtab(void)
1068{
1069	Entry	*mtab;
1070	Entry	*ep;
1071	int	count;
1072
1073	(void) printf("%-7s %-7s %-10s %-7s %-11s %s\n",
1074		"level", "off", "type", "opcode", "value", "string");
1075	for (mtab = mtab1, count = 1; count <= 2; count++, mtab = mtab2) {
1076		if (mtab == (Entry *)NULL) {
1077			continue;
1078		}
1079		for (ep = mtab; ep->e_off != -1L; ep++) {
1080			(void) printf("%-7d %-7ld %-10s %-7c ",
1081			    ep->e_level,
1082			    ep->e_off, type_to_name(ep),
1083			    op_to_name(ep->e_opcode));
1084			if (ep->e_type == STR) {
1085				showstr(ep->e_value.str, 10);
1086			} else {	/* numeric */
1087				(void) printf("%-#11llo", ep->e_value.num);
1088			}
1089			(void) printf(" %s", ep->e_str);
1090			if (ep->e_opcode & SUB)
1091				(void) printf("\tsubst");
1092			(void) printf("\n");
1093		}
1094	}
1095}
1096
1097intmax_t
1098f_getmaxoffset(int first)
1099{
1100	Entry *mtab;
1101	Entry *ep;
1102	intmax_t cur;
1103	intmax_t max = 0;
1104
1105	if (first) {
1106		mtab = mtab1;
1107	} else {
1108		mtab = mtab2;
1109	}
1110	if (mtab == (Entry *)NULL) {
1111		return (0);
1112	}
1113	for (ep = mtab; ep->e_off != -1L; ep++) {
1114		cur = ep->e_off;
1115		switch (ep->e_type) {
1116		case STR:
1117			cur += strlen(ep->e_value.str);
1118			break;
1119		case BYTE:
1120		case UBYTE:
1121			cur += sizeof (uchar_t);
1122			break;
1123		case SHORT:
1124		case USHORT:
1125			cur += sizeof (uint16_t);
1126			break;
1127		case LONG:
1128		case ULONG:
1129			cur += sizeof (uint32_t);
1130			break;
1131		case LLONG:
1132		case ULLONG:
1133			cur += sizeof (uint64_t);
1134			break;
1135		}
1136		if (cur <= INT_MAX && cur > max) {
1137			max = cur;
1138		}
1139	}
1140
1141	return (max);
1142}
1143