xref: /onnv-gate/usr/src/cmd/fm/fmdump/common/fmdump.c (revision 10928:eb060666c73f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55609Scy152378  * Common Development and Distribution License (the "License").
65609Scy152378  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
228740SSean.Ye@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <alloca.h>
270Sstevel@tonic-gate #include <unistd.h>
280Sstevel@tonic-gate #include <limits.h>
290Sstevel@tonic-gate #include <strings.h>
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <stdarg.h>
320Sstevel@tonic-gate #include <stdio.h>
330Sstevel@tonic-gate #include <errno.h>
340Sstevel@tonic-gate #include <time.h>
350Sstevel@tonic-gate #include <ctype.h>
366640Scth #include <regex.h>
378740SSean.Ye@Sun.COM #include <dirent.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <fmdump.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #define	FMDUMP_EXIT_SUCCESS	0
420Sstevel@tonic-gate #define	FMDUMP_EXIT_FATAL	1
430Sstevel@tonic-gate #define	FMDUMP_EXIT_USAGE	2
440Sstevel@tonic-gate #define	FMDUMP_EXIT_ERROR	3
450Sstevel@tonic-gate 
460Sstevel@tonic-gate const char *g_pname;
470Sstevel@tonic-gate ulong_t g_errs;
480Sstevel@tonic-gate ulong_t g_recs;
490Sstevel@tonic-gate char *g_root;
509501SRobert.Johnston@Sun.COM 
511414Scindi struct topo_hdl *g_thp;
529501SRobert.Johnston@Sun.COM fmd_msg_hdl_t *g_msg;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /*PRINTFLIKE2*/
550Sstevel@tonic-gate void
560Sstevel@tonic-gate fmdump_printf(FILE *fp, const char *format, ...)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate 	va_list ap;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	va_start(ap, format);
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 	if (vfprintf(fp, format, ap) < 0) {
630Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: failed to print record: %s\n",
640Sstevel@tonic-gate 		    g_pname, strerror(errno));
650Sstevel@tonic-gate 		g_errs++;
660Sstevel@tonic-gate 	}
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	va_end(ap);
690Sstevel@tonic-gate }
700Sstevel@tonic-gate 
710Sstevel@tonic-gate void
720Sstevel@tonic-gate fmdump_vwarn(const char *format, va_list ap)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	int err = errno;
750Sstevel@tonic-gate 
760Sstevel@tonic-gate 	(void) fprintf(stderr, "%s: warning: ", g_pname);
770Sstevel@tonic-gate 	(void) vfprintf(stderr, format, ap);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	if (strchr(format, '\n') == NULL)
800Sstevel@tonic-gate 		(void) fprintf(stderr, ": %s\n", strerror(err));
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	g_errs++;
830Sstevel@tonic-gate }
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*PRINTFLIKE1*/
860Sstevel@tonic-gate void
870Sstevel@tonic-gate fmdump_warn(const char *format, ...)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate 	va_list ap;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate 	va_start(ap, format);
920Sstevel@tonic-gate 	fmdump_vwarn(format, ap);
930Sstevel@tonic-gate 	va_end(ap);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
960Sstevel@tonic-gate char *
970Sstevel@tonic-gate fmdump_date(char *buf, size_t len, const fmd_log_record_t *rp)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate 	if (rp->rec_sec > LONG_MAX) {
1000Sstevel@tonic-gate 		fmdump_warn("record time is too large for 32-bit utility\n");
1010Sstevel@tonic-gate 		(void) snprintf(buf, len, "0x%llx", rp->rec_sec);
1020Sstevel@tonic-gate 	} else {
1030Sstevel@tonic-gate 		time_t tod = (time_t)rp->rec_sec;
1045609Scy152378 		time_t now = time(NULL);
1055609Scy152378 		if (tod > now+60 ||
1065609Scy152378 		    tod < now - 6L*30L*24L*60L*60L) { /* 6 months ago */
1075609Scy152378 			(void) strftime(buf, len, "%b %d %Y %T",
1085609Scy152378 			    localtime(&tod));
1095609Scy152378 		} else {
1105609Scy152378 			size_t sz;
1115609Scy152378 			sz = strftime(buf, len, "%b %d %T", localtime(&tod));
1125609Scy152378 			(void) snprintf(buf + sz, len - sz, ".%4.4llu",
1135609Scy152378 			    rp->rec_nsec / (NANOSEC / 10000));
1145609Scy152378 		}
1150Sstevel@tonic-gate 	}
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	return (buf);
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate char *
1210Sstevel@tonic-gate fmdump_year(char *buf, size_t len, const fmd_log_record_t *rp)
1220Sstevel@tonic-gate {
1230Sstevel@tonic-gate #ifdef _ILP32
1240Sstevel@tonic-gate 	if (rp->rec_sec > LONG_MAX) {
1250Sstevel@tonic-gate 		fmdump_warn("record time is too large for 32-bit utility\n");
1260Sstevel@tonic-gate 		(void) snprintf(buf, len, "0x%llx", rp->rec_sec);
1270Sstevel@tonic-gate 	} else {
1280Sstevel@tonic-gate #endif
1290Sstevel@tonic-gate 		time_t tod = (time_t)rp->rec_sec;
1300Sstevel@tonic-gate 		(void) strftime(buf, len, "%b %d %Y %T", localtime(&tod));
1310Sstevel@tonic-gate #ifdef _ILP32
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate #endif
1340Sstevel@tonic-gate 	return (buf);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate static int
1380Sstevel@tonic-gate usage(FILE *fp)
1390Sstevel@tonic-gate {
1409501SRobert.Johnston@Sun.COM 	(void) fprintf(fp, "Usage: %s [-efmvV] [-c class] [-R root] [-t time] "
1416640Scth 	    "[-T time] [-u uuid]\n\t\t[-n name[.name]*[=value]] [file]\n",
1426640Scth 	    g_pname);
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	(void) fprintf(fp,
1450Sstevel@tonic-gate 	    "\t-c  select events that match the specified class\n"
1460Sstevel@tonic-gate 	    "\t-e  display error log content instead of fault log content\n"
1470Sstevel@tonic-gate 	    "\t-f  follow growth of log file by waiting for additional data\n"
1489501SRobert.Johnston@Sun.COM 	    "\t-m  display human-readable messages for the fault log\n"
1490Sstevel@tonic-gate 	    "\t-R  set root directory for pathname expansions\n"
1500Sstevel@tonic-gate 	    "\t-t  select events that occurred after the specified time\n"
1510Sstevel@tonic-gate 	    "\t-T  select events that occurred before the specified time\n"
1520Sstevel@tonic-gate 	    "\t-u  select events that match the specified uuid\n"
1536640Scth 	    "\t-n  select events containing named nvpair "
1546640Scth 	    "(with matching value)\n"
1550Sstevel@tonic-gate 	    "\t-v  set verbose mode: display additional event detail\n"
1560Sstevel@tonic-gate 	    "\t-V  set very verbose mode: display complete event contents\n");
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	return (FMDUMP_EXIT_USAGE);
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate /*ARGSUSED*/
1620Sstevel@tonic-gate static int
1630Sstevel@tonic-gate error(fmd_log_t *lp, void *private)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	fmdump_warn("skipping record: %s\n",
1660Sstevel@tonic-gate 	    fmd_log_errmsg(lp, fmd_log_errno(lp)));
1670Sstevel@tonic-gate 	return (0);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate  * Yet another disgusting argument parsing function (TM).  We attempt to parse
1720Sstevel@tonic-gate  * a time argument in a variety of strptime(3C) formats, in which case it is
1730Sstevel@tonic-gate  * interpreted as a local time and is converted to a timeval using mktime(3C).
1740Sstevel@tonic-gate  * If those formats fail, we look to see if the time is a decimal integer
1750Sstevel@tonic-gate  * followed by one of our magic suffixes, in which case the time is interpreted
1760Sstevel@tonic-gate  * as a time delta *before* the current time-of-day (i.e. "1h" = "1 hour ago").
1770Sstevel@tonic-gate  */
1780Sstevel@tonic-gate static struct timeval *
1790Sstevel@tonic-gate gettimeopt(const char *arg)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	const struct {
1820Sstevel@tonic-gate 		const char *name;
1830Sstevel@tonic-gate 		hrtime_t mul;
1840Sstevel@tonic-gate 	} suffix[] = {
1856640Scth 		{ "ns",		NANOSEC / NANOSEC },
1860Sstevel@tonic-gate 		{ "nsec",	NANOSEC / NANOSEC },
1870Sstevel@tonic-gate 		{ "us",		NANOSEC / MICROSEC },
1880Sstevel@tonic-gate 		{ "usec",	NANOSEC / MICROSEC },
1890Sstevel@tonic-gate 		{ "ms",		NANOSEC / MILLISEC },
1900Sstevel@tonic-gate 		{ "msec",	NANOSEC / MILLISEC },
1910Sstevel@tonic-gate 		{ "s",		NANOSEC / SEC },
1920Sstevel@tonic-gate 		{ "sec",	NANOSEC / SEC },
1930Sstevel@tonic-gate 		{ "m",		NANOSEC * (hrtime_t)60 },
1940Sstevel@tonic-gate 		{ "min",	NANOSEC * (hrtime_t)60 },
1950Sstevel@tonic-gate 		{ "h",		NANOSEC * (hrtime_t)(60 * 60) },
1960Sstevel@tonic-gate 		{ "hour",	NANOSEC * (hrtime_t)(60 * 60) },
1970Sstevel@tonic-gate 		{ "d",		NANOSEC * (hrtime_t)(24 * 60 * 60) },
1980Sstevel@tonic-gate 		{ "day",	NANOSEC * (hrtime_t)(24 * 60 * 60) },
1990Sstevel@tonic-gate 		{ NULL }
2000Sstevel@tonic-gate 	};
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	struct timeval *tvp = malloc(sizeof (struct timeval));
2030Sstevel@tonic-gate 	struct timeval tod;
2040Sstevel@tonic-gate 	struct tm tm;
2050Sstevel@tonic-gate 	char *p;
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	if (tvp == NULL) {
2080Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: failed to allocate memory: %s\n",
2090Sstevel@tonic-gate 		    g_pname, strerror(errno));
2100Sstevel@tonic-gate 		exit(FMDUMP_EXIT_FATAL);
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	if (gettimeofday(&tod, NULL) != 0) {
2140Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: failed to get tod: %s\n",
2150Sstevel@tonic-gate 		    g_pname, strerror(errno));
2160Sstevel@tonic-gate 		exit(FMDUMP_EXIT_FATAL);
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * First try a variety of strptime() calls.  If these all fail, we'll
2210Sstevel@tonic-gate 	 * try parsing an integer followed by one of our suffix[] strings.
2220Sstevel@tonic-gate 	 * NOTE: any form using %y must appear *before* the equivalent %Y form;
2230Sstevel@tonic-gate 	 * otherwise %Y will accept the two year digits but infer century zero.
2240Sstevel@tonic-gate 	 * Any form ending in %y must additionally check isdigit(*p) to ensure
2250Sstevel@tonic-gate 	 * that it does not inadvertently match 2 digits of a 4-digit year.
2260Sstevel@tonic-gate 	 *
2270Sstevel@tonic-gate 	 * Beware: Any strptime() sequence containing consecutive %x sequences
2280Sstevel@tonic-gate 	 * may fall victim to SCCS expanding it as a keyword!  If this happens
2290Sstevel@tonic-gate 	 * we use separate string constant that ANSI C will concatenate.
2300Sstevel@tonic-gate 	 */
2310Sstevel@tonic-gate 	if ((p = strptime(arg, "%m/%d/%y" "%t" "%H:%M:%S", &tm)) == NULL &&
2320Sstevel@tonic-gate 	    (p = strptime(arg, "%m/%d/%Y" "%t" "%H:%M:%S", &tm)) == NULL &&
2330Sstevel@tonic-gate 	    (p = strptime(arg, "%m/%d/%y" "%t" "%H:%M", &tm)) == NULL &&
2340Sstevel@tonic-gate 	    (p = strptime(arg, "%m/%d/%Y" "%t" "%H:%M", &tm)) == NULL &&
2350Sstevel@tonic-gate 	    ((p = strptime(arg, "%m/%d/%y", &tm)) == NULL || isdigit(*p)) &&
2360Sstevel@tonic-gate 	    (p = strptime(arg, "%m/%d/%Y", &tm)) == NULL &&
2370Sstevel@tonic-gate 	    (p = strptime(arg, "%y-%m-%dT%H:%M:%S", &tm)) == NULL &&
2380Sstevel@tonic-gate 	    (p = strptime(arg, "%Y-%m-%dT%H:%M:%S", &tm)) == NULL &&
2390Sstevel@tonic-gate 	    (p = strptime(arg, "%y-%m-%dT%H:%M", &tm)) == NULL &&
2400Sstevel@tonic-gate 	    (p = strptime(arg, "%Y-%m-%dT%H:%M", &tm)) == NULL &&
2410Sstevel@tonic-gate 	    (p = strptime(arg, "%y-%m-%d", &tm)) == NULL &&
2420Sstevel@tonic-gate 	    (p = strptime(arg, "%Y-%m-%d", &tm)) == NULL &&
2430Sstevel@tonic-gate 	    (p = strptime(arg, "%d%b%y" "%t" "%H:%M:%S", &tm)) == NULL &&
2440Sstevel@tonic-gate 	    (p = strptime(arg, "%d%b%Y" "%t" "%H:%M:%S", &tm)) == NULL &&
2450Sstevel@tonic-gate 	    (p = strptime(arg, "%d%b%y" "%t" "%H:%M", &tm)) == NULL &&
2460Sstevel@tonic-gate 	    (p = strptime(arg, "%d%b%Y" "%t" "%H:%M", &tm)) == NULL &&
2470Sstevel@tonic-gate 	    ((p = strptime(arg, "%d%b%y", &tm)) == NULL || isdigit(*p)) &&
2480Sstevel@tonic-gate 	    (p = strptime(arg, "%d%b%Y", &tm)) == NULL &&
2490Sstevel@tonic-gate 	    (p = strptime(arg, "%b%t%d" "%t" "%H:%M:%S", &tm)) == NULL &&
2500Sstevel@tonic-gate 	    (p = strptime(arg, "%b%t%d" "%t" "%H:%M:%S", &tm)) == NULL &&
2510Sstevel@tonic-gate 	    (p = strptime(arg, "%H:%M:%S", &tm)) == NULL &&
2520Sstevel@tonic-gate 	    (p = strptime(arg, "%H:%M", &tm)) == NULL) {
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		hrtime_t nsec;
2550Sstevel@tonic-gate 		int i;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 		errno = 0;
2580Sstevel@tonic-gate 		nsec = strtol(arg, (char **)&p, 10);
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		if (errno != 0 || nsec == 0 || p == arg || *p == '\0') {
2610Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: illegal time "
2620Sstevel@tonic-gate 			    "format -- %s\n", g_pname, arg);
2630Sstevel@tonic-gate 			exit(FMDUMP_EXIT_USAGE);
2640Sstevel@tonic-gate 		}
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 		for (i = 0; suffix[i].name != NULL; i++) {
2670Sstevel@tonic-gate 			if (strcasecmp(suffix[i].name, p) == 0) {
2680Sstevel@tonic-gate 				nsec *= suffix[i].mul;
2690Sstevel@tonic-gate 				break;
2700Sstevel@tonic-gate 			}
2710Sstevel@tonic-gate 		}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 		if (suffix[i].name == NULL) {
2740Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: illegal time "
2750Sstevel@tonic-gate 			    "format -- %s\n", g_pname, arg);
2760Sstevel@tonic-gate 			exit(FMDUMP_EXIT_USAGE);
2770Sstevel@tonic-gate 		}
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 		tvp->tv_sec = nsec / NANOSEC;
2800Sstevel@tonic-gate 		tvp->tv_usec = (nsec % NANOSEC) / (NANOSEC / MICROSEC);
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 		if (tvp->tv_sec > tod.tv_sec) {
2830Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: time delta precedes "
2840Sstevel@tonic-gate 			    "UTC time origin -- %s\n", g_pname, arg);
2850Sstevel@tonic-gate 			exit(FMDUMP_EXIT_USAGE);
2860Sstevel@tonic-gate 		}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 		tvp->tv_sec = tod.tv_sec - tvp->tv_sec;
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	} else if (*p == '\0' || *p == '.') {
2910Sstevel@tonic-gate 		/*
2920Sstevel@tonic-gate 		 * If tm_year is zero, we matched [%b %d] %H:%M[:%S]; use
2930Sstevel@tonic-gate 		 * the result of localtime(&tod.tv_sec) to fill in the rest.
2940Sstevel@tonic-gate 		 */
2950Sstevel@tonic-gate 		if (tm.tm_year == 0) {
2960Sstevel@tonic-gate 			int h = tm.tm_hour;
2970Sstevel@tonic-gate 			int m = tm.tm_min;
2980Sstevel@tonic-gate 			int s = tm.tm_sec;
2990Sstevel@tonic-gate 			int b = tm.tm_mon;
3000Sstevel@tonic-gate 			int d = tm.tm_mday;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 			bcopy(localtime(&tod.tv_sec), &tm, sizeof (tm));
3030Sstevel@tonic-gate 			tm.tm_isdst = 0; /* see strptime(3C) and below */
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 			if (d > 0) {
3060Sstevel@tonic-gate 				tm.tm_mon = b;
3070Sstevel@tonic-gate 				tm.tm_mday = d;
3080Sstevel@tonic-gate 			}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 			tm.tm_hour = h;
3110Sstevel@tonic-gate 			tm.tm_min = m;
3120Sstevel@tonic-gate 			tm.tm_sec = s;
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		errno = 0;
3160Sstevel@tonic-gate 		tvp->tv_sec = mktime(&tm);
3170Sstevel@tonic-gate 		tvp->tv_usec = 0;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		if (tvp->tv_sec == -1L && errno != 0) {
3200Sstevel@tonic-gate 			(void) fprintf(stderr, "%s: failed to compose "
3210Sstevel@tonic-gate 			    "time %s: %s\n", g_pname, arg, strerror(errno));
3220Sstevel@tonic-gate 			exit(FMDUMP_EXIT_ERROR);
3230Sstevel@tonic-gate 		}
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 		/*
3260Sstevel@tonic-gate 		 * If our mktime() set tm_isdst, adjust the result for DST by
3270Sstevel@tonic-gate 		 * subtracting the offset between the main and alternate zones.
3280Sstevel@tonic-gate 		 */
3290Sstevel@tonic-gate 		if (tm.tm_isdst)
3300Sstevel@tonic-gate 			tvp->tv_sec -= timezone - altzone;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 		if (p[0] == '.') {
3330Sstevel@tonic-gate 			arg = p;
3340Sstevel@tonic-gate 			errno = 0;
3350Sstevel@tonic-gate 			tvp->tv_usec =
3360Sstevel@tonic-gate 			    (suseconds_t)(strtod(arg, &p) * (double)MICROSEC);
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 			if (errno != 0 || p == arg || *p != '\0') {
3390Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: illegal time "
3400Sstevel@tonic-gate 				    "suffix -- .%s\n", g_pname, arg);
3410Sstevel@tonic-gate 				exit(FMDUMP_EXIT_USAGE);
3420Sstevel@tonic-gate 			}
3430Sstevel@tonic-gate 		}
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	} else {
3460Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: unexpected suffix after "
3470Sstevel@tonic-gate 		    "time %s -- %s\n", g_pname, arg, p);
3480Sstevel@tonic-gate 		exit(FMDUMP_EXIT_USAGE);
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	return (tvp);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate  * If the -u option is specified in combination with the -e option, we iterate
3560Sstevel@tonic-gate  * over each record in the fault log with a matching UUID finding xrefs to the
3570Sstevel@tonic-gate  * error log, and then use this function to iterate over every xref'd record.
3580Sstevel@tonic-gate  */
3590Sstevel@tonic-gate int
3600Sstevel@tonic-gate xref_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
3610Sstevel@tonic-gate {
3620Sstevel@tonic-gate 	const fmd_log_record_t *xrp = rp->rec_xrefs;
3630Sstevel@tonic-gate 	fmdump_arg_t *dap = arg;
3640Sstevel@tonic-gate 	int i, rv = 0;
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	for (i = 0; rv == 0 && i < rp->rec_nrefs; i++, xrp++) {
3670Sstevel@tonic-gate 		if (fmd_log_filter(lp, dap->da_fc, dap->da_fv, xrp))
3680Sstevel@tonic-gate 			rv = dap->da_fmt->do_func(lp, xrp, dap->da_fp);
3690Sstevel@tonic-gate 	}
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	return (rv);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate int
3750Sstevel@tonic-gate xoff_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	fmdump_lyr_t *dyp = arg;
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 	fmdump_printf(dyp->dy_fp, "%16llx ", (u_longlong_t)rp->rec_off);
3800Sstevel@tonic-gate 	return (dyp->dy_func(lp, rp, dyp->dy_arg));
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate /*
3846640Scth  * Initialize fmd_log_filter_nvarg_t from -n name=value argument string.
3856640Scth  */
3866640Scth static fmd_log_filter_nvarg_t *
3876640Scth setupnamevalue(char *namevalue)
3886640Scth {
3896640Scth 	fmd_log_filter_nvarg_t	*argt;
3906640Scth 	char			*value;
3916640Scth 	regex_t			*value_regex = NULL;
3926640Scth 	char			errstr[128];
3936640Scth 	int			rv;
3946640Scth 
3956640Scth 	if ((value = strchr(namevalue, '=')) == NULL) {
3966640Scth 		value_regex = NULL;
3976640Scth 	} else {
3986640Scth 		*value++ = '\0';	/* separate name and value string */
3996640Scth 
4006640Scth 		/*
4016640Scth 		 * Skip white space before value to facilitate direct
4026640Scth 		 * cut/paste from previous fmdump output.
4036640Scth 		 */
4046640Scth 		while (isspace(*value))
4056640Scth 			value++;
4066640Scth 
4076640Scth 		if ((value_regex = malloc(sizeof (regex_t))) == NULL) {
4086640Scth 			(void) fprintf(stderr, "%s: failed to allocate memory: "
4096640Scth 			    "%s\n", g_pname, strerror(errno));
4106640Scth 			exit(FMDUMP_EXIT_FATAL);
4116640Scth 		}
4126640Scth 
4136640Scth 		/* compile regular expression for possible string match */
4146640Scth 		if ((rv = regcomp(value_regex, value,
4156640Scth 		    REG_NOSUB|REG_NEWLINE)) != 0) {
4166640Scth 			(void) regerror(rv, value_regex, errstr,
4176640Scth 			    sizeof (errstr));
4186640Scth 			(void) fprintf(stderr, "unexpected regular expression "
4196640Scth 			    "in %s: %s\n", value, errstr);
4206640Scth 			free(value_regex);
4216640Scth 			exit(FMDUMP_EXIT_USAGE);
4226640Scth 		}
4236640Scth 	}
4246640Scth 
4256640Scth 	if ((argt = malloc(sizeof (fmd_log_filter_nvarg_t))) == NULL) {
4266640Scth 		(void) fprintf(stderr, "%s: failed to allocate memory: %s\n",
4276640Scth 		    g_pname, strerror(errno));
4286640Scth 		exit(FMDUMP_EXIT_FATAL);
4296640Scth 	}
4306640Scth 	argt->nvarg_name = namevalue;		/* now just name */
4316640Scth 	argt->nvarg_value = value;
4326640Scth 	argt->nvarg_value_regex = value_regex;
4336640Scth 	return (argt);
4346640Scth }
4356640Scth 
4366640Scth /*
4370Sstevel@tonic-gate  * If the -a option is not present, filter out fault records that correspond
4380Sstevel@tonic-gate  * to events that the producer requested not be messaged for administrators.
4390Sstevel@tonic-gate  */
4400Sstevel@tonic-gate /*ARGSUSED*/
4410Sstevel@tonic-gate int
4420Sstevel@tonic-gate log_filter_silent(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	boolean_t msg;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	return (nvlist_lookup_boolean_value(rp->rec_nvl,
4470Sstevel@tonic-gate 	    FM_SUSPECT_MESSAGE, &msg) != 0 || msg != 0);
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4508740SSean.Ye@Sun.COM struct loglink {
4518740SSean.Ye@Sun.COM 	char 		*path;
4528740SSean.Ye@Sun.COM 	long		suffix;
4538740SSean.Ye@Sun.COM 	struct loglink	*next;
4548740SSean.Ye@Sun.COM };
4558740SSean.Ye@Sun.COM 
4568740SSean.Ye@Sun.COM static void
4578740SSean.Ye@Sun.COM addlink(struct loglink **llp, char *dirname, char *logname, long suffix)
4588740SSean.Ye@Sun.COM {
4598740SSean.Ye@Sun.COM 	struct loglink *newp;
4608740SSean.Ye@Sun.COM 	size_t len;
4618740SSean.Ye@Sun.COM 	char *str;
4628740SSean.Ye@Sun.COM 
4638740SSean.Ye@Sun.COM 	newp = malloc(sizeof (struct loglink));
4648740SSean.Ye@Sun.COM 	len = strlen(dirname) + strlen(logname) + 2;
4658740SSean.Ye@Sun.COM 	str = malloc(len);
4668740SSean.Ye@Sun.COM 	if (newp == NULL || str == NULL) {
4678740SSean.Ye@Sun.COM 		(void) fprintf(stderr, "%s: failed to allocate memory: %s\n",
4688740SSean.Ye@Sun.COM 		    g_pname, strerror(errno));
4698740SSean.Ye@Sun.COM 		exit(FMDUMP_EXIT_FATAL);
4708740SSean.Ye@Sun.COM 	}
4718740SSean.Ye@Sun.COM 
4728740SSean.Ye@Sun.COM 	(void) snprintf(str, len, "%s/%s", dirname, logname);
4738740SSean.Ye@Sun.COM 	newp->path = str;
4748740SSean.Ye@Sun.COM 	newp->suffix = suffix;
4758740SSean.Ye@Sun.COM 
4768740SSean.Ye@Sun.COM 	while (*llp != NULL && suffix < (*llp)->suffix)
4778740SSean.Ye@Sun.COM 		llp = &(*llp)->next;
4788740SSean.Ye@Sun.COM 
4798740SSean.Ye@Sun.COM 	newp->next = *llp;
4808740SSean.Ye@Sun.COM 	*llp = newp;
4818740SSean.Ye@Sun.COM }
4828740SSean.Ye@Sun.COM 
4838740SSean.Ye@Sun.COM /*
4848740SSean.Ye@Sun.COM  * Find and return all the rotated logs.
4858740SSean.Ye@Sun.COM  */
4868740SSean.Ye@Sun.COM static struct loglink *
4878740SSean.Ye@Sun.COM get_rotated_logs(char *logpath)
4888740SSean.Ye@Sun.COM {
4898740SSean.Ye@Sun.COM 	char dirname[PATH_MAX], *logname, *endptr;
4908740SSean.Ye@Sun.COM 	DIR *dirp;
4918740SSean.Ye@Sun.COM 	struct dirent *dp;
4928740SSean.Ye@Sun.COM 	long len, suffix;
4938740SSean.Ye@Sun.COM 	struct loglink *head = NULL;
4948740SSean.Ye@Sun.COM 
4958740SSean.Ye@Sun.COM 	(void) strlcpy(dirname, logpath, sizeof (dirname));
4968740SSean.Ye@Sun.COM 	logname = strrchr(dirname, '/');
4978740SSean.Ye@Sun.COM 	*logname++ = '\0';
4988740SSean.Ye@Sun.COM 	len = strlen(logname);
4998740SSean.Ye@Sun.COM 
5008740SSean.Ye@Sun.COM 	if ((dirp = opendir(dirname)) == NULL) {
5018740SSean.Ye@Sun.COM 		(void) fprintf(stderr, "%s: failed to opendir `%s': %s\n",
5028740SSean.Ye@Sun.COM 		    g_pname, dirname, strerror(errno));
5038740SSean.Ye@Sun.COM 		return (NULL);
5048740SSean.Ye@Sun.COM 	}
5058740SSean.Ye@Sun.COM 
5068740SSean.Ye@Sun.COM 	while ((dp = readdir(dirp)) != NULL) {
5078740SSean.Ye@Sun.COM 		/*
5088740SSean.Ye@Sun.COM 		 * Search the log directory for logs named "<logname>.0",
5098740SSean.Ye@Sun.COM 		 * "<logname>.1", etc and add to the link in the
5108740SSean.Ye@Sun.COM 		 * reverse numeric order.
5118740SSean.Ye@Sun.COM 		 */
5128740SSean.Ye@Sun.COM 		if (strlen(dp->d_name) < len + 2 ||
5138740SSean.Ye@Sun.COM 		    strncmp(dp->d_name, logname, len) != 0 ||
5148740SSean.Ye@Sun.COM 		    dp->d_name[len] != '.')
5158740SSean.Ye@Sun.COM 			continue;
5168740SSean.Ye@Sun.COM 
5178740SSean.Ye@Sun.COM 		/*
5188740SSean.Ye@Sun.COM 		 * "*.0-" file normally should not be seen.  It may
5198740SSean.Ye@Sun.COM 		 * exist when user manually run 'fmadm rotate'.
5208740SSean.Ye@Sun.COM 		 * In such case, we put it at the end of the list so
5218740SSean.Ye@Sun.COM 		 * it'll be dumped after all the rotated logs, before
5228740SSean.Ye@Sun.COM 		 * the current one.
5238740SSean.Ye@Sun.COM 		 */
5248740SSean.Ye@Sun.COM 		if (strcmp(dp->d_name + len + 1, "0-") == 0)
5258740SSean.Ye@Sun.COM 			addlink(&head, dirname, dp->d_name, -1);
5268740SSean.Ye@Sun.COM 		else if ((suffix = strtol(dp->d_name + len + 1,
5278740SSean.Ye@Sun.COM 		    &endptr, 10)) >= 0 && *endptr == '\0')
5288740SSean.Ye@Sun.COM 			addlink(&head, dirname, dp->d_name, suffix);
5298740SSean.Ye@Sun.COM 	}
5308740SSean.Ye@Sun.COM 
5318740SSean.Ye@Sun.COM 	(void) closedir(dirp);
5328740SSean.Ye@Sun.COM 
5338740SSean.Ye@Sun.COM 	return (head);
5348740SSean.Ye@Sun.COM }
5358740SSean.Ye@Sun.COM 
5360Sstevel@tonic-gate int
5370Sstevel@tonic-gate main(int argc, char *argv[])
5380Sstevel@tonic-gate {
5399501SRobert.Johnston@Sun.COM 	int opt_a = 0, opt_e = 0, opt_f = 0, opt_H = 0, opt_m = 0;
5400Sstevel@tonic-gate 	int opt_u = 0, opt_v = 0, opt_V = 0;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	char ifile[PATH_MAX] = "";
5430Sstevel@tonic-gate 	int iflags = 0;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	fmdump_arg_t arg;
5460Sstevel@tonic-gate 	fmdump_lyr_t lyr;
5470Sstevel@tonic-gate 	const fmdump_ops_t *ops;
5480Sstevel@tonic-gate 	fmd_log_filter_t *filtv;
5490Sstevel@tonic-gate 	uint_t filtc;
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 	fmd_log_filter_t *errfv, *fltfv, *allfv;
5520Sstevel@tonic-gate 	uint_t errfc = 0, fltfc = 0, allfc = 0;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	fmd_log_header_t log;
5550Sstevel@tonic-gate 	fmd_log_rec_f *func;
5560Sstevel@tonic-gate 	void *farg;
5570Sstevel@tonic-gate 	fmd_log_t *lp;
5580Sstevel@tonic-gate 	int c, err;
5590Sstevel@tonic-gate 	off64_t off = 0;
5608740SSean.Ye@Sun.COM 	ulong_t recs;
5618740SSean.Ye@Sun.COM 	struct loglink *rotated_logs = NULL, *llp;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	g_pname = argv[0];
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	errfv = alloca(sizeof (fmd_log_filter_t) * argc);
5660Sstevel@tonic-gate 	fltfv = alloca(sizeof (fmd_log_filter_t) * argc);
5670Sstevel@tonic-gate 	allfv = alloca(sizeof (fmd_log_filter_t) * argc);
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	while (optind < argc) {
5706640Scth 		while ((c =
5719501SRobert.Johnston@Sun.COM 		    getopt(argc, argv, "ac:efHmn:O:R:t:T:u:vV")) != EOF) {
5720Sstevel@tonic-gate 			switch (c) {
5730Sstevel@tonic-gate 			case 'a':
5740Sstevel@tonic-gate 				opt_a++;
5750Sstevel@tonic-gate 				break;
5760Sstevel@tonic-gate 			case 'c':
5770Sstevel@tonic-gate 				errfv[errfc].filt_func = fmd_log_filter_class;
5780Sstevel@tonic-gate 				errfv[errfc].filt_arg = optarg;
5790Sstevel@tonic-gate 				allfv[allfc++] = errfv[errfc++];
5800Sstevel@tonic-gate 				break;
5810Sstevel@tonic-gate 			case 'e':
5820Sstevel@tonic-gate 				opt_e++;
5830Sstevel@tonic-gate 				break;
5840Sstevel@tonic-gate 			case 'f':
5850Sstevel@tonic-gate 				opt_f++;
5860Sstevel@tonic-gate 				break;
5870Sstevel@tonic-gate 			case 'H':
5880Sstevel@tonic-gate 				opt_H++;
5890Sstevel@tonic-gate 				break;
5909501SRobert.Johnston@Sun.COM 			case 'm':
5919501SRobert.Johnston@Sun.COM 				opt_m++;
5929501SRobert.Johnston@Sun.COM 				break;
5930Sstevel@tonic-gate 			case 'O':
5940Sstevel@tonic-gate 				off = strtoull(optarg, NULL, 16);
5950Sstevel@tonic-gate 				iflags |= FMD_LOG_XITER_OFFS;
5960Sstevel@tonic-gate 				break;
5970Sstevel@tonic-gate 			case 'R':
5980Sstevel@tonic-gate 				g_root = optarg;
5990Sstevel@tonic-gate 				break;
6000Sstevel@tonic-gate 			case 't':
6010Sstevel@tonic-gate 				errfv[errfc].filt_func = fmd_log_filter_after;
6020Sstevel@tonic-gate 				errfv[errfc].filt_arg = gettimeopt(optarg);
6030Sstevel@tonic-gate 				allfv[allfc++] = errfv[errfc++];
6040Sstevel@tonic-gate 				break;
6050Sstevel@tonic-gate 			case 'T':
6060Sstevel@tonic-gate 				errfv[errfc].filt_func = fmd_log_filter_before;
6070Sstevel@tonic-gate 				errfv[errfc].filt_arg = gettimeopt(optarg);
6080Sstevel@tonic-gate 				allfv[allfc++] = errfv[errfc++];
6090Sstevel@tonic-gate 				break;
6100Sstevel@tonic-gate 			case 'u':
6110Sstevel@tonic-gate 				fltfv[fltfc].filt_func = fmd_log_filter_uuid;
6120Sstevel@tonic-gate 				fltfv[fltfc].filt_arg = optarg;
6130Sstevel@tonic-gate 				allfv[allfc++] = fltfv[fltfc++];
6140Sstevel@tonic-gate 				opt_u++;
6150Sstevel@tonic-gate 				opt_a++; /* -u implies -a */
6160Sstevel@tonic-gate 				break;
6176640Scth 			case 'n': {
6186640Scth 				fltfv[fltfc].filt_func = fmd_log_filter_nv;
6196640Scth 				fltfv[fltfc].filt_arg = setupnamevalue(optarg);
6206640Scth 				allfv[allfc++] = fltfv[fltfc++];
6216640Scth 				break;
6226640Scth 			}
6230Sstevel@tonic-gate 			case 'v':
6240Sstevel@tonic-gate 				opt_v++;
6250Sstevel@tonic-gate 				break;
6260Sstevel@tonic-gate 			case 'V':
6270Sstevel@tonic-gate 				opt_V++;
6280Sstevel@tonic-gate 				break;
6290Sstevel@tonic-gate 			default:
6300Sstevel@tonic-gate 				return (usage(stderr));
6310Sstevel@tonic-gate 			}
6320Sstevel@tonic-gate 		}
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 		if (optind < argc) {
6350Sstevel@tonic-gate 			if (*ifile != '\0') {
6360Sstevel@tonic-gate 				(void) fprintf(stderr, "%s: illegal "
6370Sstevel@tonic-gate 				    "argument -- %s\n", g_pname, argv[optind]);
6380Sstevel@tonic-gate 				return (FMDUMP_EXIT_USAGE);
6390Sstevel@tonic-gate 			} else {
6400Sstevel@tonic-gate 				(void) strlcpy(ifile,
6410Sstevel@tonic-gate 				    argv[optind++], sizeof (ifile));
6420Sstevel@tonic-gate 			}
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	if (*ifile == '\0') {
6470Sstevel@tonic-gate 		(void) snprintf(ifile, sizeof (ifile), "%s/var/fm/fmd/%slog",
6480Sstevel@tonic-gate 		    g_root ? g_root : "", opt_e && !opt_u ? "err" : "flt");
6498740SSean.Ye@Sun.COM 		/*
6508740SSean.Ye@Sun.COM 		 * logadm may rotate the logs.  When no input file is specified,
6518740SSean.Ye@Sun.COM 		 * we try to dump all the rotated logs as well in the right
6528740SSean.Ye@Sun.COM 		 * order.
6538740SSean.Ye@Sun.COM 		 */
6548740SSean.Ye@Sun.COM 		if (!opt_H && off == 0)
6558740SSean.Ye@Sun.COM 			rotated_logs = get_rotated_logs(ifile);
6560Sstevel@tonic-gate 	} else if (g_root != NULL) {
6570Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: -R option is not appropriate "
6580Sstevel@tonic-gate 		    "when file operand is present\n", g_pname);
6590Sstevel@tonic-gate 		return (FMDUMP_EXIT_USAGE);
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 
6629501SRobert.Johnston@Sun.COM 	if ((g_msg = fmd_msg_init(g_root, FMD_MSG_VERSION)) == NULL) {
6639501SRobert.Johnston@Sun.COM 		(void) fprintf(stderr, "%s: failed to initialize "
6649501SRobert.Johnston@Sun.COM 		    "libfmd_msg: %s\n", g_pname, strerror(errno));
6659501SRobert.Johnston@Sun.COM 		return (FMDUMP_EXIT_FATAL);
6669501SRobert.Johnston@Sun.COM 	}
6679501SRobert.Johnston@Sun.COM 
6680Sstevel@tonic-gate 	if ((lp = fmd_log_open(FMD_LOG_VERSION, ifile, &err)) == NULL) {
6690Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: failed to open %s: %s\n",
6700Sstevel@tonic-gate 		    g_pname, ifile, fmd_log_errmsg(NULL, err));
6710Sstevel@tonic-gate 		return (FMDUMP_EXIT_FATAL);
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	if (opt_H) {
6750Sstevel@tonic-gate 		fmd_log_header(lp, &log);
6760Sstevel@tonic-gate 
6770Sstevel@tonic-gate 		(void) printf("EXD_CREATOR = %s\n", log.log_creator);
6780Sstevel@tonic-gate 		(void) printf("EXD_HOSTNAME = %s\n", log.log_hostname);
6790Sstevel@tonic-gate 		(void) printf("EXD_FMA_LABEL = %s\n", log.log_label);
6800Sstevel@tonic-gate 		(void) printf("EXD_FMA_VERSION = %s\n", log.log_version);
6810Sstevel@tonic-gate 		(void) printf("EXD_FMA_OSREL = %s\n", log.log_osrelease);
6820Sstevel@tonic-gate 		(void) printf("EXD_FMA_OSVER = %s\n", log.log_osversion);
6830Sstevel@tonic-gate 		(void) printf("EXD_FMA_PLAT = %s\n", log.log_platform);
6841052Sdilpreet 		(void) printf("EXD_FMA_UUID = %s\n", log.log_uuid);
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 		return (FMDUMP_EXIT_SUCCESS);
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (off != 0 && fmd_log_seek(lp, off) != 0) {
6900Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: failed to seek %s: %s\n",
6910Sstevel@tonic-gate 		    g_pname, ifile, fmd_log_errmsg(lp, fmd_log_errno(lp)));
6920Sstevel@tonic-gate 		return (FMDUMP_EXIT_FATAL);
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	if (opt_e && opt_u)
6960Sstevel@tonic-gate 		ops = &fmdump_err_ops;
6970Sstevel@tonic-gate 	else if (strcmp(fmd_log_label(lp), fmdump_flt_ops.do_label) == 0)
6980Sstevel@tonic-gate 		ops = &fmdump_flt_ops;
6990Sstevel@tonic-gate 	else if (strcmp(fmd_log_label(lp), fmdump_asru_ops.do_label) == 0)
7000Sstevel@tonic-gate 		ops = &fmdump_asru_ops;
7010Sstevel@tonic-gate 	else
7020Sstevel@tonic-gate 		ops = &fmdump_err_ops;
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	if (!opt_a && ops == &fmdump_flt_ops) {
7050Sstevel@tonic-gate 		fltfv[fltfc].filt_func = log_filter_silent;
7060Sstevel@tonic-gate 		fltfv[fltfc].filt_arg = NULL;
7070Sstevel@tonic-gate 		allfv[allfc++] = fltfv[fltfc++];
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	if (opt_V) {
7110Sstevel@tonic-gate 		arg.da_fmt = &ops->do_formats[FMDUMP_VERB2];
7120Sstevel@tonic-gate 		iflags |= FMD_LOG_XITER_REFS;
7130Sstevel@tonic-gate 	} else if (opt_v) {
7140Sstevel@tonic-gate 		arg.da_fmt = &ops->do_formats[FMDUMP_VERB1];
7159501SRobert.Johnston@Sun.COM 	} else if (opt_m) {
7169501SRobert.Johnston@Sun.COM 		arg.da_fmt = &ops->do_formats[FMDUMP_MSG];
7170Sstevel@tonic-gate 	} else
7180Sstevel@tonic-gate 		arg.da_fmt = &ops->do_formats[FMDUMP_SHORT];
7190Sstevel@tonic-gate 
7209501SRobert.Johnston@Sun.COM 	if (opt_m && arg.da_fmt->do_func == NULL) {
7219501SRobert.Johnston@Sun.COM 		(void) fprintf(stderr, "%s: -m mode is not supported for "
7229501SRobert.Johnston@Sun.COM 		    "log of type %s: %s\n", g_pname, fmd_log_label(lp), ifile);
7239501SRobert.Johnston@Sun.COM 		return (FMDUMP_EXIT_USAGE);
7249501SRobert.Johnston@Sun.COM 	}
7259501SRobert.Johnston@Sun.COM 
7260Sstevel@tonic-gate 	arg.da_fv = errfv;
7270Sstevel@tonic-gate 	arg.da_fc = errfc;
7280Sstevel@tonic-gate 	arg.da_fp = stdout;
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	if (iflags & FMD_LOG_XITER_OFFS)
7310Sstevel@tonic-gate 		fmdump_printf(arg.da_fp, "%16s ", "OFFSET");
7320Sstevel@tonic-gate 
733*10928SStephen.Hanson@Sun.COM 	if (arg.da_fmt->do_hdr && !(opt_V && ops == &fmdump_flt_ops))
7340Sstevel@tonic-gate 		fmdump_printf(arg.da_fp, "%s\n", arg.da_fmt->do_hdr);
7350Sstevel@tonic-gate 
7360Sstevel@tonic-gate 	if (opt_e && opt_u) {
7370Sstevel@tonic-gate 		iflags |= FMD_LOG_XITER_REFS;
7380Sstevel@tonic-gate 		func = xref_iter;
7390Sstevel@tonic-gate 		farg = &arg;
7400Sstevel@tonic-gate 		filtc = fltfc;
7410Sstevel@tonic-gate 		filtv = fltfv;
7420Sstevel@tonic-gate 	} else {
7430Sstevel@tonic-gate 		func = arg.da_fmt->do_func;
7440Sstevel@tonic-gate 		farg = arg.da_fp;
7450Sstevel@tonic-gate 		filtc = allfc;
7460Sstevel@tonic-gate 		filtv = allfv;
7470Sstevel@tonic-gate 	}
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	if (iflags & FMD_LOG_XITER_OFFS) {
7500Sstevel@tonic-gate 		lyr.dy_func = func;
7510Sstevel@tonic-gate 		lyr.dy_arg = farg;
7520Sstevel@tonic-gate 		lyr.dy_fp = arg.da_fp;
7530Sstevel@tonic-gate 		func = xoff_iter;
7540Sstevel@tonic-gate 		farg = &lyr;
7550Sstevel@tonic-gate 	}
7560Sstevel@tonic-gate 
7578740SSean.Ye@Sun.COM 	for (llp = rotated_logs; llp != NULL; llp = llp->next) {
7588740SSean.Ye@Sun.COM 		fmd_log_t *rlp;
7598740SSean.Ye@Sun.COM 
7608740SSean.Ye@Sun.COM 		if ((rlp = fmd_log_open(FMD_LOG_VERSION, llp->path, &err))
7618740SSean.Ye@Sun.COM 		    == NULL) {
7628740SSean.Ye@Sun.COM 			(void) fprintf(stderr, "%s: failed to open %s: %s\n",
7638740SSean.Ye@Sun.COM 			    g_pname, llp->path, fmd_log_errmsg(NULL, err));
7648740SSean.Ye@Sun.COM 			g_errs++;
7658740SSean.Ye@Sun.COM 			continue;
7668740SSean.Ye@Sun.COM 		}
7678740SSean.Ye@Sun.COM 
7688740SSean.Ye@Sun.COM 		recs = 0;
7698740SSean.Ye@Sun.COM 		if (fmd_log_xiter(rlp, iflags, filtc, filtv,
7708740SSean.Ye@Sun.COM 		    func, error, farg, &recs) != 0) {
7718740SSean.Ye@Sun.COM 			(void) fprintf(stderr,
7728740SSean.Ye@Sun.COM 			    "%s: failed to dump %s: %s\n", g_pname, llp->path,
7738740SSean.Ye@Sun.COM 			    fmd_log_errmsg(rlp, fmd_log_errno(rlp)));
7748740SSean.Ye@Sun.COM 			g_errs++;
7758740SSean.Ye@Sun.COM 		}
7768740SSean.Ye@Sun.COM 		g_recs += recs;
7778740SSean.Ye@Sun.COM 
7788740SSean.Ye@Sun.COM 		fmd_log_close(rlp);
7798740SSean.Ye@Sun.COM 	}
7808740SSean.Ye@Sun.COM 
7810Sstevel@tonic-gate 	do {
7828740SSean.Ye@Sun.COM 		recs = 0;
7830Sstevel@tonic-gate 		if (fmd_log_xiter(lp, iflags, filtc, filtv,
7848740SSean.Ye@Sun.COM 		    func, error, farg, &recs) != 0) {
7850Sstevel@tonic-gate 			(void) fprintf(stderr,
7860Sstevel@tonic-gate 			    "%s: failed to dump %s: %s\n", g_pname, ifile,
7870Sstevel@tonic-gate 			    fmd_log_errmsg(lp, fmd_log_errno(lp)));
7880Sstevel@tonic-gate 			g_errs++;
7890Sstevel@tonic-gate 		}
7908740SSean.Ye@Sun.COM 		g_recs += recs;
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 		if (opt_f)
7930Sstevel@tonic-gate 			(void) sleep(1);
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	} while (opt_f);
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	if (!opt_f && g_recs == 0 && isatty(STDOUT_FILENO))
7980Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: %s is empty\n", g_pname, ifile);
7990Sstevel@tonic-gate 
8009501SRobert.Johnston@Sun.COM 	if (g_thp != NULL)
8019501SRobert.Johnston@Sun.COM 		topo_close(g_thp);
8029501SRobert.Johnston@Sun.COM 
8030Sstevel@tonic-gate 	fmd_log_close(lp);
8049501SRobert.Johnston@Sun.COM 	fmd_msg_fini(g_msg);
8059501SRobert.Johnston@Sun.COM 
8060Sstevel@tonic-gate 	return (g_errs ? FMDUMP_EXIT_ERROR : FMDUMP_EXIT_SUCCESS);
8070Sstevel@tonic-gate }
808