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