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 /*
22*12967Sgavin.maltby@oracle.com * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include <alloca.h>
260Sstevel@tonic-gate #include <unistd.h>
270Sstevel@tonic-gate #include <limits.h>
280Sstevel@tonic-gate #include <strings.h>
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <stdarg.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <errno.h>
330Sstevel@tonic-gate #include <time.h>
340Sstevel@tonic-gate #include <ctype.h>
356640Scth #include <regex.h>
368740SSean.Ye@Sun.COM #include <dirent.h>
37*12967Sgavin.maltby@oracle.com #include <pthread.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
fmdump_printf(FILE * fp,const char * format,...)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
fmdump_vwarn(const char * format,va_list ap)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
fmdump_warn(const char * format,...)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
96*12967Sgavin.maltby@oracle.com static void
fmdump_exit(int err,int exitcode,const char * format,va_list ap)97*12967Sgavin.maltby@oracle.com fmdump_exit(int err, int exitcode, const char *format, va_list ap)
98*12967Sgavin.maltby@oracle.com {
99*12967Sgavin.maltby@oracle.com (void) fprintf(stderr, "%s: ", g_pname);
100*12967Sgavin.maltby@oracle.com
101*12967Sgavin.maltby@oracle.com (void) vfprintf(stderr, format, ap);
102*12967Sgavin.maltby@oracle.com
103*12967Sgavin.maltby@oracle.com if (strchr(format, '\n') == NULL)
104*12967Sgavin.maltby@oracle.com (void) fprintf(stderr, ": %s\n", strerror(err));
105*12967Sgavin.maltby@oracle.com
106*12967Sgavin.maltby@oracle.com exit(exitcode);
107*12967Sgavin.maltby@oracle.com }
108*12967Sgavin.maltby@oracle.com
109*12967Sgavin.maltby@oracle.com /*PRINTFLIKE1*/
110*12967Sgavin.maltby@oracle.com static void
fmdump_fatal(const char * format,...)111*12967Sgavin.maltby@oracle.com fmdump_fatal(const char *format, ...)
112*12967Sgavin.maltby@oracle.com {
113*12967Sgavin.maltby@oracle.com int err = errno;
114*12967Sgavin.maltby@oracle.com
115*12967Sgavin.maltby@oracle.com va_list ap;
116*12967Sgavin.maltby@oracle.com
117*12967Sgavin.maltby@oracle.com va_start(ap, format);
118*12967Sgavin.maltby@oracle.com fmdump_exit(err, FMDUMP_EXIT_FATAL, format, ap);
119*12967Sgavin.maltby@oracle.com va_end(ap);
120*12967Sgavin.maltby@oracle.com }
121*12967Sgavin.maltby@oracle.com
122*12967Sgavin.maltby@oracle.com /*PRINTFLIKE1*/
123*12967Sgavin.maltby@oracle.com static void
fmdump_usage(const char * format,...)124*12967Sgavin.maltby@oracle.com fmdump_usage(const char *format, ...)
125*12967Sgavin.maltby@oracle.com {
126*12967Sgavin.maltby@oracle.com
127*12967Sgavin.maltby@oracle.com int err = errno;
128*12967Sgavin.maltby@oracle.com
129*12967Sgavin.maltby@oracle.com va_list ap;
130*12967Sgavin.maltby@oracle.com
131*12967Sgavin.maltby@oracle.com va_start(ap, format);
132*12967Sgavin.maltby@oracle.com fmdump_exit(err, FMDUMP_EXIT_USAGE, format, ap);
133*12967Sgavin.maltby@oracle.com va_end(ap);
134*12967Sgavin.maltby@oracle.com }
135*12967Sgavin.maltby@oracle.com
1360Sstevel@tonic-gate char *
fmdump_date(char * buf,size_t len,const fmd_log_record_t * rp)1370Sstevel@tonic-gate fmdump_date(char *buf, size_t len, const fmd_log_record_t *rp)
1380Sstevel@tonic-gate {
1390Sstevel@tonic-gate if (rp->rec_sec > LONG_MAX) {
1400Sstevel@tonic-gate fmdump_warn("record time is too large for 32-bit utility\n");
1410Sstevel@tonic-gate (void) snprintf(buf, len, "0x%llx", rp->rec_sec);
1420Sstevel@tonic-gate } else {
1430Sstevel@tonic-gate time_t tod = (time_t)rp->rec_sec;
1445609Scy152378 time_t now = time(NULL);
1455609Scy152378 if (tod > now+60 ||
1465609Scy152378 tod < now - 6L*30L*24L*60L*60L) { /* 6 months ago */
1475609Scy152378 (void) strftime(buf, len, "%b %d %Y %T",
1485609Scy152378 localtime(&tod));
1495609Scy152378 } else {
1505609Scy152378 size_t sz;
1515609Scy152378 sz = strftime(buf, len, "%b %d %T", localtime(&tod));
1525609Scy152378 (void) snprintf(buf + sz, len - sz, ".%4.4llu",
1535609Scy152378 rp->rec_nsec / (NANOSEC / 10000));
1545609Scy152378 }
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate return (buf);
1580Sstevel@tonic-gate }
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate char *
fmdump_year(char * buf,size_t len,const fmd_log_record_t * rp)1610Sstevel@tonic-gate fmdump_year(char *buf, size_t len, const fmd_log_record_t *rp)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate #ifdef _ILP32
1640Sstevel@tonic-gate if (rp->rec_sec > LONG_MAX) {
1650Sstevel@tonic-gate fmdump_warn("record time is too large for 32-bit utility\n");
1660Sstevel@tonic-gate (void) snprintf(buf, len, "0x%llx", rp->rec_sec);
1670Sstevel@tonic-gate } else {
1680Sstevel@tonic-gate #endif
1690Sstevel@tonic-gate time_t tod = (time_t)rp->rec_sec;
1700Sstevel@tonic-gate (void) strftime(buf, len, "%b %d %Y %T", localtime(&tod));
1710Sstevel@tonic-gate #ifdef _ILP32
1720Sstevel@tonic-gate }
1730Sstevel@tonic-gate #endif
1740Sstevel@tonic-gate return (buf);
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate
177*12967Sgavin.maltby@oracle.com /* BEGIN CSTYLED */
178*12967Sgavin.maltby@oracle.com static const char *synopsis =
179*12967Sgavin.maltby@oracle.com "Usage: %s [[-e | -i | -I] | -A ] [-f] [-mvVp] [-c class] [-R root]\n"
180*12967Sgavin.maltby@oracle.com "\t [-t time ][-T time] [-u uuid] [-n name[.name]*[=value]] "
181*12967Sgavin.maltby@oracle.com "[file]...\n "
182*12967Sgavin.maltby@oracle.com "Log selection: [-e | -i | -I] or one [file]; default is the fault log\n"
183*12967Sgavin.maltby@oracle.com "\t-e display error log content\n"
184*12967Sgavin.maltby@oracle.com "\t-i display infolog content\n"
185*12967Sgavin.maltby@oracle.com "\t-I display the high-value-infolog content\n"
186*12967Sgavin.maltby@oracle.com "\t-R set root directory for pathname expansions\n "
187*12967Sgavin.maltby@oracle.com "Command behaviour:\n"
188*12967Sgavin.maltby@oracle.com "\t-A Aggregate specified [file]s or, if no [file], all known logs\n"
189*12967Sgavin.maltby@oracle.com "\t-f follow growth of log file by waiting for additional data\n "
190*12967Sgavin.maltby@oracle.com "Output options:\n"
191*12967Sgavin.maltby@oracle.com "\t-m display human-readable messages (only for fault logs)\n"
192*12967Sgavin.maltby@oracle.com "\t-v set verbose mode: display additional event detail\n"
193*12967Sgavin.maltby@oracle.com "\t-V set very verbose mode: display complete event contents\n"
194*12967Sgavin.maltby@oracle.com "\t-p Used with -V: apply some output prettification\n "
195*12967Sgavin.maltby@oracle.com "Selection filters:\n"
196*12967Sgavin.maltby@oracle.com "\t-c select events that match the specified class\n"
197*12967Sgavin.maltby@oracle.com "\t-t select events that occurred after the specified time\n"
198*12967Sgavin.maltby@oracle.com "\t-T select events that occurred before the specified time\n"
199*12967Sgavin.maltby@oracle.com "\t-u select events that match the specified diagnosis uuid\n"
200*12967Sgavin.maltby@oracle.com "\t-n select events containing named nvpair (with matching value)\n";
201*12967Sgavin.maltby@oracle.com /* END CSTYLED */
202*12967Sgavin.maltby@oracle.com
2030Sstevel@tonic-gate static int
usage(FILE * fp)2040Sstevel@tonic-gate usage(FILE *fp)
2050Sstevel@tonic-gate {
206*12967Sgavin.maltby@oracle.com (void) fprintf(fp, synopsis, g_pname);
2070Sstevel@tonic-gate return (FMDUMP_EXIT_USAGE);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate /*ARGSUSED*/
2110Sstevel@tonic-gate static int
error(fmd_log_t * lp,void * private)2120Sstevel@tonic-gate error(fmd_log_t *lp, void *private)
2130Sstevel@tonic-gate {
2140Sstevel@tonic-gate fmdump_warn("skipping record: %s\n",
2150Sstevel@tonic-gate fmd_log_errmsg(lp, fmd_log_errno(lp)));
2160Sstevel@tonic-gate return (0);
2170Sstevel@tonic-gate }
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate * Yet another disgusting argument parsing function (TM). We attempt to parse
2210Sstevel@tonic-gate * a time argument in a variety of strptime(3C) formats, in which case it is
2220Sstevel@tonic-gate * interpreted as a local time and is converted to a timeval using mktime(3C).
2230Sstevel@tonic-gate * If those formats fail, we look to see if the time is a decimal integer
2240Sstevel@tonic-gate * followed by one of our magic suffixes, in which case the time is interpreted
2250Sstevel@tonic-gate * as a time delta *before* the current time-of-day (i.e. "1h" = "1 hour ago").
2260Sstevel@tonic-gate */
2270Sstevel@tonic-gate static struct timeval *
gettimeopt(const char * arg)2280Sstevel@tonic-gate gettimeopt(const char *arg)
2290Sstevel@tonic-gate {
2300Sstevel@tonic-gate const struct {
2310Sstevel@tonic-gate const char *name;
2320Sstevel@tonic-gate hrtime_t mul;
2330Sstevel@tonic-gate } suffix[] = {
2346640Scth { "ns", NANOSEC / NANOSEC },
2350Sstevel@tonic-gate { "nsec", NANOSEC / NANOSEC },
2360Sstevel@tonic-gate { "us", NANOSEC / MICROSEC },
2370Sstevel@tonic-gate { "usec", NANOSEC / MICROSEC },
2380Sstevel@tonic-gate { "ms", NANOSEC / MILLISEC },
2390Sstevel@tonic-gate { "msec", NANOSEC / MILLISEC },
2400Sstevel@tonic-gate { "s", NANOSEC / SEC },
2410Sstevel@tonic-gate { "sec", NANOSEC / SEC },
2420Sstevel@tonic-gate { "m", NANOSEC * (hrtime_t)60 },
2430Sstevel@tonic-gate { "min", NANOSEC * (hrtime_t)60 },
2440Sstevel@tonic-gate { "h", NANOSEC * (hrtime_t)(60 * 60) },
2450Sstevel@tonic-gate { "hour", NANOSEC * (hrtime_t)(60 * 60) },
2460Sstevel@tonic-gate { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) },
2470Sstevel@tonic-gate { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) },
2480Sstevel@tonic-gate { NULL }
2490Sstevel@tonic-gate };
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate struct timeval *tvp = malloc(sizeof (struct timeval));
2520Sstevel@tonic-gate struct timeval tod;
2530Sstevel@tonic-gate struct tm tm;
2540Sstevel@tonic-gate char *p;
2550Sstevel@tonic-gate
256*12967Sgavin.maltby@oracle.com if (tvp == NULL)
257*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
2580Sstevel@tonic-gate
259*12967Sgavin.maltby@oracle.com if (gettimeofday(&tod, NULL) != 0)
260*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to get tod");
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate * First try a variety of strptime() calls. If these all fail, we'll
2640Sstevel@tonic-gate * try parsing an integer followed by one of our suffix[] strings.
2650Sstevel@tonic-gate * NOTE: any form using %y must appear *before* the equivalent %Y form;
2660Sstevel@tonic-gate * otherwise %Y will accept the two year digits but infer century zero.
2670Sstevel@tonic-gate * Any form ending in %y must additionally check isdigit(*p) to ensure
2680Sstevel@tonic-gate * that it does not inadvertently match 2 digits of a 4-digit year.
2690Sstevel@tonic-gate *
2700Sstevel@tonic-gate * Beware: Any strptime() sequence containing consecutive %x sequences
2710Sstevel@tonic-gate * may fall victim to SCCS expanding it as a keyword! If this happens
2720Sstevel@tonic-gate * we use separate string constant that ANSI C will concatenate.
2730Sstevel@tonic-gate */
2740Sstevel@tonic-gate if ((p = strptime(arg, "%m/%d/%y" "%t" "%H:%M:%S", &tm)) == NULL &&
2750Sstevel@tonic-gate (p = strptime(arg, "%m/%d/%Y" "%t" "%H:%M:%S", &tm)) == NULL &&
2760Sstevel@tonic-gate (p = strptime(arg, "%m/%d/%y" "%t" "%H:%M", &tm)) == NULL &&
2770Sstevel@tonic-gate (p = strptime(arg, "%m/%d/%Y" "%t" "%H:%M", &tm)) == NULL &&
2780Sstevel@tonic-gate ((p = strptime(arg, "%m/%d/%y", &tm)) == NULL || isdigit(*p)) &&
2790Sstevel@tonic-gate (p = strptime(arg, "%m/%d/%Y", &tm)) == NULL &&
2800Sstevel@tonic-gate (p = strptime(arg, "%y-%m-%dT%H:%M:%S", &tm)) == NULL &&
2810Sstevel@tonic-gate (p = strptime(arg, "%Y-%m-%dT%H:%M:%S", &tm)) == NULL &&
2820Sstevel@tonic-gate (p = strptime(arg, "%y-%m-%dT%H:%M", &tm)) == NULL &&
2830Sstevel@tonic-gate (p = strptime(arg, "%Y-%m-%dT%H:%M", &tm)) == NULL &&
2840Sstevel@tonic-gate (p = strptime(arg, "%y-%m-%d", &tm)) == NULL &&
2850Sstevel@tonic-gate (p = strptime(arg, "%Y-%m-%d", &tm)) == NULL &&
2860Sstevel@tonic-gate (p = strptime(arg, "%d%b%y" "%t" "%H:%M:%S", &tm)) == NULL &&
2870Sstevel@tonic-gate (p = strptime(arg, "%d%b%Y" "%t" "%H:%M:%S", &tm)) == NULL &&
2880Sstevel@tonic-gate (p = strptime(arg, "%d%b%y" "%t" "%H:%M", &tm)) == NULL &&
2890Sstevel@tonic-gate (p = strptime(arg, "%d%b%Y" "%t" "%H:%M", &tm)) == NULL &&
2900Sstevel@tonic-gate ((p = strptime(arg, "%d%b%y", &tm)) == NULL || isdigit(*p)) &&
2910Sstevel@tonic-gate (p = strptime(arg, "%d%b%Y", &tm)) == NULL &&
2920Sstevel@tonic-gate (p = strptime(arg, "%b%t%d" "%t" "%H:%M:%S", &tm)) == NULL &&
2930Sstevel@tonic-gate (p = strptime(arg, "%b%t%d" "%t" "%H:%M:%S", &tm)) == NULL &&
2940Sstevel@tonic-gate (p = strptime(arg, "%H:%M:%S", &tm)) == NULL &&
2950Sstevel@tonic-gate (p = strptime(arg, "%H:%M", &tm)) == NULL) {
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate hrtime_t nsec;
2980Sstevel@tonic-gate int i;
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate errno = 0;
3010Sstevel@tonic-gate nsec = strtol(arg, (char **)&p, 10);
3020Sstevel@tonic-gate
303*12967Sgavin.maltby@oracle.com if (errno != 0 || nsec == 0 || p == arg || *p == '\0')
304*12967Sgavin.maltby@oracle.com fmdump_usage("illegal time format -- %s\n", arg);
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate for (i = 0; suffix[i].name != NULL; i++) {
3070Sstevel@tonic-gate if (strcasecmp(suffix[i].name, p) == 0) {
3080Sstevel@tonic-gate nsec *= suffix[i].mul;
3090Sstevel@tonic-gate break;
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate }
3120Sstevel@tonic-gate
313*12967Sgavin.maltby@oracle.com if (suffix[i].name == NULL)
314*12967Sgavin.maltby@oracle.com fmdump_usage("illegal time format -- %s\n", arg);
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate tvp->tv_sec = nsec / NANOSEC;
3170Sstevel@tonic-gate tvp->tv_usec = (nsec % NANOSEC) / (NANOSEC / MICROSEC);
3180Sstevel@tonic-gate
319*12967Sgavin.maltby@oracle.com if (tvp->tv_sec > tod.tv_sec)
320*12967Sgavin.maltby@oracle.com fmdump_usage("time delta precedes UTC time origin "
321*12967Sgavin.maltby@oracle.com "-- %s\n", arg);
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate tvp->tv_sec = tod.tv_sec - tvp->tv_sec;
3240Sstevel@tonic-gate
3250Sstevel@tonic-gate } else if (*p == '\0' || *p == '.') {
3260Sstevel@tonic-gate /*
3270Sstevel@tonic-gate * If tm_year is zero, we matched [%b %d] %H:%M[:%S]; use
3280Sstevel@tonic-gate * the result of localtime(&tod.tv_sec) to fill in the rest.
3290Sstevel@tonic-gate */
3300Sstevel@tonic-gate if (tm.tm_year == 0) {
3310Sstevel@tonic-gate int h = tm.tm_hour;
3320Sstevel@tonic-gate int m = tm.tm_min;
3330Sstevel@tonic-gate int s = tm.tm_sec;
3340Sstevel@tonic-gate int b = tm.tm_mon;
3350Sstevel@tonic-gate int d = tm.tm_mday;
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate bcopy(localtime(&tod.tv_sec), &tm, sizeof (tm));
3380Sstevel@tonic-gate tm.tm_isdst = 0; /* see strptime(3C) and below */
3390Sstevel@tonic-gate
3400Sstevel@tonic-gate if (d > 0) {
3410Sstevel@tonic-gate tm.tm_mon = b;
3420Sstevel@tonic-gate tm.tm_mday = d;
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate
3450Sstevel@tonic-gate tm.tm_hour = h;
3460Sstevel@tonic-gate tm.tm_min = m;
3470Sstevel@tonic-gate tm.tm_sec = s;
3480Sstevel@tonic-gate }
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate errno = 0;
3510Sstevel@tonic-gate tvp->tv_sec = mktime(&tm);
3520Sstevel@tonic-gate tvp->tv_usec = 0;
3530Sstevel@tonic-gate
354*12967Sgavin.maltby@oracle.com if (tvp->tv_sec == -1L && errno != 0)
355*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to compose time %s", arg);
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate * If our mktime() set tm_isdst, adjust the result for DST by
3590Sstevel@tonic-gate * subtracting the offset between the main and alternate zones.
3600Sstevel@tonic-gate */
3610Sstevel@tonic-gate if (tm.tm_isdst)
3620Sstevel@tonic-gate tvp->tv_sec -= timezone - altzone;
3630Sstevel@tonic-gate
3640Sstevel@tonic-gate if (p[0] == '.') {
3650Sstevel@tonic-gate arg = p;
3660Sstevel@tonic-gate errno = 0;
3670Sstevel@tonic-gate tvp->tv_usec =
3680Sstevel@tonic-gate (suseconds_t)(strtod(arg, &p) * (double)MICROSEC);
3690Sstevel@tonic-gate
370*12967Sgavin.maltby@oracle.com if (errno != 0 || p == arg || *p != '\0')
371*12967Sgavin.maltby@oracle.com fmdump_usage("illegal time suffix -- .%s\n",
372*12967Sgavin.maltby@oracle.com arg);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate
3750Sstevel@tonic-gate } else {
376*12967Sgavin.maltby@oracle.com fmdump_usage("unexpected suffix after time %s -- %s\n", arg, p);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate
3790Sstevel@tonic-gate return (tvp);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate /*
3830Sstevel@tonic-gate * If the -u option is specified in combination with the -e option, we iterate
3840Sstevel@tonic-gate * over each record in the fault log with a matching UUID finding xrefs to the
3850Sstevel@tonic-gate * error log, and then use this function to iterate over every xref'd record.
3860Sstevel@tonic-gate */
3870Sstevel@tonic-gate int
xref_iter(fmd_log_t * lp,const fmd_log_record_t * rp,void * arg)3880Sstevel@tonic-gate xref_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate const fmd_log_record_t *xrp = rp->rec_xrefs;
3910Sstevel@tonic-gate fmdump_arg_t *dap = arg;
3920Sstevel@tonic-gate int i, rv = 0;
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate for (i = 0; rv == 0 && i < rp->rec_nrefs; i++, xrp++) {
3950Sstevel@tonic-gate if (fmd_log_filter(lp, dap->da_fc, dap->da_fv, xrp))
3960Sstevel@tonic-gate rv = dap->da_fmt->do_func(lp, xrp, dap->da_fp);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate return (rv);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate int
xoff_iter(fmd_log_t * lp,const fmd_log_record_t * rp,void * arg)4030Sstevel@tonic-gate xoff_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate fmdump_lyr_t *dyp = arg;
4060Sstevel@tonic-gate
4070Sstevel@tonic-gate fmdump_printf(dyp->dy_fp, "%16llx ", (u_longlong_t)rp->rec_off);
4080Sstevel@tonic-gate return (dyp->dy_func(lp, rp, dyp->dy_arg));
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate /*
4126640Scth * Initialize fmd_log_filter_nvarg_t from -n name=value argument string.
4136640Scth */
4146640Scth static fmd_log_filter_nvarg_t *
setupnamevalue(char * namevalue)4156640Scth setupnamevalue(char *namevalue)
4166640Scth {
4176640Scth fmd_log_filter_nvarg_t *argt;
4186640Scth char *value;
4196640Scth regex_t *value_regex = NULL;
4206640Scth char errstr[128];
4216640Scth int rv;
4226640Scth
4236640Scth if ((value = strchr(namevalue, '=')) == NULL) {
4246640Scth value_regex = NULL;
4256640Scth } else {
4266640Scth *value++ = '\0'; /* separate name and value string */
4276640Scth
4286640Scth /*
4296640Scth * Skip white space before value to facilitate direct
4306640Scth * cut/paste from previous fmdump output.
4316640Scth */
4326640Scth while (isspace(*value))
4336640Scth value++;
4346640Scth
435*12967Sgavin.maltby@oracle.com if ((value_regex = malloc(sizeof (regex_t))) == NULL)
436*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
4376640Scth
4386640Scth /* compile regular expression for possible string match */
4396640Scth if ((rv = regcomp(value_regex, value,
4406640Scth REG_NOSUB|REG_NEWLINE)) != 0) {
4416640Scth (void) regerror(rv, value_regex, errstr,
4426640Scth sizeof (errstr));
4436640Scth free(value_regex);
444*12967Sgavin.maltby@oracle.com fmdump_usage("unexpected regular expression in "
445*12967Sgavin.maltby@oracle.com "%s: %s\n", value, errstr);
4466640Scth }
4476640Scth }
4486640Scth
449*12967Sgavin.maltby@oracle.com if ((argt = malloc(sizeof (fmd_log_filter_nvarg_t))) == NULL)
450*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
451*12967Sgavin.maltby@oracle.com
4526640Scth argt->nvarg_name = namevalue; /* now just name */
4536640Scth argt->nvarg_value = value;
4546640Scth argt->nvarg_value_regex = value_regex;
4556640Scth return (argt);
4566640Scth }
4576640Scth
4586640Scth /*
4590Sstevel@tonic-gate * If the -a option is not present, filter out fault records that correspond
4600Sstevel@tonic-gate * to events that the producer requested not be messaged for administrators.
4610Sstevel@tonic-gate */
4620Sstevel@tonic-gate /*ARGSUSED*/
4630Sstevel@tonic-gate int
log_filter_silent(fmd_log_t * lp,const fmd_log_record_t * rp,void * arg)4640Sstevel@tonic-gate log_filter_silent(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
4650Sstevel@tonic-gate {
466*12967Sgavin.maltby@oracle.com int opt_A = (arg != NULL);
4670Sstevel@tonic-gate boolean_t msg;
468*12967Sgavin.maltby@oracle.com char *class;
469*12967Sgavin.maltby@oracle.com
470*12967Sgavin.maltby@oracle.com /*
471*12967Sgavin.maltby@oracle.com * If -A was used then apply this filter only to events of list class
472*12967Sgavin.maltby@oracle.com */
473*12967Sgavin.maltby@oracle.com if (opt_A) {
474*12967Sgavin.maltby@oracle.com if (nvlist_lookup_string(rp->rec_nvl, FM_CLASS, &class) != 0 ||
475*12967Sgavin.maltby@oracle.com strncmp(class, FM_LIST_EVENT ".",
476*12967Sgavin.maltby@oracle.com sizeof (FM_LIST_EVENT)) != 0)
477*12967Sgavin.maltby@oracle.com return (1);
478*12967Sgavin.maltby@oracle.com }
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate return (nvlist_lookup_boolean_value(rp->rec_nvl,
4810Sstevel@tonic-gate FM_SUSPECT_MESSAGE, &msg) != 0 || msg != 0);
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate
4848740SSean.Ye@Sun.COM struct loglink {
485*12967Sgavin.maltby@oracle.com char *path;
4868740SSean.Ye@Sun.COM long suffix;
4878740SSean.Ye@Sun.COM struct loglink *next;
4888740SSean.Ye@Sun.COM };
4898740SSean.Ye@Sun.COM
4908740SSean.Ye@Sun.COM static void
addlink(struct loglink ** llp,char * dirname,char * logname,long suffix)4918740SSean.Ye@Sun.COM addlink(struct loglink **llp, char *dirname, char *logname, long suffix)
4928740SSean.Ye@Sun.COM {
4938740SSean.Ye@Sun.COM struct loglink *newp;
4948740SSean.Ye@Sun.COM size_t len;
4958740SSean.Ye@Sun.COM char *str;
4968740SSean.Ye@Sun.COM
4978740SSean.Ye@Sun.COM newp = malloc(sizeof (struct loglink));
4988740SSean.Ye@Sun.COM len = strlen(dirname) + strlen(logname) + 2;
4998740SSean.Ye@Sun.COM str = malloc(len);
500*12967Sgavin.maltby@oracle.com if (newp == NULL || str == NULL)
501*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
5028740SSean.Ye@Sun.COM
5038740SSean.Ye@Sun.COM (void) snprintf(str, len, "%s/%s", dirname, logname);
5048740SSean.Ye@Sun.COM newp->path = str;
5058740SSean.Ye@Sun.COM newp->suffix = suffix;
5068740SSean.Ye@Sun.COM
5078740SSean.Ye@Sun.COM while (*llp != NULL && suffix < (*llp)->suffix)
5088740SSean.Ye@Sun.COM llp = &(*llp)->next;
5098740SSean.Ye@Sun.COM
5108740SSean.Ye@Sun.COM newp->next = *llp;
5118740SSean.Ye@Sun.COM *llp = newp;
5128740SSean.Ye@Sun.COM }
5138740SSean.Ye@Sun.COM
5148740SSean.Ye@Sun.COM /*
5158740SSean.Ye@Sun.COM * Find and return all the rotated logs.
5168740SSean.Ye@Sun.COM */
5178740SSean.Ye@Sun.COM static struct loglink *
get_rotated_logs(char * logpath)5188740SSean.Ye@Sun.COM get_rotated_logs(char *logpath)
5198740SSean.Ye@Sun.COM {
5208740SSean.Ye@Sun.COM char dirname[PATH_MAX], *logname, *endptr;
5218740SSean.Ye@Sun.COM DIR *dirp;
5228740SSean.Ye@Sun.COM struct dirent *dp;
5238740SSean.Ye@Sun.COM long len, suffix;
5248740SSean.Ye@Sun.COM struct loglink *head = NULL;
5258740SSean.Ye@Sun.COM
5268740SSean.Ye@Sun.COM (void) strlcpy(dirname, logpath, sizeof (dirname));
5278740SSean.Ye@Sun.COM logname = strrchr(dirname, '/');
5288740SSean.Ye@Sun.COM *logname++ = '\0';
5298740SSean.Ye@Sun.COM len = strlen(logname);
5308740SSean.Ye@Sun.COM
5318740SSean.Ye@Sun.COM if ((dirp = opendir(dirname)) == NULL) {
532*12967Sgavin.maltby@oracle.com fmdump_warn("failed to opendir `%s'", dirname);
533*12967Sgavin.maltby@oracle.com g_errs++;
5348740SSean.Ye@Sun.COM return (NULL);
5358740SSean.Ye@Sun.COM }
5368740SSean.Ye@Sun.COM
5378740SSean.Ye@Sun.COM while ((dp = readdir(dirp)) != NULL) {
5388740SSean.Ye@Sun.COM /*
5398740SSean.Ye@Sun.COM * Search the log directory for logs named "<logname>.0",
5408740SSean.Ye@Sun.COM * "<logname>.1", etc and add to the link in the
5418740SSean.Ye@Sun.COM * reverse numeric order.
5428740SSean.Ye@Sun.COM */
5438740SSean.Ye@Sun.COM if (strlen(dp->d_name) < len + 2 ||
5448740SSean.Ye@Sun.COM strncmp(dp->d_name, logname, len) != 0 ||
5458740SSean.Ye@Sun.COM dp->d_name[len] != '.')
5468740SSean.Ye@Sun.COM continue;
5478740SSean.Ye@Sun.COM
5488740SSean.Ye@Sun.COM /*
5498740SSean.Ye@Sun.COM * "*.0-" file normally should not be seen. It may
5508740SSean.Ye@Sun.COM * exist when user manually run 'fmadm rotate'.
5518740SSean.Ye@Sun.COM * In such case, we put it at the end of the list so
5528740SSean.Ye@Sun.COM * it'll be dumped after all the rotated logs, before
5538740SSean.Ye@Sun.COM * the current one.
5548740SSean.Ye@Sun.COM */
5558740SSean.Ye@Sun.COM if (strcmp(dp->d_name + len + 1, "0-") == 0)
5568740SSean.Ye@Sun.COM addlink(&head, dirname, dp->d_name, -1);
5578740SSean.Ye@Sun.COM else if ((suffix = strtol(dp->d_name + len + 1,
5588740SSean.Ye@Sun.COM &endptr, 10)) >= 0 && *endptr == '\0')
5598740SSean.Ye@Sun.COM addlink(&head, dirname, dp->d_name, suffix);
5608740SSean.Ye@Sun.COM }
5618740SSean.Ye@Sun.COM
5628740SSean.Ye@Sun.COM (void) closedir(dirp);
5638740SSean.Ye@Sun.COM
5648740SSean.Ye@Sun.COM return (head);
5658740SSean.Ye@Sun.COM }
5668740SSean.Ye@Sun.COM
567*12967Sgavin.maltby@oracle.com /*
568*12967Sgavin.maltby@oracle.com * Aggregate log files. If ifiles is not NULL then one or more files
569*12967Sgavin.maltby@oracle.com * were listed on the command line, and we will merge just those files.
570*12967Sgavin.maltby@oracle.com * Otherwise we will merge all known log file types, and include the
571*12967Sgavin.maltby@oracle.com * rotated logs for each type (you can suppress the inclusion of
572*12967Sgavin.maltby@oracle.com * some logtypes through use of FMDUMP_AGGREGATE_IGNORE in the process
573*12967Sgavin.maltby@oracle.com * environment, setting it to a comma-separated list of log labels and/or
574*12967Sgavin.maltby@oracle.com * log filenames to ignore).
575*12967Sgavin.maltby@oracle.com *
576*12967Sgavin.maltby@oracle.com * We will not attempt to perform a chronological sort across all log records
577*12967Sgavin.maltby@oracle.com * of all files. Indeed, we won't even sort individual log files -
578*12967Sgavin.maltby@oracle.com * we will not re-order events differently to how they appeared in their
579*12967Sgavin.maltby@oracle.com * original log file. This is because log files are already inherently
580*12967Sgavin.maltby@oracle.com * ordered by the order in which fmd receives and processes events.
581*12967Sgavin.maltby@oracle.com * So we determine the output order by comparing the "next" record
582*12967Sgavin.maltby@oracle.com * off the top of each log file.
583*12967Sgavin.maltby@oracle.com *
584*12967Sgavin.maltby@oracle.com * We will construct a number of log record source "pipelines". As above,
585*12967Sgavin.maltby@oracle.com * the next record to render in the overall output is that from the
586*12967Sgavin.maltby@oracle.com * pipeline with the oldest event.
587*12967Sgavin.maltby@oracle.com *
588*12967Sgavin.maltby@oracle.com * For the case that input logfiles were listed on the command line, each
589*12967Sgavin.maltby@oracle.com * pipeline will process exactly one of those logfiles. Distinct pipelines
590*12967Sgavin.maltby@oracle.com * may process logfiles of the same "type" - eg if two "error" logs and
591*12967Sgavin.maltby@oracle.com * one "fault" logs are specified then there'll be two pipelines producing
592*12967Sgavin.maltby@oracle.com * events from "error" logs.
593*12967Sgavin.maltby@oracle.com *
594*12967Sgavin.maltby@oracle.com * If we are merging all known log types then we will construct exactly
595*12967Sgavin.maltby@oracle.com * one pipeline for each known log type - one for error, one for fault, etc.
596*12967Sgavin.maltby@oracle.com * Each pipeline will process first the rotated logs of that type and then
597*12967Sgavin.maltby@oracle.com * move on to the current log of that type.
598*12967Sgavin.maltby@oracle.com *
599*12967Sgavin.maltby@oracle.com * The output from all pipelines flows into a serializer which selects
600*12967Sgavin.maltby@oracle.com * the next record once all pipelines have asserted their output state.
601*12967Sgavin.maltby@oracle.com * The output state of a pipeline is one of:
602*12967Sgavin.maltby@oracle.com *
603*12967Sgavin.maltby@oracle.com * - record available: the next record from this pipeline is available
604*12967Sgavin.maltby@oracle.com * for comparison and consumption
605*12967Sgavin.maltby@oracle.com *
606*12967Sgavin.maltby@oracle.com * - done: this pipeline will produce no more records
607*12967Sgavin.maltby@oracle.com *
608*12967Sgavin.maltby@oracle.com * - polling: this pipeline is polling for new records and will
609*12967Sgavin.maltby@oracle.com * make them available as output if/when any are observed
610*12967Sgavin.maltby@oracle.com *
611*12967Sgavin.maltby@oracle.com * - processing: output state will be updated shortly
612*12967Sgavin.maltby@oracle.com *
613*12967Sgavin.maltby@oracle.com * A pipeline iterates over each file queued to it using fmd_log_xiter.
614*12967Sgavin.maltby@oracle.com * We do this in a separate thread for each pipeline. The callback on
615*12967Sgavin.maltby@oracle.com * each iteration must update the serializer to let it know that
616*12967Sgavin.maltby@oracle.com * a new record is available. In the serializer thread we decide whether
617*12967Sgavin.maltby@oracle.com * we have all records expected have arrived and it is time to choose
618*12967Sgavin.maltby@oracle.com * the next output record.
619*12967Sgavin.maltby@oracle.com */
620*12967Sgavin.maltby@oracle.com
621*12967Sgavin.maltby@oracle.com /*
622*12967Sgavin.maltby@oracle.com * A pipeline descriptor. The pl_cv condition variable is used together
623*12967Sgavin.maltby@oracle.com * with pl_lock for initial synchronisation, and thereafter with the
624*12967Sgavin.maltby@oracle.com * lock for the serializer for pausing and continuing this pipeline.
625*12967Sgavin.maltby@oracle.com */
626*12967Sgavin.maltby@oracle.com struct fmdump_pipeline {
627*12967Sgavin.maltby@oracle.com pthread_mutex_t pl_lock; /* used only in pipeline startup */
628*12967Sgavin.maltby@oracle.com int pl_started; /* sync with main thread on startup */
629*12967Sgavin.maltby@oracle.com pthread_t pl_thr; /* our processing thread */
630*12967Sgavin.maltby@oracle.com pthread_cond_t pl_cv; /* see above */
631*12967Sgavin.maltby@oracle.com struct loglink *pl_rotated; /* rotated logs to process first */
632*12967Sgavin.maltby@oracle.com char *pl_logpath; /* target path to process */
633*12967Sgavin.maltby@oracle.com char *pl_processing; /* path currently being processed */
634*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *pl_srlzer; /* link to serializer */
635*12967Sgavin.maltby@oracle.com int pl_srlzeridx; /* serializer index for this pipeline */
636*12967Sgavin.maltby@oracle.com const fmdump_ops_t *pl_ops; /* ops for the log type we're given */
637*12967Sgavin.maltby@oracle.com int pl_fmt; /* FMDUMP_{SHORT,VERB1,VERB2,PRETTY} */
638*12967Sgavin.maltby@oracle.com boolean_t pl_follow; /* go into poll mode at log end */
639*12967Sgavin.maltby@oracle.com fmdump_arg_t pl_arg; /* arguments */
640*12967Sgavin.maltby@oracle.com };
641*12967Sgavin.maltby@oracle.com
642*12967Sgavin.maltby@oracle.com enum fmdump_pipestate {
643*12967Sgavin.maltby@oracle.com FMDUMP_PIPE_PROCESSING = 0x1000,
644*12967Sgavin.maltby@oracle.com FMDUMP_PIPE_RECORDAVAIL,
645*12967Sgavin.maltby@oracle.com FMDUMP_PIPE_POLLING,
646*12967Sgavin.maltby@oracle.com FMDUMP_PIPE_DONE
647*12967Sgavin.maltby@oracle.com };
648*12967Sgavin.maltby@oracle.com
649*12967Sgavin.maltby@oracle.com /*
650*12967Sgavin.maltby@oracle.com * Each pipeline has an associated output slot in the serializer. This
651*12967Sgavin.maltby@oracle.com * must be updated with the serializer locked. After update evaluate
652*12967Sgavin.maltby@oracle.com * whether there are enough slots decided that we should select a
653*12967Sgavin.maltby@oracle.com * record to output.
654*12967Sgavin.maltby@oracle.com */
655*12967Sgavin.maltby@oracle.com struct fmdump_srlzer_slot {
656*12967Sgavin.maltby@oracle.com enum fmdump_pipestate ss_state;
657*12967Sgavin.maltby@oracle.com uint64_t ss_sec;
658*12967Sgavin.maltby@oracle.com uint64_t ss_nsec;
659*12967Sgavin.maltby@oracle.com };
660*12967Sgavin.maltby@oracle.com
661*12967Sgavin.maltby@oracle.com /*
662*12967Sgavin.maltby@oracle.com * All pipelines are linked to a single serializer. The serializer
663*12967Sgavin.maltby@oracle.com * structure must be updated under the ds_lock; this mutex is also
664*12967Sgavin.maltby@oracle.com * paired with the pl_cv of individual pipelines (one mutex, many condvars)
665*12967Sgavin.maltby@oracle.com * in pausing and continuing individual pipelines.
666*12967Sgavin.maltby@oracle.com */
667*12967Sgavin.maltby@oracle.com struct fmdump_srlzer {
668*12967Sgavin.maltby@oracle.com struct fmdump_pipeline *ds_pipearr; /* pipeline array */
669*12967Sgavin.maltby@oracle.com pthread_mutex_t ds_lock; /* see above */
670*12967Sgavin.maltby@oracle.com uint32_t ds_pipecnt; /* number of pipelines */
671*12967Sgavin.maltby@oracle.com uint32_t ds_pollcnt; /* pipelines in poll mode */
672*12967Sgavin.maltby@oracle.com uint32_t ds_nrecordavail; /* pipelines with a record */
673*12967Sgavin.maltby@oracle.com uint32_t ds_ndone; /* completed pipelines */
674*12967Sgavin.maltby@oracle.com struct fmdump_srlzer_slot *ds_slot; /* slot array */
675*12967Sgavin.maltby@oracle.com };
676*12967Sgavin.maltby@oracle.com
677*12967Sgavin.maltby@oracle.com /*
678*12967Sgavin.maltby@oracle.com * All known log types. When aggregation is requested an no file list
679*12967Sgavin.maltby@oracle.com * is provided we will process the logs identified here (if lt_enabled
680*12967Sgavin.maltby@oracle.com * is true and not over-ridden by environment settings). We also
681*12967Sgavin.maltby@oracle.com * use this in determining the appropriate ops structure for each distinct
682*12967Sgavin.maltby@oracle.com * label.
683*12967Sgavin.maltby@oracle.com */
684*12967Sgavin.maltby@oracle.com static struct fmdump_logtype {
685*12967Sgavin.maltby@oracle.com const char *lt_label; /* label from log header */
686*12967Sgavin.maltby@oracle.com boolean_t lt_enabled; /* include in merge? */
687*12967Sgavin.maltby@oracle.com const char *lt_logname; /* var/fm/fmd/%s */
688*12967Sgavin.maltby@oracle.com const fmdump_ops_t *lt_ops;
689*12967Sgavin.maltby@oracle.com } logtypes[] = {
690*12967Sgavin.maltby@oracle.com {
691*12967Sgavin.maltby@oracle.com "error",
692*12967Sgavin.maltby@oracle.com B_TRUE,
693*12967Sgavin.maltby@oracle.com "errlog",
694*12967Sgavin.maltby@oracle.com &fmdump_err_ops
695*12967Sgavin.maltby@oracle.com },
696*12967Sgavin.maltby@oracle.com {
697*12967Sgavin.maltby@oracle.com "fault",
698*12967Sgavin.maltby@oracle.com B_TRUE,
699*12967Sgavin.maltby@oracle.com "fltlog",
700*12967Sgavin.maltby@oracle.com &fmdump_flt_ops
701*12967Sgavin.maltby@oracle.com },
702*12967Sgavin.maltby@oracle.com {
703*12967Sgavin.maltby@oracle.com "info",
704*12967Sgavin.maltby@oracle.com B_TRUE,
705*12967Sgavin.maltby@oracle.com "infolog",
706*12967Sgavin.maltby@oracle.com &fmdump_info_ops
707*12967Sgavin.maltby@oracle.com },
708*12967Sgavin.maltby@oracle.com {
709*12967Sgavin.maltby@oracle.com "info",
710*12967Sgavin.maltby@oracle.com B_TRUE,
711*12967Sgavin.maltby@oracle.com "infolog_hival",
712*12967Sgavin.maltby@oracle.com &fmdump_info_ops
713*12967Sgavin.maltby@oracle.com },
714*12967Sgavin.maltby@oracle.com {
715*12967Sgavin.maltby@oracle.com "asru",
716*12967Sgavin.maltby@oracle.com B_FALSE, /* not included unless in file list */
717*12967Sgavin.maltby@oracle.com NULL,
718*12967Sgavin.maltby@oracle.com &fmdump_asru_ops /* but we need ops when it is */
719*12967Sgavin.maltby@oracle.com }
720*12967Sgavin.maltby@oracle.com };
721*12967Sgavin.maltby@oracle.com
722*12967Sgavin.maltby@oracle.com /*
723*12967Sgavin.maltby@oracle.com * Disable logtypes per environment setting. Does not apply when a list
724*12967Sgavin.maltby@oracle.com * of logs is provided on the command line.
725*12967Sgavin.maltby@oracle.com */
726*12967Sgavin.maltby@oracle.com static void
do_disables(void)727*12967Sgavin.maltby@oracle.com do_disables(void)
728*12967Sgavin.maltby@oracle.com {
729*12967Sgavin.maltby@oracle.com char *env = getenv("FMDUMP_AGGREGATE_IGNORE");
730*12967Sgavin.maltby@oracle.com char *dup, *start, *tofree;
731*12967Sgavin.maltby@oracle.com int i;
732*12967Sgavin.maltby@oracle.com
733*12967Sgavin.maltby@oracle.com if (env == NULL)
734*12967Sgavin.maltby@oracle.com return;
735*12967Sgavin.maltby@oracle.com
736*12967Sgavin.maltby@oracle.com tofree = dup = strdup(env);
737*12967Sgavin.maltby@oracle.com
738*12967Sgavin.maltby@oracle.com while (dup != NULL) {
739*12967Sgavin.maltby@oracle.com start = strsep(&dup, ",");
740*12967Sgavin.maltby@oracle.com for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) {
741*12967Sgavin.maltby@oracle.com if (logtypes[i].lt_logname == NULL)
742*12967Sgavin.maltby@oracle.com continue;
743*12967Sgavin.maltby@oracle.com
744*12967Sgavin.maltby@oracle.com if (strcmp(start, logtypes[i].lt_label) == 0 ||
745*12967Sgavin.maltby@oracle.com strcmp(start, logtypes[i].lt_logname) == 0) {
746*12967Sgavin.maltby@oracle.com logtypes[i].lt_enabled = B_FALSE;
747*12967Sgavin.maltby@oracle.com }
748*12967Sgavin.maltby@oracle.com }
749*12967Sgavin.maltby@oracle.com }
750*12967Sgavin.maltby@oracle.com
751*12967Sgavin.maltby@oracle.com free(tofree);
752*12967Sgavin.maltby@oracle.com }
753*12967Sgavin.maltby@oracle.com
754*12967Sgavin.maltby@oracle.com static void
srlzer_enter(struct fmdump_pipeline * pl)755*12967Sgavin.maltby@oracle.com srlzer_enter(struct fmdump_pipeline *pl)
756*12967Sgavin.maltby@oracle.com {
757*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *srlzer = pl->pl_srlzer;
758*12967Sgavin.maltby@oracle.com
759*12967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&srlzer->ds_lock);
760*12967Sgavin.maltby@oracle.com }
761*12967Sgavin.maltby@oracle.com
762*12967Sgavin.maltby@oracle.com static void
srlzer_exit(struct fmdump_pipeline * pl)763*12967Sgavin.maltby@oracle.com srlzer_exit(struct fmdump_pipeline *pl)
764*12967Sgavin.maltby@oracle.com {
765*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *srlzer = pl->pl_srlzer;
766*12967Sgavin.maltby@oracle.com
767*12967Sgavin.maltby@oracle.com ASSERT(MUTEX_HELD(&srlzer->ds_lock));
768*12967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&srlzer->ds_lock);
769*12967Sgavin.maltby@oracle.com }
770*12967Sgavin.maltby@oracle.com
771*12967Sgavin.maltby@oracle.com static struct fmdump_pipeline *
srlzer_choose(struct fmdump_srlzer * srlzer)772*12967Sgavin.maltby@oracle.com srlzer_choose(struct fmdump_srlzer *srlzer)
773*12967Sgavin.maltby@oracle.com {
774*12967Sgavin.maltby@oracle.com struct fmdump_srlzer_slot *slot, *oldest;
775*12967Sgavin.maltby@oracle.com int oldestidx = -1;
776*12967Sgavin.maltby@oracle.com int first = 1;
777*12967Sgavin.maltby@oracle.com int i;
778*12967Sgavin.maltby@oracle.com
779*12967Sgavin.maltby@oracle.com ASSERT(MUTEX_HELD(&srlzer->ds_lock));
780*12967Sgavin.maltby@oracle.com
781*12967Sgavin.maltby@oracle.com for (i = 0, slot = &srlzer->ds_slot[0]; i < srlzer->ds_pipecnt;
782*12967Sgavin.maltby@oracle.com i++, slot++) {
783*12967Sgavin.maltby@oracle.com if (slot->ss_state != FMDUMP_PIPE_RECORDAVAIL)
784*12967Sgavin.maltby@oracle.com continue;
785*12967Sgavin.maltby@oracle.com
786*12967Sgavin.maltby@oracle.com if (first) {
787*12967Sgavin.maltby@oracle.com oldest = slot;
788*12967Sgavin.maltby@oracle.com oldestidx = i;
789*12967Sgavin.maltby@oracle.com first = 0;
790*12967Sgavin.maltby@oracle.com continue;
791*12967Sgavin.maltby@oracle.com }
792*12967Sgavin.maltby@oracle.com
793*12967Sgavin.maltby@oracle.com if (slot->ss_sec < oldest->ss_sec ||
794*12967Sgavin.maltby@oracle.com slot->ss_sec == oldest->ss_sec &&
795*12967Sgavin.maltby@oracle.com slot->ss_nsec < oldest->ss_nsec) {
796*12967Sgavin.maltby@oracle.com oldest = slot;
797*12967Sgavin.maltby@oracle.com oldestidx = i;
798*12967Sgavin.maltby@oracle.com }
799*12967Sgavin.maltby@oracle.com }
800*12967Sgavin.maltby@oracle.com
801*12967Sgavin.maltby@oracle.com return (oldestidx >= 0 ? &srlzer->ds_pipearr[oldestidx] : NULL);
802*12967Sgavin.maltby@oracle.com }
803*12967Sgavin.maltby@oracle.com
804*12967Sgavin.maltby@oracle.com static void
pipeline_stall(struct fmdump_pipeline * pl)805*12967Sgavin.maltby@oracle.com pipeline_stall(struct fmdump_pipeline *pl)
806*12967Sgavin.maltby@oracle.com {
807*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *srlzer = pl->pl_srlzer;
808*12967Sgavin.maltby@oracle.com
809*12967Sgavin.maltby@oracle.com ASSERT(MUTEX_HELD(&srlzer->ds_lock));
810*12967Sgavin.maltby@oracle.com (void) pthread_cond_wait(&pl->pl_cv, &srlzer->ds_lock);
811*12967Sgavin.maltby@oracle.com }
812*12967Sgavin.maltby@oracle.com
813*12967Sgavin.maltby@oracle.com static void
pipeline_continue(struct fmdump_pipeline * pl)814*12967Sgavin.maltby@oracle.com pipeline_continue(struct fmdump_pipeline *pl)
815*12967Sgavin.maltby@oracle.com {
816*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *srlzer = pl->pl_srlzer;
817*12967Sgavin.maltby@oracle.com
818*12967Sgavin.maltby@oracle.com ASSERT(MUTEX_HELD(&srlzer->ds_lock));
819*12967Sgavin.maltby@oracle.com (void) pthread_cond_signal(&srlzer->ds_pipearr[pl->pl_srlzeridx].pl_cv);
820*12967Sgavin.maltby@oracle.com }
821*12967Sgavin.maltby@oracle.com
822*12967Sgavin.maltby@oracle.com /*
823*12967Sgavin.maltby@oracle.com * Called on each pipeline record iteration to make a new record
824*12967Sgavin.maltby@oracle.com * available for input to the serializer. Returns 0 to indicate that
825*12967Sgavin.maltby@oracle.com * the caller must stall the pipeline, or 1 to indicate that the
826*12967Sgavin.maltby@oracle.com * caller should go ahead and render their record. If this record
827*12967Sgavin.maltby@oracle.com * addition fills the serializer then choose a pipeline that must
828*12967Sgavin.maltby@oracle.com * render output.
829*12967Sgavin.maltby@oracle.com */
830*12967Sgavin.maltby@oracle.com static int
pipeline_output(struct fmdump_pipeline * pl,const fmd_log_record_t * rp)831*12967Sgavin.maltby@oracle.com pipeline_output(struct fmdump_pipeline *pl, const fmd_log_record_t *rp)
832*12967Sgavin.maltby@oracle.com {
833*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *srlzer = pl->pl_srlzer;
834*12967Sgavin.maltby@oracle.com struct fmdump_srlzer_slot *slot;
835*12967Sgavin.maltby@oracle.com struct fmdump_pipeline *wpl;
836*12967Sgavin.maltby@oracle.com int thisidx = pl->pl_srlzeridx;
837*12967Sgavin.maltby@oracle.com
838*12967Sgavin.maltby@oracle.com ASSERT(MUTEX_HELD(&srlzer->ds_lock));
839*12967Sgavin.maltby@oracle.com
840*12967Sgavin.maltby@oracle.com slot = &srlzer->ds_slot[thisidx];
841*12967Sgavin.maltby@oracle.com slot->ss_state = FMDUMP_PIPE_RECORDAVAIL;
842*12967Sgavin.maltby@oracle.com slot->ss_sec = rp->rec_sec;
843*12967Sgavin.maltby@oracle.com slot->ss_nsec = rp->rec_nsec;
844*12967Sgavin.maltby@oracle.com srlzer->ds_nrecordavail++;
845*12967Sgavin.maltby@oracle.com
846*12967Sgavin.maltby@oracle.com /*
847*12967Sgavin.maltby@oracle.com * Once all pipelines are polling we just render in arrival order.
848*12967Sgavin.maltby@oracle.com */
849*12967Sgavin.maltby@oracle.com if (srlzer->ds_pollcnt == srlzer->ds_pipecnt)
850*12967Sgavin.maltby@oracle.com return (1);
851*12967Sgavin.maltby@oracle.com
852*12967Sgavin.maltby@oracle.com /*
853*12967Sgavin.maltby@oracle.com * If not all pipelines have asserted an output yet then the
854*12967Sgavin.maltby@oracle.com * caller must block.
855*12967Sgavin.maltby@oracle.com */
856*12967Sgavin.maltby@oracle.com if (srlzer->ds_nrecordavail + srlzer->ds_ndone +
857*12967Sgavin.maltby@oracle.com srlzer->ds_pollcnt < srlzer->ds_pipecnt)
858*12967Sgavin.maltby@oracle.com return (0);
859*12967Sgavin.maltby@oracle.com
860*12967Sgavin.maltby@oracle.com /*
861*12967Sgavin.maltby@oracle.com * Right so it's time to turn the crank by choosing which of the
862*12967Sgavin.maltby@oracle.com * filled line of slots should produce output. If it is the slot
863*12967Sgavin.maltby@oracle.com * for our caller then return their index to them, otherwise return
864*12967Sgavin.maltby@oracle.com * -1 to the caller to make them block and cv_signal the winner.
865*12967Sgavin.maltby@oracle.com */
866*12967Sgavin.maltby@oracle.com wpl = srlzer_choose(srlzer);
867*12967Sgavin.maltby@oracle.com ASSERT(wpl != NULL);
868*12967Sgavin.maltby@oracle.com
869*12967Sgavin.maltby@oracle.com if (wpl == pl)
870*12967Sgavin.maltby@oracle.com return (1);
871*12967Sgavin.maltby@oracle.com
872*12967Sgavin.maltby@oracle.com /* Wake the oldest, and return 0 to put the caller to sleep */
873*12967Sgavin.maltby@oracle.com pipeline_continue(wpl);
874*12967Sgavin.maltby@oracle.com
875*12967Sgavin.maltby@oracle.com return (0);
876*12967Sgavin.maltby@oracle.com }
877*12967Sgavin.maltby@oracle.com
878*12967Sgavin.maltby@oracle.com static void
pipeline_mark_consumed(struct fmdump_pipeline * pl)879*12967Sgavin.maltby@oracle.com pipeline_mark_consumed(struct fmdump_pipeline *pl)
880*12967Sgavin.maltby@oracle.com {
881*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *srlzer = pl->pl_srlzer;
882*12967Sgavin.maltby@oracle.com
883*12967Sgavin.maltby@oracle.com ASSERT(MUTEX_HELD(&srlzer->ds_lock));
884*12967Sgavin.maltby@oracle.com srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_PROCESSING;
885*12967Sgavin.maltby@oracle.com srlzer->ds_nrecordavail--;
886*12967Sgavin.maltby@oracle.com }
887*12967Sgavin.maltby@oracle.com
888*12967Sgavin.maltby@oracle.com static void
pipeline_done(struct fmdump_pipeline * pl)889*12967Sgavin.maltby@oracle.com pipeline_done(struct fmdump_pipeline *pl)
890*12967Sgavin.maltby@oracle.com {
891*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *srlzer = pl->pl_srlzer;
892*12967Sgavin.maltby@oracle.com struct fmdump_pipeline *wpl;
893*12967Sgavin.maltby@oracle.com
894*12967Sgavin.maltby@oracle.com srlzer_enter(pl);
895*12967Sgavin.maltby@oracle.com
896*12967Sgavin.maltby@oracle.com srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_DONE;
897*12967Sgavin.maltby@oracle.com srlzer->ds_ndone++;
898*12967Sgavin.maltby@oracle.com wpl = srlzer_choose(srlzer);
899*12967Sgavin.maltby@oracle.com if (wpl != NULL)
900*12967Sgavin.maltby@oracle.com pipeline_continue(wpl);
901*12967Sgavin.maltby@oracle.com
902*12967Sgavin.maltby@oracle.com srlzer_exit(pl);
903*12967Sgavin.maltby@oracle.com }
904*12967Sgavin.maltby@oracle.com
905*12967Sgavin.maltby@oracle.com static void
pipeline_pollmode(struct fmdump_pipeline * pl)906*12967Sgavin.maltby@oracle.com pipeline_pollmode(struct fmdump_pipeline *pl)
907*12967Sgavin.maltby@oracle.com {
908*12967Sgavin.maltby@oracle.com struct fmdump_srlzer *srlzer = pl->pl_srlzer;
909*12967Sgavin.maltby@oracle.com struct fmdump_pipeline *wpl;
910*12967Sgavin.maltby@oracle.com
911*12967Sgavin.maltby@oracle.com if (srlzer->ds_slot[pl->pl_srlzeridx].ss_state == FMDUMP_PIPE_POLLING)
912*12967Sgavin.maltby@oracle.com return;
913*12967Sgavin.maltby@oracle.com
914*12967Sgavin.maltby@oracle.com srlzer_enter(pl);
915*12967Sgavin.maltby@oracle.com
916*12967Sgavin.maltby@oracle.com srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_POLLING;
917*12967Sgavin.maltby@oracle.com if (++srlzer->ds_pollcnt + srlzer->ds_nrecordavail ==
918*12967Sgavin.maltby@oracle.com srlzer->ds_pipecnt && (wpl = srlzer_choose(srlzer)) != NULL)
919*12967Sgavin.maltby@oracle.com pipeline_continue(wpl);
920*12967Sgavin.maltby@oracle.com
921*12967Sgavin.maltby@oracle.com srlzer_exit(pl);
922*12967Sgavin.maltby@oracle.com }
923*12967Sgavin.maltby@oracle.com
924*12967Sgavin.maltby@oracle.com static int
pipeline_err(fmd_log_t * lp,void * arg)925*12967Sgavin.maltby@oracle.com pipeline_err(fmd_log_t *lp, void *arg)
926*12967Sgavin.maltby@oracle.com {
927*12967Sgavin.maltby@oracle.com struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg;
928*12967Sgavin.maltby@oracle.com
929*12967Sgavin.maltby@oracle.com fmdump_warn("skipping record in %s: %s\n", pl->pl_processing,
930*12967Sgavin.maltby@oracle.com fmd_log_errmsg(lp, fmd_log_errno(lp)));
931*12967Sgavin.maltby@oracle.com g_errs++;
932*12967Sgavin.maltby@oracle.com
933*12967Sgavin.maltby@oracle.com return (0);
934*12967Sgavin.maltby@oracle.com }
935*12967Sgavin.maltby@oracle.com
936*12967Sgavin.maltby@oracle.com static int
pipeline_cb(fmd_log_t * lp,const fmd_log_record_t * rp,void * arg)937*12967Sgavin.maltby@oracle.com pipeline_cb(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
938*12967Sgavin.maltby@oracle.com {
939*12967Sgavin.maltby@oracle.com struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg;
940*12967Sgavin.maltby@oracle.com int rc;
941*12967Sgavin.maltby@oracle.com
942*12967Sgavin.maltby@oracle.com fmd_log_rec_f *func = pl->pl_arg.da_fmt->do_func;
943*12967Sgavin.maltby@oracle.com
944*12967Sgavin.maltby@oracle.com srlzer_enter(pl);
945*12967Sgavin.maltby@oracle.com
946*12967Sgavin.maltby@oracle.com if (!pipeline_output(pl, rp))
947*12967Sgavin.maltby@oracle.com pipeline_stall(pl);
948*12967Sgavin.maltby@oracle.com
949*12967Sgavin.maltby@oracle.com rc = func(lp, rp, pl->pl_arg.da_fp);
950*12967Sgavin.maltby@oracle.com pipeline_mark_consumed(pl);
951*12967Sgavin.maltby@oracle.com
952*12967Sgavin.maltby@oracle.com srlzer_exit(pl);
953*12967Sgavin.maltby@oracle.com
954*12967Sgavin.maltby@oracle.com return (rc);
955*12967Sgavin.maltby@oracle.com }
956*12967Sgavin.maltby@oracle.com
957*12967Sgavin.maltby@oracle.com static void
pipeline_process(struct fmdump_pipeline * pl,char * logpath,boolean_t follow)958*12967Sgavin.maltby@oracle.com pipeline_process(struct fmdump_pipeline *pl, char *logpath, boolean_t follow)
959*12967Sgavin.maltby@oracle.com {
960*12967Sgavin.maltby@oracle.com fmd_log_header_t log;
961*12967Sgavin.maltby@oracle.com fmd_log_t *lp;
962*12967Sgavin.maltby@oracle.com int err;
963*12967Sgavin.maltby@oracle.com int i;
964*12967Sgavin.maltby@oracle.com
965*12967Sgavin.maltby@oracle.com pl->pl_processing = logpath;
966*12967Sgavin.maltby@oracle.com
967*12967Sgavin.maltby@oracle.com if ((lp = fmd_log_open(FMD_LOG_VERSION, logpath, &err)) == NULL) {
968*12967Sgavin.maltby@oracle.com fmdump_warn("failed to open %s: %s\n",
969*12967Sgavin.maltby@oracle.com logpath, fmd_log_errmsg(NULL, err));
970*12967Sgavin.maltby@oracle.com g_errs++;
971*12967Sgavin.maltby@oracle.com return;
972*12967Sgavin.maltby@oracle.com }
973*12967Sgavin.maltby@oracle.com
974*12967Sgavin.maltby@oracle.com fmd_log_header(lp, &log);
975*12967Sgavin.maltby@oracle.com for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) {
976*12967Sgavin.maltby@oracle.com if (strcmp(log.log_label, logtypes[i].lt_label) == 0) {
977*12967Sgavin.maltby@oracle.com pl->pl_ops = logtypes[i].lt_ops;
978*12967Sgavin.maltby@oracle.com pl->pl_arg.da_fmt =
979*12967Sgavin.maltby@oracle.com &pl->pl_ops->do_formats[pl->pl_fmt];
980*12967Sgavin.maltby@oracle.com break;
981*12967Sgavin.maltby@oracle.com }
982*12967Sgavin.maltby@oracle.com }
983*12967Sgavin.maltby@oracle.com
984*12967Sgavin.maltby@oracle.com if (pl->pl_ops == NULL) {
985*12967Sgavin.maltby@oracle.com fmdump_warn("unknown log type %s for %s\n",
986*12967Sgavin.maltby@oracle.com log.log_label, logpath);
987*12967Sgavin.maltby@oracle.com g_errs++;
988*12967Sgavin.maltby@oracle.com return;
989*12967Sgavin.maltby@oracle.com }
990*12967Sgavin.maltby@oracle.com
991*12967Sgavin.maltby@oracle.com do {
992*12967Sgavin.maltby@oracle.com if (fmd_log_xiter(lp, FMD_LOG_XITER_REFS, pl->pl_arg.da_fc,
993*12967Sgavin.maltby@oracle.com pl->pl_arg.da_fv, pipeline_cb, pipeline_err, (void *)pl,
994*12967Sgavin.maltby@oracle.com NULL) != 0) {
995*12967Sgavin.maltby@oracle.com fmdump_warn("failed to dump %s: %s\n",
996*12967Sgavin.maltby@oracle.com logpath, fmd_log_errmsg(lp, fmd_log_errno(lp)));
997*12967Sgavin.maltby@oracle.com g_errs++;
998*12967Sgavin.maltby@oracle.com fmd_log_close(lp);
999*12967Sgavin.maltby@oracle.com return;
1000*12967Sgavin.maltby@oracle.com }
1001*12967Sgavin.maltby@oracle.com
1002*12967Sgavin.maltby@oracle.com if (follow) {
1003*12967Sgavin.maltby@oracle.com pipeline_pollmode(pl);
1004*12967Sgavin.maltby@oracle.com (void) sleep(1);
1005*12967Sgavin.maltby@oracle.com }
1006*12967Sgavin.maltby@oracle.com
1007*12967Sgavin.maltby@oracle.com } while (follow);
1008*12967Sgavin.maltby@oracle.com
1009*12967Sgavin.maltby@oracle.com fmd_log_close(lp);
1010*12967Sgavin.maltby@oracle.com }
1011*12967Sgavin.maltby@oracle.com
1012*12967Sgavin.maltby@oracle.com static void *
pipeline_thr(void * arg)1013*12967Sgavin.maltby@oracle.com pipeline_thr(void *arg)
1014*12967Sgavin.maltby@oracle.com {
1015*12967Sgavin.maltby@oracle.com struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg;
1016*12967Sgavin.maltby@oracle.com struct loglink *ll;
1017*12967Sgavin.maltby@oracle.com
1018*12967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&pl->pl_lock);
1019*12967Sgavin.maltby@oracle.com pl->pl_started = 1;
1020*12967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&pl->pl_lock);
1021*12967Sgavin.maltby@oracle.com (void) pthread_cond_signal(&pl->pl_cv);
1022*12967Sgavin.maltby@oracle.com
1023*12967Sgavin.maltby@oracle.com for (ll = pl->pl_rotated; ll != NULL; ll = ll->next)
1024*12967Sgavin.maltby@oracle.com pipeline_process(pl, ll->path, B_FALSE);
1025*12967Sgavin.maltby@oracle.com
1026*12967Sgavin.maltby@oracle.com pipeline_process(pl, pl->pl_logpath, pl->pl_follow);
1027*12967Sgavin.maltby@oracle.com pipeline_done(pl);
1028*12967Sgavin.maltby@oracle.com
1029*12967Sgavin.maltby@oracle.com return (NULL);
1030*12967Sgavin.maltby@oracle.com }
1031*12967Sgavin.maltby@oracle.com
1032*12967Sgavin.maltby@oracle.com
1033*12967Sgavin.maltby@oracle.com static int
aggregate(char ** ifiles,int n_ifiles,int opt_f,fmd_log_filter_t * fv,uint_t fc,int opt_v,int opt_V,int opt_p)1034*12967Sgavin.maltby@oracle.com aggregate(char **ifiles, int n_ifiles, int opt_f,
1035*12967Sgavin.maltby@oracle.com fmd_log_filter_t *fv, uint_t fc,
1036*12967Sgavin.maltby@oracle.com int opt_v, int opt_V, int opt_p)
1037*12967Sgavin.maltby@oracle.com {
1038*12967Sgavin.maltby@oracle.com struct fmdump_pipeline *pipeline, *pl;
1039*12967Sgavin.maltby@oracle.com struct fmdump_srlzer srlzer;
1040*12967Sgavin.maltby@oracle.com uint32_t npipe;
1041*12967Sgavin.maltby@oracle.com int fmt;
1042*12967Sgavin.maltby@oracle.com int i;
1043*12967Sgavin.maltby@oracle.com
1044*12967Sgavin.maltby@oracle.com if (ifiles != NULL) {
1045*12967Sgavin.maltby@oracle.com npipe = n_ifiles;
1046*12967Sgavin.maltby@oracle.com pipeline = calloc(npipe, sizeof (struct fmdump_pipeline));
1047*12967Sgavin.maltby@oracle.com if (!pipeline)
1048*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
1049*12967Sgavin.maltby@oracle.com
1050*12967Sgavin.maltby@oracle.com for (i = 0; i < n_ifiles; i++)
1051*12967Sgavin.maltby@oracle.com pipeline[i].pl_logpath = ifiles[i];
1052*12967Sgavin.maltby@oracle.com } else {
1053*12967Sgavin.maltby@oracle.com pipeline = calloc(sizeof (logtypes) / sizeof (logtypes[0]),
1054*12967Sgavin.maltby@oracle.com sizeof (struct fmdump_pipeline));
1055*12967Sgavin.maltby@oracle.com if (!pipeline)
1056*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
1057*12967Sgavin.maltby@oracle.com
1058*12967Sgavin.maltby@oracle.com do_disables();
1059*12967Sgavin.maltby@oracle.com
1060*12967Sgavin.maltby@oracle.com npipe = 0;
1061*12967Sgavin.maltby@oracle.com for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) {
1062*12967Sgavin.maltby@oracle.com struct fmdump_logtype *ltp = &logtypes[i];
1063*12967Sgavin.maltby@oracle.com char *logpath;
1064*12967Sgavin.maltby@oracle.com
1065*12967Sgavin.maltby@oracle.com if (ltp->lt_enabled == B_FALSE)
1066*12967Sgavin.maltby@oracle.com continue;
1067*12967Sgavin.maltby@oracle.com
1068*12967Sgavin.maltby@oracle.com if ((logpath = malloc(PATH_MAX)) == NULL)
1069*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
1070*12967Sgavin.maltby@oracle.com
1071*12967Sgavin.maltby@oracle.com (void) snprintf(logpath, PATH_MAX,
1072*12967Sgavin.maltby@oracle.com "%s/var/fm/fmd/%s",
1073*12967Sgavin.maltby@oracle.com g_root ? g_root : "", ltp->lt_logname);
1074*12967Sgavin.maltby@oracle.com
1075*12967Sgavin.maltby@oracle.com pipeline[npipe].pl_rotated =
1076*12967Sgavin.maltby@oracle.com get_rotated_logs(logpath);
1077*12967Sgavin.maltby@oracle.com
1078*12967Sgavin.maltby@oracle.com pipeline[npipe++].pl_logpath = logpath;
1079*12967Sgavin.maltby@oracle.com }
1080*12967Sgavin.maltby@oracle.com }
1081*12967Sgavin.maltby@oracle.com
1082*12967Sgavin.maltby@oracle.com if (opt_V)
1083*12967Sgavin.maltby@oracle.com fmt = opt_p ? FMDUMP_PRETTY : FMDUMP_VERB2;
1084*12967Sgavin.maltby@oracle.com else if (opt_v)
1085*12967Sgavin.maltby@oracle.com fmt = FMDUMP_VERB1;
1086*12967Sgavin.maltby@oracle.com else
1087*12967Sgavin.maltby@oracle.com fmt = FMDUMP_SHORT;
1088*12967Sgavin.maltby@oracle.com
1089*12967Sgavin.maltby@oracle.com bzero(&srlzer, sizeof (srlzer));
1090*12967Sgavin.maltby@oracle.com srlzer.ds_pipearr = pipeline;
1091*12967Sgavin.maltby@oracle.com srlzer.ds_pipecnt = npipe;
1092*12967Sgavin.maltby@oracle.com srlzer.ds_slot = calloc(npipe, sizeof (struct fmdump_srlzer_slot));
1093*12967Sgavin.maltby@oracle.com if (!srlzer.ds_slot)
1094*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
1095*12967Sgavin.maltby@oracle.com (void) pthread_mutex_init(&srlzer.ds_lock, NULL);
1096*12967Sgavin.maltby@oracle.com
1097*12967Sgavin.maltby@oracle.com for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++) {
1098*12967Sgavin.maltby@oracle.com (void) pthread_mutex_init(&pl->pl_lock, NULL);
1099*12967Sgavin.maltby@oracle.com (void) pthread_cond_init(&pl->pl_cv, NULL);
1100*12967Sgavin.maltby@oracle.com srlzer.ds_slot[i].ss_state = FMDUMP_PIPE_PROCESSING;
1101*12967Sgavin.maltby@oracle.com pl->pl_srlzer = &srlzer;
1102*12967Sgavin.maltby@oracle.com pl->pl_srlzeridx = i;
1103*12967Sgavin.maltby@oracle.com pl->pl_follow = opt_f ? B_TRUE : B_FALSE;
1104*12967Sgavin.maltby@oracle.com pl->pl_fmt = fmt;
1105*12967Sgavin.maltby@oracle.com pl->pl_arg.da_fv = fv;
1106*12967Sgavin.maltby@oracle.com pl->pl_arg.da_fc = fc;
1107*12967Sgavin.maltby@oracle.com pl->pl_arg.da_fp = stdout;
1108*12967Sgavin.maltby@oracle.com
1109*12967Sgavin.maltby@oracle.com (void) pthread_mutex_lock(&pl->pl_lock);
1110*12967Sgavin.maltby@oracle.com
1111*12967Sgavin.maltby@oracle.com if (pthread_create(&pl->pl_thr, NULL,
1112*12967Sgavin.maltby@oracle.com pipeline_thr, (void *)pl) != 0)
1113*12967Sgavin.maltby@oracle.com fmdump_fatal("pthread_create for pipeline %d failed",
1114*12967Sgavin.maltby@oracle.com i);
1115*12967Sgavin.maltby@oracle.com }
1116*12967Sgavin.maltby@oracle.com
1117*12967Sgavin.maltby@oracle.com for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++) {
1118*12967Sgavin.maltby@oracle.com while (!pl->pl_started)
1119*12967Sgavin.maltby@oracle.com (void) pthread_cond_wait(&pl->pl_cv, &pl->pl_lock);
1120*12967Sgavin.maltby@oracle.com
1121*12967Sgavin.maltby@oracle.com (void) pthread_mutex_unlock(&pl->pl_lock);
1122*12967Sgavin.maltby@oracle.com }
1123*12967Sgavin.maltby@oracle.com
1124*12967Sgavin.maltby@oracle.com for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++)
1125*12967Sgavin.maltby@oracle.com (void) pthread_join(pl->pl_thr, NULL);
1126*12967Sgavin.maltby@oracle.com
1127*12967Sgavin.maltby@oracle.com if (ifiles == NULL) {
1128*12967Sgavin.maltby@oracle.com for (i = 0; i < npipe; i++)
1129*12967Sgavin.maltby@oracle.com free(pipeline[i].pl_logpath);
1130*12967Sgavin.maltby@oracle.com }
1131*12967Sgavin.maltby@oracle.com
1132*12967Sgavin.maltby@oracle.com free(srlzer.ds_slot);
1133*12967Sgavin.maltby@oracle.com
1134*12967Sgavin.maltby@oracle.com free(pipeline);
1135*12967Sgavin.maltby@oracle.com
1136*12967Sgavin.maltby@oracle.com return (FMDUMP_EXIT_SUCCESS);
1137*12967Sgavin.maltby@oracle.com }
1138*12967Sgavin.maltby@oracle.com
1139*12967Sgavin.maltby@oracle.com static void
cleanup(char ** ifiles,int n_ifiles)1140*12967Sgavin.maltby@oracle.com cleanup(char **ifiles, int n_ifiles)
1141*12967Sgavin.maltby@oracle.com {
1142*12967Sgavin.maltby@oracle.com int i;
1143*12967Sgavin.maltby@oracle.com
1144*12967Sgavin.maltby@oracle.com if (ifiles == NULL)
1145*12967Sgavin.maltby@oracle.com return;
1146*12967Sgavin.maltby@oracle.com
1147*12967Sgavin.maltby@oracle.com for (i = 0; i < n_ifiles; i++) {
1148*12967Sgavin.maltby@oracle.com if (ifiles[i] != NULL) {
1149*12967Sgavin.maltby@oracle.com free(ifiles[i]);
1150*12967Sgavin.maltby@oracle.com ifiles[i] = NULL;
1151*12967Sgavin.maltby@oracle.com }
1152*12967Sgavin.maltby@oracle.com }
1153*12967Sgavin.maltby@oracle.com
1154*12967Sgavin.maltby@oracle.com free(ifiles);
1155*12967Sgavin.maltby@oracle.com }
1156*12967Sgavin.maltby@oracle.com
11570Sstevel@tonic-gate int
main(int argc,char * argv[])11580Sstevel@tonic-gate main(int argc, char *argv[])
11590Sstevel@tonic-gate {
1160*12967Sgavin.maltby@oracle.com int opt_a = 0, opt_e = 0, opt_f = 0, opt_H = 0, opt_m = 0, opt_p = 0;
11610Sstevel@tonic-gate int opt_u = 0, opt_v = 0, opt_V = 0;
1162*12967Sgavin.maltby@oracle.com int opt_i = 0, opt_I = 0;
1163*12967Sgavin.maltby@oracle.com int opt_A = 0;
1164*12967Sgavin.maltby@oracle.com char **ifiles = NULL;
1165*12967Sgavin.maltby@oracle.com char *ifile = NULL;
1166*12967Sgavin.maltby@oracle.com int n_ifiles;
1167*12967Sgavin.maltby@oracle.com int ifileidx = 0;
11680Sstevel@tonic-gate int iflags = 0;
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate fmdump_arg_t arg;
11710Sstevel@tonic-gate fmdump_lyr_t lyr;
11720Sstevel@tonic-gate const fmdump_ops_t *ops;
11730Sstevel@tonic-gate fmd_log_filter_t *filtv;
11740Sstevel@tonic-gate uint_t filtc;
11750Sstevel@tonic-gate
11760Sstevel@tonic-gate fmd_log_filter_t *errfv, *fltfv, *allfv;
11770Sstevel@tonic-gate uint_t errfc = 0, fltfc = 0, allfc = 0;
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate fmd_log_header_t log;
11800Sstevel@tonic-gate fmd_log_rec_f *func;
11810Sstevel@tonic-gate void *farg;
11820Sstevel@tonic-gate fmd_log_t *lp;
11830Sstevel@tonic-gate int c, err;
11840Sstevel@tonic-gate off64_t off = 0;
11858740SSean.Ye@Sun.COM ulong_t recs;
11868740SSean.Ye@Sun.COM struct loglink *rotated_logs = NULL, *llp;
11870Sstevel@tonic-gate
11880Sstevel@tonic-gate g_pname = argv[0];
11890Sstevel@tonic-gate
11900Sstevel@tonic-gate errfv = alloca(sizeof (fmd_log_filter_t) * argc);
11910Sstevel@tonic-gate fltfv = alloca(sizeof (fmd_log_filter_t) * argc);
11920Sstevel@tonic-gate allfv = alloca(sizeof (fmd_log_filter_t) * argc);
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate while (optind < argc) {
11956640Scth while ((c =
1196*12967Sgavin.maltby@oracle.com getopt(argc, argv, "Aac:efHiImn:O:pR:t:T:u:vV")) != EOF) {
11970Sstevel@tonic-gate switch (c) {
1198*12967Sgavin.maltby@oracle.com case 'A':
1199*12967Sgavin.maltby@oracle.com opt_A++;
1200*12967Sgavin.maltby@oracle.com break;
12010Sstevel@tonic-gate case 'a':
12020Sstevel@tonic-gate opt_a++;
12030Sstevel@tonic-gate break;
12040Sstevel@tonic-gate case 'c':
12050Sstevel@tonic-gate errfv[errfc].filt_func = fmd_log_filter_class;
12060Sstevel@tonic-gate errfv[errfc].filt_arg = optarg;
12070Sstevel@tonic-gate allfv[allfc++] = errfv[errfc++];
12080Sstevel@tonic-gate break;
12090Sstevel@tonic-gate case 'e':
1210*12967Sgavin.maltby@oracle.com if (opt_i)
1211*12967Sgavin.maltby@oracle.com return (usage(stderr));
12120Sstevel@tonic-gate opt_e++;
12130Sstevel@tonic-gate break;
12140Sstevel@tonic-gate case 'f':
12150Sstevel@tonic-gate opt_f++;
12160Sstevel@tonic-gate break;
12170Sstevel@tonic-gate case 'H':
12180Sstevel@tonic-gate opt_H++;
12190Sstevel@tonic-gate break;
1220*12967Sgavin.maltby@oracle.com case 'i':
1221*12967Sgavin.maltby@oracle.com if (opt_e || opt_I)
1222*12967Sgavin.maltby@oracle.com return (usage(stderr));
1223*12967Sgavin.maltby@oracle.com opt_i++;
1224*12967Sgavin.maltby@oracle.com break;
1225*12967Sgavin.maltby@oracle.com case 'I':
1226*12967Sgavin.maltby@oracle.com if (opt_e || opt_i)
1227*12967Sgavin.maltby@oracle.com return (usage(stderr));
1228*12967Sgavin.maltby@oracle.com opt_I++;
1229*12967Sgavin.maltby@oracle.com break;
12309501SRobert.Johnston@Sun.COM case 'm':
12319501SRobert.Johnston@Sun.COM opt_m++;
12329501SRobert.Johnston@Sun.COM break;
12330Sstevel@tonic-gate case 'O':
12340Sstevel@tonic-gate off = strtoull(optarg, NULL, 16);
12350Sstevel@tonic-gate iflags |= FMD_LOG_XITER_OFFS;
12360Sstevel@tonic-gate break;
1237*12967Sgavin.maltby@oracle.com case 'p':
1238*12967Sgavin.maltby@oracle.com opt_p++;
1239*12967Sgavin.maltby@oracle.com break;
12400Sstevel@tonic-gate case 'R':
12410Sstevel@tonic-gate g_root = optarg;
12420Sstevel@tonic-gate break;
12430Sstevel@tonic-gate case 't':
12440Sstevel@tonic-gate errfv[errfc].filt_func = fmd_log_filter_after;
12450Sstevel@tonic-gate errfv[errfc].filt_arg = gettimeopt(optarg);
12460Sstevel@tonic-gate allfv[allfc++] = errfv[errfc++];
12470Sstevel@tonic-gate break;
12480Sstevel@tonic-gate case 'T':
12490Sstevel@tonic-gate errfv[errfc].filt_func = fmd_log_filter_before;
12500Sstevel@tonic-gate errfv[errfc].filt_arg = gettimeopt(optarg);
12510Sstevel@tonic-gate allfv[allfc++] = errfv[errfc++];
12520Sstevel@tonic-gate break;
12530Sstevel@tonic-gate case 'u':
12540Sstevel@tonic-gate fltfv[fltfc].filt_func = fmd_log_filter_uuid;
12550Sstevel@tonic-gate fltfv[fltfc].filt_arg = optarg;
12560Sstevel@tonic-gate allfv[allfc++] = fltfv[fltfc++];
12570Sstevel@tonic-gate opt_u++;
12580Sstevel@tonic-gate opt_a++; /* -u implies -a */
12590Sstevel@tonic-gate break;
12606640Scth case 'n': {
12616640Scth fltfv[fltfc].filt_func = fmd_log_filter_nv;
12626640Scth fltfv[fltfc].filt_arg = setupnamevalue(optarg);
12636640Scth allfv[allfc++] = fltfv[fltfc++];
12646640Scth break;
12656640Scth }
12660Sstevel@tonic-gate case 'v':
12670Sstevel@tonic-gate opt_v++;
12680Sstevel@tonic-gate break;
12690Sstevel@tonic-gate case 'V':
12700Sstevel@tonic-gate opt_V++;
12710Sstevel@tonic-gate break;
12720Sstevel@tonic-gate default:
12730Sstevel@tonic-gate return (usage(stderr));
12740Sstevel@tonic-gate }
12750Sstevel@tonic-gate }
12760Sstevel@tonic-gate
1277*12967Sgavin.maltby@oracle.com if (opt_A && (opt_e || opt_i || opt_I || opt_m || opt_u))
1278*12967Sgavin.maltby@oracle.com fmdump_usage("-A excludes all of "
1279*12967Sgavin.maltby@oracle.com "-e, -i, -I, -m and -u\n");
1280*12967Sgavin.maltby@oracle.com
12810Sstevel@tonic-gate if (optind < argc) {
1282*12967Sgavin.maltby@oracle.com char *dest;
1283*12967Sgavin.maltby@oracle.com
1284*12967Sgavin.maltby@oracle.com if (ifiles == NULL) {
1285*12967Sgavin.maltby@oracle.com n_ifiles = argc - optind;
1286*12967Sgavin.maltby@oracle.com ifiles = calloc(n_ifiles, sizeof (char *));
1287*12967Sgavin.maltby@oracle.com if (ifiles == NULL) {
1288*12967Sgavin.maltby@oracle.com fmdump_fatal(
1289*12967Sgavin.maltby@oracle.com "failed to allocate memory for "
1290*12967Sgavin.maltby@oracle.com "%d input file%s", n_ifiles,
1291*12967Sgavin.maltby@oracle.com n_ifiles > 1 ? "s" : "");
1292*12967Sgavin.maltby@oracle.com }
12930Sstevel@tonic-gate }
1294*12967Sgavin.maltby@oracle.com
1295*12967Sgavin.maltby@oracle.com if (ifileidx > 0 && !opt_A)
1296*12967Sgavin.maltby@oracle.com fmdump_usage("illegal argument -- %s\n",
1297*12967Sgavin.maltby@oracle.com argv[optind]);
1298*12967Sgavin.maltby@oracle.com
1299*12967Sgavin.maltby@oracle.com if ((dest = malloc(PATH_MAX)) == NULL)
1300*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
1301*12967Sgavin.maltby@oracle.com
1302*12967Sgavin.maltby@oracle.com (void) strlcpy(dest, argv[optind++], PATH_MAX);
1303*12967Sgavin.maltby@oracle.com ifiles[ifileidx++] = dest;
13040Sstevel@tonic-gate }
13050Sstevel@tonic-gate }
13060Sstevel@tonic-gate
1307*12967Sgavin.maltby@oracle.com if (opt_A) {
1308*12967Sgavin.maltby@oracle.com int rc;
1309*12967Sgavin.maltby@oracle.com
1310*12967Sgavin.maltby@oracle.com if (!opt_a) {
1311*12967Sgavin.maltby@oracle.com fltfv[fltfc].filt_func = log_filter_silent;
1312*12967Sgavin.maltby@oracle.com fltfv[fltfc].filt_arg = (void *)1;
1313*12967Sgavin.maltby@oracle.com allfv[allfc++] = fltfv[fltfc++];
1314*12967Sgavin.maltby@oracle.com }
1315*12967Sgavin.maltby@oracle.com
1316*12967Sgavin.maltby@oracle.com rc = aggregate(ifiles, n_ifiles, opt_f,
1317*12967Sgavin.maltby@oracle.com allfv, allfc,
1318*12967Sgavin.maltby@oracle.com opt_v, opt_V, opt_p);
1319*12967Sgavin.maltby@oracle.com
1320*12967Sgavin.maltby@oracle.com cleanup(ifiles, n_ifiles);
1321*12967Sgavin.maltby@oracle.com return (rc);
1322*12967Sgavin.maltby@oracle.com } else {
1323*12967Sgavin.maltby@oracle.com if (ifiles == NULL) {
1324*12967Sgavin.maltby@oracle.com if ((ifile = calloc(1, PATH_MAX)) == NULL)
1325*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to allocate memory");
1326*12967Sgavin.maltby@oracle.com } else {
1327*12967Sgavin.maltby@oracle.com ifile = ifiles[0];
1328*12967Sgavin.maltby@oracle.com }
1329*12967Sgavin.maltby@oracle.com }
1330*12967Sgavin.maltby@oracle.com
1331*12967Sgavin.maltby@oracle.com
13320Sstevel@tonic-gate if (*ifile == '\0') {
1333*12967Sgavin.maltby@oracle.com const char *pfx, *sfx;
1334*12967Sgavin.maltby@oracle.com
1335*12967Sgavin.maltby@oracle.com if (opt_u || (!opt_e && !opt_i && !opt_I)) {
1336*12967Sgavin.maltby@oracle.com pfx = "flt";
1337*12967Sgavin.maltby@oracle.com sfx = "";
1338*12967Sgavin.maltby@oracle.com } else {
1339*12967Sgavin.maltby@oracle.com if (opt_e) {
1340*12967Sgavin.maltby@oracle.com pfx = "err";
1341*12967Sgavin.maltby@oracle.com sfx = "";
1342*12967Sgavin.maltby@oracle.com } else {
1343*12967Sgavin.maltby@oracle.com pfx = "info";
1344*12967Sgavin.maltby@oracle.com sfx = opt_I ? "_hival" : "";
1345*12967Sgavin.maltby@oracle.com }
1346*12967Sgavin.maltby@oracle.com }
1347*12967Sgavin.maltby@oracle.com
1348*12967Sgavin.maltby@oracle.com (void) snprintf(ifile, PATH_MAX, "%s/var/fm/fmd/%slog%s",
1349*12967Sgavin.maltby@oracle.com g_root ? g_root : "", pfx, sfx);
13508740SSean.Ye@Sun.COM /*
13518740SSean.Ye@Sun.COM * logadm may rotate the logs. When no input file is specified,
13528740SSean.Ye@Sun.COM * we try to dump all the rotated logs as well in the right
13538740SSean.Ye@Sun.COM * order.
13548740SSean.Ye@Sun.COM */
13558740SSean.Ye@Sun.COM if (!opt_H && off == 0)
13568740SSean.Ye@Sun.COM rotated_logs = get_rotated_logs(ifile);
13570Sstevel@tonic-gate } else if (g_root != NULL) {
1358*12967Sgavin.maltby@oracle.com fmdump_usage("-R option is not appropriate "
1359*12967Sgavin.maltby@oracle.com "when file operand is present\n");
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate
1362*12967Sgavin.maltby@oracle.com if ((g_msg = fmd_msg_init(g_root, FMD_MSG_VERSION)) == NULL)
1363*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to initialize libfmd_msg");
13649501SRobert.Johnston@Sun.COM
13650Sstevel@tonic-gate if ((lp = fmd_log_open(FMD_LOG_VERSION, ifile, &err)) == NULL) {
1366*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to open %s: %s\n", ifile,
1367*12967Sgavin.maltby@oracle.com fmd_log_errmsg(NULL, err));
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate
13700Sstevel@tonic-gate if (opt_H) {
13710Sstevel@tonic-gate fmd_log_header(lp, &log);
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate (void) printf("EXD_CREATOR = %s\n", log.log_creator);
13740Sstevel@tonic-gate (void) printf("EXD_HOSTNAME = %s\n", log.log_hostname);
13750Sstevel@tonic-gate (void) printf("EXD_FMA_LABEL = %s\n", log.log_label);
13760Sstevel@tonic-gate (void) printf("EXD_FMA_VERSION = %s\n", log.log_version);
13770Sstevel@tonic-gate (void) printf("EXD_FMA_OSREL = %s\n", log.log_osrelease);
13780Sstevel@tonic-gate (void) printf("EXD_FMA_OSVER = %s\n", log.log_osversion);
13790Sstevel@tonic-gate (void) printf("EXD_FMA_PLAT = %s\n", log.log_platform);
13801052Sdilpreet (void) printf("EXD_FMA_UUID = %s\n", log.log_uuid);
13810Sstevel@tonic-gate
13820Sstevel@tonic-gate return (FMDUMP_EXIT_SUCCESS);
13830Sstevel@tonic-gate }
13840Sstevel@tonic-gate
13850Sstevel@tonic-gate if (off != 0 && fmd_log_seek(lp, off) != 0) {
1386*12967Sgavin.maltby@oracle.com fmdump_fatal("failed to seek %s: %s\n", ifile,
1387*12967Sgavin.maltby@oracle.com fmd_log_errmsg(lp, fmd_log_errno(lp)));
13880Sstevel@tonic-gate }
13890Sstevel@tonic-gate
13900Sstevel@tonic-gate if (opt_e && opt_u)
13910Sstevel@tonic-gate ops = &fmdump_err_ops;
13920Sstevel@tonic-gate else if (strcmp(fmd_log_label(lp), fmdump_flt_ops.do_label) == 0)
13930Sstevel@tonic-gate ops = &fmdump_flt_ops;
13940Sstevel@tonic-gate else if (strcmp(fmd_log_label(lp), fmdump_asru_ops.do_label) == 0)
13950Sstevel@tonic-gate ops = &fmdump_asru_ops;
1396*12967Sgavin.maltby@oracle.com else if (strcmp(fmd_log_label(lp), fmdump_info_ops.do_label) == 0)
1397*12967Sgavin.maltby@oracle.com ops = &fmdump_info_ops;
13980Sstevel@tonic-gate else
13990Sstevel@tonic-gate ops = &fmdump_err_ops;
14000Sstevel@tonic-gate
14010Sstevel@tonic-gate if (!opt_a && ops == &fmdump_flt_ops) {
14020Sstevel@tonic-gate fltfv[fltfc].filt_func = log_filter_silent;
14030Sstevel@tonic-gate fltfv[fltfc].filt_arg = NULL;
14040Sstevel@tonic-gate allfv[allfc++] = fltfv[fltfc++];
14050Sstevel@tonic-gate }
14060Sstevel@tonic-gate
14070Sstevel@tonic-gate if (opt_V) {
1408*12967Sgavin.maltby@oracle.com arg.da_fmt =
1409*12967Sgavin.maltby@oracle.com &ops->do_formats[opt_p ? FMDUMP_PRETTY : FMDUMP_VERB2];
14100Sstevel@tonic-gate iflags |= FMD_LOG_XITER_REFS;
14110Sstevel@tonic-gate } else if (opt_v) {
14120Sstevel@tonic-gate arg.da_fmt = &ops->do_formats[FMDUMP_VERB1];
14139501SRobert.Johnston@Sun.COM } else if (opt_m) {
14149501SRobert.Johnston@Sun.COM arg.da_fmt = &ops->do_formats[FMDUMP_MSG];
14150Sstevel@tonic-gate } else
14160Sstevel@tonic-gate arg.da_fmt = &ops->do_formats[FMDUMP_SHORT];
14170Sstevel@tonic-gate
14189501SRobert.Johnston@Sun.COM if (opt_m && arg.da_fmt->do_func == NULL) {
1419*12967Sgavin.maltby@oracle.com fmdump_usage("-m mode is not supported for "
1420*12967Sgavin.maltby@oracle.com "log of type %s: %s\n", fmd_log_label(lp), ifile);
14219501SRobert.Johnston@Sun.COM }
14229501SRobert.Johnston@Sun.COM
14230Sstevel@tonic-gate arg.da_fv = errfv;
14240Sstevel@tonic-gate arg.da_fc = errfc;
14250Sstevel@tonic-gate arg.da_fp = stdout;
14260Sstevel@tonic-gate
14270Sstevel@tonic-gate if (iflags & FMD_LOG_XITER_OFFS)
14280Sstevel@tonic-gate fmdump_printf(arg.da_fp, "%16s ", "OFFSET");
14290Sstevel@tonic-gate
143010928SStephen.Hanson@Sun.COM if (arg.da_fmt->do_hdr && !(opt_V && ops == &fmdump_flt_ops))
14310Sstevel@tonic-gate fmdump_printf(arg.da_fp, "%s\n", arg.da_fmt->do_hdr);
14320Sstevel@tonic-gate
14330Sstevel@tonic-gate if (opt_e && opt_u) {
14340Sstevel@tonic-gate iflags |= FMD_LOG_XITER_REFS;
14350Sstevel@tonic-gate func = xref_iter;
14360Sstevel@tonic-gate farg = &arg;
14370Sstevel@tonic-gate filtc = fltfc;
14380Sstevel@tonic-gate filtv = fltfv;
14390Sstevel@tonic-gate } else {
14400Sstevel@tonic-gate func = arg.da_fmt->do_func;
14410Sstevel@tonic-gate farg = arg.da_fp;
14420Sstevel@tonic-gate filtc = allfc;
14430Sstevel@tonic-gate filtv = allfv;
14440Sstevel@tonic-gate }
14450Sstevel@tonic-gate
14460Sstevel@tonic-gate if (iflags & FMD_LOG_XITER_OFFS) {
14470Sstevel@tonic-gate lyr.dy_func = func;
14480Sstevel@tonic-gate lyr.dy_arg = farg;
14490Sstevel@tonic-gate lyr.dy_fp = arg.da_fp;
14500Sstevel@tonic-gate func = xoff_iter;
14510Sstevel@tonic-gate farg = &lyr;
14520Sstevel@tonic-gate }
14530Sstevel@tonic-gate
14548740SSean.Ye@Sun.COM for (llp = rotated_logs; llp != NULL; llp = llp->next) {
14558740SSean.Ye@Sun.COM fmd_log_t *rlp;
14568740SSean.Ye@Sun.COM
14578740SSean.Ye@Sun.COM if ((rlp = fmd_log_open(FMD_LOG_VERSION, llp->path, &err))
14588740SSean.Ye@Sun.COM == NULL) {
1459*12967Sgavin.maltby@oracle.com fmdump_warn("failed to open %s: %s\n",
1460*12967Sgavin.maltby@oracle.com llp->path, fmd_log_errmsg(NULL, err));
14618740SSean.Ye@Sun.COM g_errs++;
14628740SSean.Ye@Sun.COM continue;
14638740SSean.Ye@Sun.COM }
14648740SSean.Ye@Sun.COM
14658740SSean.Ye@Sun.COM recs = 0;
14668740SSean.Ye@Sun.COM if (fmd_log_xiter(rlp, iflags, filtc, filtv,
14678740SSean.Ye@Sun.COM func, error, farg, &recs) != 0) {
1468*12967Sgavin.maltby@oracle.com fmdump_warn("failed to dump %s: %s\n", llp->path,
14698740SSean.Ye@Sun.COM fmd_log_errmsg(rlp, fmd_log_errno(rlp)));
14708740SSean.Ye@Sun.COM g_errs++;
14718740SSean.Ye@Sun.COM }
14728740SSean.Ye@Sun.COM g_recs += recs;
14738740SSean.Ye@Sun.COM
14748740SSean.Ye@Sun.COM fmd_log_close(rlp);
14758740SSean.Ye@Sun.COM }
14768740SSean.Ye@Sun.COM
14770Sstevel@tonic-gate do {
14788740SSean.Ye@Sun.COM recs = 0;
14790Sstevel@tonic-gate if (fmd_log_xiter(lp, iflags, filtc, filtv,
14808740SSean.Ye@Sun.COM func, error, farg, &recs) != 0) {
1481*12967Sgavin.maltby@oracle.com fmdump_warn("failed to dump %s: %s\n", ifile,
14820Sstevel@tonic-gate fmd_log_errmsg(lp, fmd_log_errno(lp)));
14830Sstevel@tonic-gate g_errs++;
14840Sstevel@tonic-gate }
14858740SSean.Ye@Sun.COM g_recs += recs;
14860Sstevel@tonic-gate
14870Sstevel@tonic-gate if (opt_f)
14880Sstevel@tonic-gate (void) sleep(1);
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate } while (opt_f);
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate if (!opt_f && g_recs == 0 && isatty(STDOUT_FILENO))
1493*12967Sgavin.maltby@oracle.com fmdump_warn("%s is empty\n", ifile);
14940Sstevel@tonic-gate
14959501SRobert.Johnston@Sun.COM if (g_thp != NULL)
14969501SRobert.Johnston@Sun.COM topo_close(g_thp);
14979501SRobert.Johnston@Sun.COM
14980Sstevel@tonic-gate fmd_log_close(lp);
14999501SRobert.Johnston@Sun.COM fmd_msg_fini(g_msg);
15009501SRobert.Johnston@Sun.COM
1501*12967Sgavin.maltby@oracle.com if (ifiles == NULL)
1502*12967Sgavin.maltby@oracle.com free(ifile);
1503*12967Sgavin.maltby@oracle.com else
1504*12967Sgavin.maltby@oracle.com cleanup(ifiles, n_ifiles);
1505*12967Sgavin.maltby@oracle.com
15060Sstevel@tonic-gate return (g_errs ? FMDUMP_EXIT_ERROR : FMDUMP_EXIT_SUCCESS);
15070Sstevel@tonic-gate }
1508