17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
547911a7dScy152378 * Common Development and Distribution License (the "License").
647911a7dScy152378 * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
2169fcd3d4SYuri Pankov
227c478bd9Sstevel@tonic-gate /*
23f6e214c7SGavin Maltby * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
2469fcd3d4SYuri Pankov * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25*2db6d663SJoshua M. Clulow * Copyright (c) 2013, Joyent, Inc. All rights reserved.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <alloca.h>
297c478bd9Sstevel@tonic-gate #include <unistd.h>
307c478bd9Sstevel@tonic-gate #include <limits.h>
317c478bd9Sstevel@tonic-gate #include <strings.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <stdarg.h>
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <time.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
38602ca9eaScth #include <regex.h>
39c93c462eSCheng Sean Ye #include <dirent.h>
40f6e214c7SGavin Maltby #include <pthread.h>
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate #include <fmdump.h>
437c478bd9Sstevel@tonic-gate
447c478bd9Sstevel@tonic-gate #define FMDUMP_EXIT_SUCCESS 0
457c478bd9Sstevel@tonic-gate #define FMDUMP_EXIT_FATAL 1
467c478bd9Sstevel@tonic-gate #define FMDUMP_EXIT_USAGE 2
477c478bd9Sstevel@tonic-gate #define FMDUMP_EXIT_ERROR 3
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate const char *g_pname;
507c478bd9Sstevel@tonic-gate ulong_t g_errs;
517c478bd9Sstevel@tonic-gate ulong_t g_recs;
527c478bd9Sstevel@tonic-gate char *g_root;
53b6955755SRobert Johnston
547aec1d6eScindi struct topo_hdl *g_thp;
55b6955755SRobert Johnston fmd_msg_hdl_t *g_msg;
567c478bd9Sstevel@tonic-gate
577c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
587c478bd9Sstevel@tonic-gate void
fmdump_printf(FILE * fp,const char * format,...)597c478bd9Sstevel@tonic-gate fmdump_printf(FILE *fp, const char *format, ...)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate va_list ap;
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate va_start(ap, format);
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate if (vfprintf(fp, format, ap) < 0) {
667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: failed to print record: %s\n",
677c478bd9Sstevel@tonic-gate g_pname, strerror(errno));
687c478bd9Sstevel@tonic-gate g_errs++;
697c478bd9Sstevel@tonic-gate }
707c478bd9Sstevel@tonic-gate
717c478bd9Sstevel@tonic-gate va_end(ap);
727c478bd9Sstevel@tonic-gate }
737c478bd9Sstevel@tonic-gate
747c478bd9Sstevel@tonic-gate void
fmdump_vwarn(const char * format,va_list ap)757c478bd9Sstevel@tonic-gate fmdump_vwarn(const char *format, va_list ap)
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate int err = errno;
787c478bd9Sstevel@tonic-gate
797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: warning: ", g_pname);
807c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, ap);
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate if (strchr(format, '\n') == NULL)
837c478bd9Sstevel@tonic-gate (void) fprintf(stderr, ": %s\n", strerror(err));
847c478bd9Sstevel@tonic-gate
857c478bd9Sstevel@tonic-gate g_errs++;
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
897c478bd9Sstevel@tonic-gate void
fmdump_warn(const char * format,...)907c478bd9Sstevel@tonic-gate fmdump_warn(const char *format, ...)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate va_list ap;
937c478bd9Sstevel@tonic-gate
947c478bd9Sstevel@tonic-gate va_start(ap, format);
957c478bd9Sstevel@tonic-gate fmdump_vwarn(format, ap);
967c478bd9Sstevel@tonic-gate va_end(ap);
977c478bd9Sstevel@tonic-gate }
987c478bd9Sstevel@tonic-gate
99f6e214c7SGavin Maltby static void
fmdump_exit(int err,int exitcode,const char * format,va_list ap)100f6e214c7SGavin Maltby fmdump_exit(int err, int exitcode, const char *format, va_list ap)
101f6e214c7SGavin Maltby {
102f6e214c7SGavin Maltby (void) fprintf(stderr, "%s: ", g_pname);
103f6e214c7SGavin Maltby
104f6e214c7SGavin Maltby (void) vfprintf(stderr, format, ap);
105f6e214c7SGavin Maltby
106f6e214c7SGavin Maltby if (strchr(format, '\n') == NULL)
107f6e214c7SGavin Maltby (void) fprintf(stderr, ": %s\n", strerror(err));
108f6e214c7SGavin Maltby
109f6e214c7SGavin Maltby exit(exitcode);
110f6e214c7SGavin Maltby }
111f6e214c7SGavin Maltby
112f6e214c7SGavin Maltby /*PRINTFLIKE1*/
113f6e214c7SGavin Maltby static void
fmdump_fatal(const char * format,...)114f6e214c7SGavin Maltby fmdump_fatal(const char *format, ...)
115f6e214c7SGavin Maltby {
116f6e214c7SGavin Maltby int err = errno;
117f6e214c7SGavin Maltby
118f6e214c7SGavin Maltby va_list ap;
119f6e214c7SGavin Maltby
120f6e214c7SGavin Maltby va_start(ap, format);
121f6e214c7SGavin Maltby fmdump_exit(err, FMDUMP_EXIT_FATAL, format, ap);
122f6e214c7SGavin Maltby va_end(ap);
123f6e214c7SGavin Maltby }
124f6e214c7SGavin Maltby
125f6e214c7SGavin Maltby /*PRINTFLIKE1*/
126f6e214c7SGavin Maltby static void
fmdump_usage(const char * format,...)127f6e214c7SGavin Maltby fmdump_usage(const char *format, ...)
128f6e214c7SGavin Maltby {
129f6e214c7SGavin Maltby
130f6e214c7SGavin Maltby int err = errno;
131f6e214c7SGavin Maltby
132f6e214c7SGavin Maltby va_list ap;
133f6e214c7SGavin Maltby
134f6e214c7SGavin Maltby va_start(ap, format);
135f6e214c7SGavin Maltby fmdump_exit(err, FMDUMP_EXIT_USAGE, format, ap);
136f6e214c7SGavin Maltby va_end(ap);
137f6e214c7SGavin Maltby }
138f6e214c7SGavin Maltby
1397c478bd9Sstevel@tonic-gate char *
fmdump_date(char * buf,size_t len,const fmd_log_record_t * rp)1407c478bd9Sstevel@tonic-gate fmdump_date(char *buf, size_t len, const fmd_log_record_t *rp)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate if (rp->rec_sec > LONG_MAX) {
1437c478bd9Sstevel@tonic-gate fmdump_warn("record time is too large for 32-bit utility\n");
1447c478bd9Sstevel@tonic-gate (void) snprintf(buf, len, "0x%llx", rp->rec_sec);
1457c478bd9Sstevel@tonic-gate } else {
1467c478bd9Sstevel@tonic-gate time_t tod = (time_t)rp->rec_sec;
14747911a7dScy152378 time_t now = time(NULL);
14847911a7dScy152378 if (tod > now+60 ||
14947911a7dScy152378 tod < now - 6L*30L*24L*60L*60L) { /* 6 months ago */
15047911a7dScy152378 (void) strftime(buf, len, "%b %d %Y %T",
15147911a7dScy152378 localtime(&tod));
15247911a7dScy152378 } else {
15347911a7dScy152378 size_t sz;
15447911a7dScy152378 sz = strftime(buf, len, "%b %d %T", localtime(&tod));
15547911a7dScy152378 (void) snprintf(buf + sz, len - sz, ".%4.4llu",
15647911a7dScy152378 rp->rec_nsec / (NANOSEC / 10000));
15747911a7dScy152378 }
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate return (buf);
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate char *
fmdump_year(char * buf,size_t len,const fmd_log_record_t * rp)1647c478bd9Sstevel@tonic-gate fmdump_year(char *buf, size_t len, const fmd_log_record_t *rp)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate #ifdef _ILP32
1677c478bd9Sstevel@tonic-gate if (rp->rec_sec > LONG_MAX) {
1687c478bd9Sstevel@tonic-gate fmdump_warn("record time is too large for 32-bit utility\n");
1697c478bd9Sstevel@tonic-gate (void) snprintf(buf, len, "0x%llx", rp->rec_sec);
1707c478bd9Sstevel@tonic-gate } else {
1717c478bd9Sstevel@tonic-gate #endif
1727c478bd9Sstevel@tonic-gate time_t tod = (time_t)rp->rec_sec;
1737c478bd9Sstevel@tonic-gate (void) strftime(buf, len, "%b %d %Y %T", localtime(&tod));
1747c478bd9Sstevel@tonic-gate #ifdef _ILP32
1757c478bd9Sstevel@tonic-gate }
1767c478bd9Sstevel@tonic-gate #endif
1777c478bd9Sstevel@tonic-gate return (buf);
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
180f6e214c7SGavin Maltby /* BEGIN CSTYLED */
181f6e214c7SGavin Maltby static const char *synopsis =
182f6e214c7SGavin Maltby "Usage: %s [[-e | -i | -I] | -A ] [-f] [-mvVp] [-c class] [-R root]\n"
183f6e214c7SGavin Maltby "\t [-t time ][-T time] [-u uuid] [-n name[.name]*[=value]] "
184f6e214c7SGavin Maltby "[file]...\n "
185f6e214c7SGavin Maltby "Log selection: [-e | -i | -I] or one [file]; default is the fault log\n"
186f6e214c7SGavin Maltby "\t-e display error log content\n"
187f6e214c7SGavin Maltby "\t-i display infolog content\n"
188f6e214c7SGavin Maltby "\t-I display the high-value-infolog content\n"
189f6e214c7SGavin Maltby "\t-R set root directory for pathname expansions\n "
190f6e214c7SGavin Maltby "Command behaviour:\n"
191f6e214c7SGavin Maltby "\t-A Aggregate specified [file]s or, if no [file], all known logs\n"
192f6e214c7SGavin Maltby "\t-f follow growth of log file by waiting for additional data\n "
193f6e214c7SGavin Maltby "Output options:\n"
194f6e214c7SGavin Maltby "\t-m display human-readable messages (only for fault logs)\n"
195f6e214c7SGavin Maltby "\t-v set verbose mode: display additional event detail\n"
196f6e214c7SGavin Maltby "\t-V set very verbose mode: display complete event contents\n"
197f6e214c7SGavin Maltby "\t-p Used with -V: apply some output prettification\n"
198*2db6d663SJoshua M. Clulow "\t-j Used with -V: emit JSON-formatted output\n "
199f6e214c7SGavin Maltby "Selection filters:\n"
200f6e214c7SGavin Maltby "\t-c select events that match the specified class\n"
201f6e214c7SGavin Maltby "\t-t select events that occurred after the specified time\n"
202f6e214c7SGavin Maltby "\t-T select events that occurred before the specified time\n"
203f6e214c7SGavin Maltby "\t-u select events that match the specified diagnosis uuid\n"
204f6e214c7SGavin Maltby "\t-n select events containing named nvpair (with matching value)\n";
205f6e214c7SGavin Maltby /* END CSTYLED */
206f6e214c7SGavin Maltby
2077c478bd9Sstevel@tonic-gate static int
usage(FILE * fp)2087c478bd9Sstevel@tonic-gate usage(FILE *fp)
2097c478bd9Sstevel@tonic-gate {
210f6e214c7SGavin Maltby (void) fprintf(fp, synopsis, g_pname);
2117c478bd9Sstevel@tonic-gate return (FMDUMP_EXIT_USAGE);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2157c478bd9Sstevel@tonic-gate static int
error(fmd_log_t * lp,void * private)2167c478bd9Sstevel@tonic-gate error(fmd_log_t *lp, void *private)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate fmdump_warn("skipping record: %s\n",
2197c478bd9Sstevel@tonic-gate fmd_log_errmsg(lp, fmd_log_errno(lp)));
2207c478bd9Sstevel@tonic-gate return (0);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate * Yet another disgusting argument parsing function (TM). We attempt to parse
2257c478bd9Sstevel@tonic-gate * a time argument in a variety of strptime(3C) formats, in which case it is
2267c478bd9Sstevel@tonic-gate * interpreted as a local time and is converted to a timeval using mktime(3C).
2277c478bd9Sstevel@tonic-gate * If those formats fail, we look to see if the time is a decimal integer
2287c478bd9Sstevel@tonic-gate * followed by one of our magic suffixes, in which case the time is interpreted
2297c478bd9Sstevel@tonic-gate * as a time delta *before* the current time-of-day (i.e. "1h" = "1 hour ago").
2307c478bd9Sstevel@tonic-gate */
2317c478bd9Sstevel@tonic-gate static struct timeval *
gettimeopt(const char * arg)2327c478bd9Sstevel@tonic-gate gettimeopt(const char *arg)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate const struct {
2357c478bd9Sstevel@tonic-gate const char *name;
2367c478bd9Sstevel@tonic-gate hrtime_t mul;
2377c478bd9Sstevel@tonic-gate } suffix[] = {
2387c478bd9Sstevel@tonic-gate { "ns", NANOSEC / NANOSEC },
2397c478bd9Sstevel@tonic-gate { "nsec", NANOSEC / NANOSEC },
2407c478bd9Sstevel@tonic-gate { "us", NANOSEC / MICROSEC },
2417c478bd9Sstevel@tonic-gate { "usec", NANOSEC / MICROSEC },
2427c478bd9Sstevel@tonic-gate { "ms", NANOSEC / MILLISEC },
2437c478bd9Sstevel@tonic-gate { "msec", NANOSEC / MILLISEC },
2447c478bd9Sstevel@tonic-gate { "s", NANOSEC / SEC },
2457c478bd9Sstevel@tonic-gate { "sec", NANOSEC / SEC },
2467c478bd9Sstevel@tonic-gate { "m", NANOSEC * (hrtime_t)60 },
2477c478bd9Sstevel@tonic-gate { "min", NANOSEC * (hrtime_t)60 },
2487c478bd9Sstevel@tonic-gate { "h", NANOSEC * (hrtime_t)(60 * 60) },
2497c478bd9Sstevel@tonic-gate { "hour", NANOSEC * (hrtime_t)(60 * 60) },
2507c478bd9Sstevel@tonic-gate { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) },
2517c478bd9Sstevel@tonic-gate { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) },
2527c478bd9Sstevel@tonic-gate { NULL }
2537c478bd9Sstevel@tonic-gate };
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate struct timeval *tvp = malloc(sizeof (struct timeval));
2567c478bd9Sstevel@tonic-gate struct timeval tod;
2577c478bd9Sstevel@tonic-gate struct tm tm;
2587c478bd9Sstevel@tonic-gate char *p;
2597c478bd9Sstevel@tonic-gate
260f6e214c7SGavin Maltby if (tvp == NULL)
261f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
2627c478bd9Sstevel@tonic-gate
263f6e214c7SGavin Maltby if (gettimeofday(&tod, NULL) != 0)
264f6e214c7SGavin Maltby fmdump_fatal("failed to get tod");
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate * First try a variety of strptime() calls. If these all fail, we'll
2687c478bd9Sstevel@tonic-gate * try parsing an integer followed by one of our suffix[] strings.
2697c478bd9Sstevel@tonic-gate */
27069fcd3d4SYuri Pankov if ((p = strptime(arg, "%m/%d/%Y %H:%M:%S", &tm)) == NULL &&
27169fcd3d4SYuri Pankov (p = strptime(arg, "%m/%d/%y %H:%M:%S", &tm)) == NULL &&
27269fcd3d4SYuri Pankov (p = strptime(arg, "%m/%d/%Y %H:%M", &tm)) == NULL &&
27369fcd3d4SYuri Pankov (p = strptime(arg, "%m/%d/%y %H:%M", &tm)) == NULL &&
2747c478bd9Sstevel@tonic-gate (p = strptime(arg, "%m/%d/%Y", &tm)) == NULL &&
27569fcd3d4SYuri Pankov (p = strptime(arg, "%m/%d/%y", &tm)) == NULL &&
2767c478bd9Sstevel@tonic-gate (p = strptime(arg, "%Y-%m-%dT%H:%M:%S", &tm)) == NULL &&
27769fcd3d4SYuri Pankov (p = strptime(arg, "%y-%m-%dT%H:%M:%S", &tm)) == NULL &&
2787c478bd9Sstevel@tonic-gate (p = strptime(arg, "%Y-%m-%dT%H:%M", &tm)) == NULL &&
27969fcd3d4SYuri Pankov (p = strptime(arg, "%y-%m-%dT%H:%M", &tm)) == NULL &&
2807c478bd9Sstevel@tonic-gate (p = strptime(arg, "%Y-%m-%d", &tm)) == NULL &&
28169fcd3d4SYuri Pankov (p = strptime(arg, "%y-%m-%d", &tm)) == NULL &&
28269fcd3d4SYuri Pankov (p = strptime(arg, "%d%b%Y %H:%M:%S", &tm)) == NULL &&
28369fcd3d4SYuri Pankov (p = strptime(arg, "%d%b%y %H:%M:%S", &tm)) == NULL &&
28469fcd3d4SYuri Pankov (p = strptime(arg, "%d%b%Y %H:%M", &tm)) == NULL &&
28569fcd3d4SYuri Pankov (p = strptime(arg, "%d%b%y %H:%M", &tm)) == NULL &&
2867c478bd9Sstevel@tonic-gate (p = strptime(arg, "%d%b%Y", &tm)) == NULL &&
28769fcd3d4SYuri Pankov (p = strptime(arg, "%d%b%y", &tm)) == NULL &&
28869fcd3d4SYuri Pankov (p = strptime(arg, "%b %d %H:%M:%S", &tm)) == NULL &&
28969fcd3d4SYuri Pankov (p = strptime(arg, "%b %d %H:%M:%S", &tm)) == NULL &&
2907c478bd9Sstevel@tonic-gate (p = strptime(arg, "%H:%M:%S", &tm)) == NULL &&
2917c478bd9Sstevel@tonic-gate (p = strptime(arg, "%H:%M", &tm)) == NULL) {
2927c478bd9Sstevel@tonic-gate
2937c478bd9Sstevel@tonic-gate hrtime_t nsec;
2947c478bd9Sstevel@tonic-gate int i;
2957c478bd9Sstevel@tonic-gate
2967c478bd9Sstevel@tonic-gate errno = 0;
2977c478bd9Sstevel@tonic-gate nsec = strtol(arg, (char **)&p, 10);
2987c478bd9Sstevel@tonic-gate
299f6e214c7SGavin Maltby if (errno != 0 || nsec == 0 || p == arg || *p == '\0')
300f6e214c7SGavin Maltby fmdump_usage("illegal time format -- %s\n", arg);
3017c478bd9Sstevel@tonic-gate
3027c478bd9Sstevel@tonic-gate for (i = 0; suffix[i].name != NULL; i++) {
3037c478bd9Sstevel@tonic-gate if (strcasecmp(suffix[i].name, p) == 0) {
3047c478bd9Sstevel@tonic-gate nsec *= suffix[i].mul;
3057c478bd9Sstevel@tonic-gate break;
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate }
3087c478bd9Sstevel@tonic-gate
309f6e214c7SGavin Maltby if (suffix[i].name == NULL)
310f6e214c7SGavin Maltby fmdump_usage("illegal time format -- %s\n", arg);
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate tvp->tv_sec = nsec / NANOSEC;
3137c478bd9Sstevel@tonic-gate tvp->tv_usec = (nsec % NANOSEC) / (NANOSEC / MICROSEC);
3147c478bd9Sstevel@tonic-gate
315f6e214c7SGavin Maltby if (tvp->tv_sec > tod.tv_sec)
316f6e214c7SGavin Maltby fmdump_usage("time delta precedes UTC time origin "
317f6e214c7SGavin Maltby "-- %s\n", arg);
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate tvp->tv_sec = tod.tv_sec - tvp->tv_sec;
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate } else if (*p == '\0' || *p == '.') {
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate * If tm_year is zero, we matched [%b %d] %H:%M[:%S]; use
3247c478bd9Sstevel@tonic-gate * the result of localtime(&tod.tv_sec) to fill in the rest.
3257c478bd9Sstevel@tonic-gate */
3267c478bd9Sstevel@tonic-gate if (tm.tm_year == 0) {
3277c478bd9Sstevel@tonic-gate int h = tm.tm_hour;
3287c478bd9Sstevel@tonic-gate int m = tm.tm_min;
3297c478bd9Sstevel@tonic-gate int s = tm.tm_sec;
3307c478bd9Sstevel@tonic-gate int b = tm.tm_mon;
3317c478bd9Sstevel@tonic-gate int d = tm.tm_mday;
3327c478bd9Sstevel@tonic-gate
3337c478bd9Sstevel@tonic-gate bcopy(localtime(&tod.tv_sec), &tm, sizeof (tm));
3347c478bd9Sstevel@tonic-gate tm.tm_isdst = 0; /* see strptime(3C) and below */
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate if (d > 0) {
3377c478bd9Sstevel@tonic-gate tm.tm_mon = b;
3387c478bd9Sstevel@tonic-gate tm.tm_mday = d;
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate tm.tm_hour = h;
3427c478bd9Sstevel@tonic-gate tm.tm_min = m;
3437c478bd9Sstevel@tonic-gate tm.tm_sec = s;
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate errno = 0;
3477c478bd9Sstevel@tonic-gate tvp->tv_sec = mktime(&tm);
3487c478bd9Sstevel@tonic-gate tvp->tv_usec = 0;
3497c478bd9Sstevel@tonic-gate
350f6e214c7SGavin Maltby if (tvp->tv_sec == -1L && errno != 0)
351f6e214c7SGavin Maltby fmdump_fatal("failed to compose time %s", arg);
3527c478bd9Sstevel@tonic-gate
3537c478bd9Sstevel@tonic-gate /*
3547c478bd9Sstevel@tonic-gate * If our mktime() set tm_isdst, adjust the result for DST by
3557c478bd9Sstevel@tonic-gate * subtracting the offset between the main and alternate zones.
3567c478bd9Sstevel@tonic-gate */
3577c478bd9Sstevel@tonic-gate if (tm.tm_isdst)
3587c478bd9Sstevel@tonic-gate tvp->tv_sec -= timezone - altzone;
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate if (p[0] == '.') {
3617c478bd9Sstevel@tonic-gate arg = p;
3627c478bd9Sstevel@tonic-gate errno = 0;
3637c478bd9Sstevel@tonic-gate tvp->tv_usec =
3647c478bd9Sstevel@tonic-gate (suseconds_t)(strtod(arg, &p) * (double)MICROSEC);
3657c478bd9Sstevel@tonic-gate
366f6e214c7SGavin Maltby if (errno != 0 || p == arg || *p != '\0')
367f6e214c7SGavin Maltby fmdump_usage("illegal time suffix -- .%s\n",
368f6e214c7SGavin Maltby arg);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate } else {
372f6e214c7SGavin Maltby fmdump_usage("unexpected suffix after time %s -- %s\n", arg, p);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate return (tvp);
3767c478bd9Sstevel@tonic-gate }
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate /*
3797c478bd9Sstevel@tonic-gate * If the -u option is specified in combination with the -e option, we iterate
3807c478bd9Sstevel@tonic-gate * over each record in the fault log with a matching UUID finding xrefs to the
3817c478bd9Sstevel@tonic-gate * error log, and then use this function to iterate over every xref'd record.
3827c478bd9Sstevel@tonic-gate */
3837c478bd9Sstevel@tonic-gate int
xref_iter(fmd_log_t * lp,const fmd_log_record_t * rp,void * arg)3847c478bd9Sstevel@tonic-gate xref_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
3857c478bd9Sstevel@tonic-gate {
3867c478bd9Sstevel@tonic-gate const fmd_log_record_t *xrp = rp->rec_xrefs;
3877c478bd9Sstevel@tonic-gate fmdump_arg_t *dap = arg;
3887c478bd9Sstevel@tonic-gate int i, rv = 0;
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate for (i = 0; rv == 0 && i < rp->rec_nrefs; i++, xrp++) {
3917c478bd9Sstevel@tonic-gate if (fmd_log_filter(lp, dap->da_fc, dap->da_fv, xrp))
3927c478bd9Sstevel@tonic-gate rv = dap->da_fmt->do_func(lp, xrp, dap->da_fp);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate return (rv);
3967c478bd9Sstevel@tonic-gate }
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate int
xoff_iter(fmd_log_t * lp,const fmd_log_record_t * rp,void * arg)3997c478bd9Sstevel@tonic-gate xoff_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate fmdump_lyr_t *dyp = arg;
4027c478bd9Sstevel@tonic-gate
4037c478bd9Sstevel@tonic-gate fmdump_printf(dyp->dy_fp, "%16llx ", (u_longlong_t)rp->rec_off);
4047c478bd9Sstevel@tonic-gate return (dyp->dy_func(lp, rp, dyp->dy_arg));
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /*
408602ca9eaScth * Initialize fmd_log_filter_nvarg_t from -n name=value argument string.
409602ca9eaScth */
410602ca9eaScth static fmd_log_filter_nvarg_t *
setupnamevalue(char * namevalue)411602ca9eaScth setupnamevalue(char *namevalue)
412602ca9eaScth {
413602ca9eaScth fmd_log_filter_nvarg_t *argt;
414602ca9eaScth char *value;
415602ca9eaScth regex_t *value_regex = NULL;
416602ca9eaScth char errstr[128];
417602ca9eaScth int rv;
418602ca9eaScth
419602ca9eaScth if ((value = strchr(namevalue, '=')) == NULL) {
420602ca9eaScth value_regex = NULL;
421602ca9eaScth } else {
422602ca9eaScth *value++ = '\0'; /* separate name and value string */
423602ca9eaScth
424602ca9eaScth /*
425602ca9eaScth * Skip white space before value to facilitate direct
426602ca9eaScth * cut/paste from previous fmdump output.
427602ca9eaScth */
428602ca9eaScth while (isspace(*value))
429602ca9eaScth value++;
430602ca9eaScth
431f6e214c7SGavin Maltby if ((value_regex = malloc(sizeof (regex_t))) == NULL)
432f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
433602ca9eaScth
434602ca9eaScth /* compile regular expression for possible string match */
435602ca9eaScth if ((rv = regcomp(value_regex, value,
436602ca9eaScth REG_NOSUB|REG_NEWLINE)) != 0) {
437602ca9eaScth (void) regerror(rv, value_regex, errstr,
438602ca9eaScth sizeof (errstr));
439602ca9eaScth free(value_regex);
440f6e214c7SGavin Maltby fmdump_usage("unexpected regular expression in "
441f6e214c7SGavin Maltby "%s: %s\n", value, errstr);
442602ca9eaScth }
443602ca9eaScth }
444602ca9eaScth
445f6e214c7SGavin Maltby if ((argt = malloc(sizeof (fmd_log_filter_nvarg_t))) == NULL)
446f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
447f6e214c7SGavin Maltby
448602ca9eaScth argt->nvarg_name = namevalue; /* now just name */
449602ca9eaScth argt->nvarg_value = value;
450602ca9eaScth argt->nvarg_value_regex = value_regex;
451602ca9eaScth return (argt);
452602ca9eaScth }
453602ca9eaScth
454602ca9eaScth /*
4557c478bd9Sstevel@tonic-gate * If the -a option is not present, filter out fault records that correspond
4567c478bd9Sstevel@tonic-gate * to events that the producer requested not be messaged for administrators.
4577c478bd9Sstevel@tonic-gate */
4587c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4597c478bd9Sstevel@tonic-gate int
log_filter_silent(fmd_log_t * lp,const fmd_log_record_t * rp,void * arg)4607c478bd9Sstevel@tonic-gate log_filter_silent(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
4617c478bd9Sstevel@tonic-gate {
462f6e214c7SGavin Maltby int opt_A = (arg != NULL);
4637c478bd9Sstevel@tonic-gate boolean_t msg;
464f6e214c7SGavin Maltby char *class;
465f6e214c7SGavin Maltby
466f6e214c7SGavin Maltby /*
467f6e214c7SGavin Maltby * If -A was used then apply this filter only to events of list class
468f6e214c7SGavin Maltby */
469f6e214c7SGavin Maltby if (opt_A) {
470f6e214c7SGavin Maltby if (nvlist_lookup_string(rp->rec_nvl, FM_CLASS, &class) != 0 ||
471f6e214c7SGavin Maltby strncmp(class, FM_LIST_EVENT ".",
472f6e214c7SGavin Maltby sizeof (FM_LIST_EVENT)) != 0)
473f6e214c7SGavin Maltby return (1);
474f6e214c7SGavin Maltby }
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate return (nvlist_lookup_boolean_value(rp->rec_nvl,
4777c478bd9Sstevel@tonic-gate FM_SUSPECT_MESSAGE, &msg) != 0 || msg != 0);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate
480c93c462eSCheng Sean Ye struct loglink {
481c93c462eSCheng Sean Ye char *path;
482c93c462eSCheng Sean Ye long suffix;
483c93c462eSCheng Sean Ye struct loglink *next;
484c93c462eSCheng Sean Ye };
485c93c462eSCheng Sean Ye
486c93c462eSCheng Sean Ye static void
addlink(struct loglink ** llp,char * dirname,char * logname,long suffix)487c93c462eSCheng Sean Ye addlink(struct loglink **llp, char *dirname, char *logname, long suffix)
488c93c462eSCheng Sean Ye {
489c93c462eSCheng Sean Ye struct loglink *newp;
490c93c462eSCheng Sean Ye size_t len;
491c93c462eSCheng Sean Ye char *str;
492c93c462eSCheng Sean Ye
493c93c462eSCheng Sean Ye newp = malloc(sizeof (struct loglink));
494c93c462eSCheng Sean Ye len = strlen(dirname) + strlen(logname) + 2;
495c93c462eSCheng Sean Ye str = malloc(len);
496f6e214c7SGavin Maltby if (newp == NULL || str == NULL)
497f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
498c93c462eSCheng Sean Ye
499c93c462eSCheng Sean Ye (void) snprintf(str, len, "%s/%s", dirname, logname);
500c93c462eSCheng Sean Ye newp->path = str;
501c93c462eSCheng Sean Ye newp->suffix = suffix;
502c93c462eSCheng Sean Ye
503c93c462eSCheng Sean Ye while (*llp != NULL && suffix < (*llp)->suffix)
504c93c462eSCheng Sean Ye llp = &(*llp)->next;
505c93c462eSCheng Sean Ye
506c93c462eSCheng Sean Ye newp->next = *llp;
507c93c462eSCheng Sean Ye *llp = newp;
508c93c462eSCheng Sean Ye }
509c93c462eSCheng Sean Ye
510c93c462eSCheng Sean Ye /*
511c93c462eSCheng Sean Ye * Find and return all the rotated logs.
512c93c462eSCheng Sean Ye */
513c93c462eSCheng Sean Ye static struct loglink *
get_rotated_logs(char * logpath)514c93c462eSCheng Sean Ye get_rotated_logs(char *logpath)
515c93c462eSCheng Sean Ye {
516c93c462eSCheng Sean Ye char dirname[PATH_MAX], *logname, *endptr;
517c93c462eSCheng Sean Ye DIR *dirp;
518c93c462eSCheng Sean Ye struct dirent *dp;
519c93c462eSCheng Sean Ye long len, suffix;
520c93c462eSCheng Sean Ye struct loglink *head = NULL;
521c93c462eSCheng Sean Ye
522c93c462eSCheng Sean Ye (void) strlcpy(dirname, logpath, sizeof (dirname));
523c93c462eSCheng Sean Ye logname = strrchr(dirname, '/');
524c93c462eSCheng Sean Ye *logname++ = '\0';
525c93c462eSCheng Sean Ye len = strlen(logname);
526c93c462eSCheng Sean Ye
527c93c462eSCheng Sean Ye if ((dirp = opendir(dirname)) == NULL) {
528f6e214c7SGavin Maltby fmdump_warn("failed to opendir `%s'", dirname);
529f6e214c7SGavin Maltby g_errs++;
530c93c462eSCheng Sean Ye return (NULL);
531c93c462eSCheng Sean Ye }
532c93c462eSCheng Sean Ye
533c93c462eSCheng Sean Ye while ((dp = readdir(dirp)) != NULL) {
534c93c462eSCheng Sean Ye /*
535c93c462eSCheng Sean Ye * Search the log directory for logs named "<logname>.0",
536c93c462eSCheng Sean Ye * "<logname>.1", etc and add to the link in the
537c93c462eSCheng Sean Ye * reverse numeric order.
538c93c462eSCheng Sean Ye */
539c93c462eSCheng Sean Ye if (strlen(dp->d_name) < len + 2 ||
540c93c462eSCheng Sean Ye strncmp(dp->d_name, logname, len) != 0 ||
541c93c462eSCheng Sean Ye dp->d_name[len] != '.')
542c93c462eSCheng Sean Ye continue;
543c93c462eSCheng Sean Ye
544c93c462eSCheng Sean Ye /*
545c93c462eSCheng Sean Ye * "*.0-" file normally should not be seen. It may
546c93c462eSCheng Sean Ye * exist when user manually run 'fmadm rotate'.
547c93c462eSCheng Sean Ye * In such case, we put it at the end of the list so
548c93c462eSCheng Sean Ye * it'll be dumped after all the rotated logs, before
549c93c462eSCheng Sean Ye * the current one.
550c93c462eSCheng Sean Ye */
551c93c462eSCheng Sean Ye if (strcmp(dp->d_name + len + 1, "0-") == 0)
552c93c462eSCheng Sean Ye addlink(&head, dirname, dp->d_name, -1);
553c93c462eSCheng Sean Ye else if ((suffix = strtol(dp->d_name + len + 1,
554c93c462eSCheng Sean Ye &endptr, 10)) >= 0 && *endptr == '\0')
555c93c462eSCheng Sean Ye addlink(&head, dirname, dp->d_name, suffix);
556c93c462eSCheng Sean Ye }
557c93c462eSCheng Sean Ye
558c93c462eSCheng Sean Ye (void) closedir(dirp);
559c93c462eSCheng Sean Ye
560c93c462eSCheng Sean Ye return (head);
561c93c462eSCheng Sean Ye }
562c93c462eSCheng Sean Ye
563f6e214c7SGavin Maltby /*
564f6e214c7SGavin Maltby * Aggregate log files. If ifiles is not NULL then one or more files
565f6e214c7SGavin Maltby * were listed on the command line, and we will merge just those files.
566f6e214c7SGavin Maltby * Otherwise we will merge all known log file types, and include the
567f6e214c7SGavin Maltby * rotated logs for each type (you can suppress the inclusion of
568f6e214c7SGavin Maltby * some logtypes through use of FMDUMP_AGGREGATE_IGNORE in the process
569f6e214c7SGavin Maltby * environment, setting it to a comma-separated list of log labels and/or
570f6e214c7SGavin Maltby * log filenames to ignore).
571f6e214c7SGavin Maltby *
572f6e214c7SGavin Maltby * We will not attempt to perform a chronological sort across all log records
573f6e214c7SGavin Maltby * of all files. Indeed, we won't even sort individual log files -
574f6e214c7SGavin Maltby * we will not re-order events differently to how they appeared in their
575f6e214c7SGavin Maltby * original log file. This is because log files are already inherently
576f6e214c7SGavin Maltby * ordered by the order in which fmd receives and processes events.
577f6e214c7SGavin Maltby * So we determine the output order by comparing the "next" record
578f6e214c7SGavin Maltby * off the top of each log file.
579f6e214c7SGavin Maltby *
580f6e214c7SGavin Maltby * We will construct a number of log record source "pipelines". As above,
581f6e214c7SGavin Maltby * the next record to render in the overall output is that from the
582f6e214c7SGavin Maltby * pipeline with the oldest event.
583f6e214c7SGavin Maltby *
584f6e214c7SGavin Maltby * For the case that input logfiles were listed on the command line, each
585f6e214c7SGavin Maltby * pipeline will process exactly one of those logfiles. Distinct pipelines
586f6e214c7SGavin Maltby * may process logfiles of the same "type" - eg if two "error" logs and
587f6e214c7SGavin Maltby * one "fault" logs are specified then there'll be two pipelines producing
588f6e214c7SGavin Maltby * events from "error" logs.
589f6e214c7SGavin Maltby *
590f6e214c7SGavin Maltby * If we are merging all known log types then we will construct exactly
591f6e214c7SGavin Maltby * one pipeline for each known log type - one for error, one for fault, etc.
592f6e214c7SGavin Maltby * Each pipeline will process first the rotated logs of that type and then
593f6e214c7SGavin Maltby * move on to the current log of that type.
594f6e214c7SGavin Maltby *
595f6e214c7SGavin Maltby * The output from all pipelines flows into a serializer which selects
596f6e214c7SGavin Maltby * the next record once all pipelines have asserted their output state.
597f6e214c7SGavin Maltby * The output state of a pipeline is one of:
598f6e214c7SGavin Maltby *
599f6e214c7SGavin Maltby * - record available: the next record from this pipeline is available
600f6e214c7SGavin Maltby * for comparison and consumption
601f6e214c7SGavin Maltby *
602f6e214c7SGavin Maltby * - done: this pipeline will produce no more records
603f6e214c7SGavin Maltby *
604f6e214c7SGavin Maltby * - polling: this pipeline is polling for new records and will
605f6e214c7SGavin Maltby * make them available as output if/when any are observed
606f6e214c7SGavin Maltby *
607f6e214c7SGavin Maltby * - processing: output state will be updated shortly
608f6e214c7SGavin Maltby *
609f6e214c7SGavin Maltby * A pipeline iterates over each file queued to it using fmd_log_xiter.
610f6e214c7SGavin Maltby * We do this in a separate thread for each pipeline. The callback on
611f6e214c7SGavin Maltby * each iteration must update the serializer to let it know that
612f6e214c7SGavin Maltby * a new record is available. In the serializer thread we decide whether
613f6e214c7SGavin Maltby * we have all records expected have arrived and it is time to choose
614f6e214c7SGavin Maltby * the next output record.
615f6e214c7SGavin Maltby */
616f6e214c7SGavin Maltby
617f6e214c7SGavin Maltby /*
618f6e214c7SGavin Maltby * A pipeline descriptor. The pl_cv condition variable is used together
619f6e214c7SGavin Maltby * with pl_lock for initial synchronisation, and thereafter with the
620f6e214c7SGavin Maltby * lock for the serializer for pausing and continuing this pipeline.
621f6e214c7SGavin Maltby */
622f6e214c7SGavin Maltby struct fmdump_pipeline {
623f6e214c7SGavin Maltby pthread_mutex_t pl_lock; /* used only in pipeline startup */
624f6e214c7SGavin Maltby int pl_started; /* sync with main thread on startup */
625f6e214c7SGavin Maltby pthread_t pl_thr; /* our processing thread */
626f6e214c7SGavin Maltby pthread_cond_t pl_cv; /* see above */
627f6e214c7SGavin Maltby struct loglink *pl_rotated; /* rotated logs to process first */
628f6e214c7SGavin Maltby char *pl_logpath; /* target path to process */
629f6e214c7SGavin Maltby char *pl_processing; /* path currently being processed */
630f6e214c7SGavin Maltby struct fmdump_srlzer *pl_srlzer; /* link to serializer */
631f6e214c7SGavin Maltby int pl_srlzeridx; /* serializer index for this pipeline */
632f6e214c7SGavin Maltby const fmdump_ops_t *pl_ops; /* ops for the log type we're given */
633f6e214c7SGavin Maltby int pl_fmt; /* FMDUMP_{SHORT,VERB1,VERB2,PRETTY} */
634f6e214c7SGavin Maltby boolean_t pl_follow; /* go into poll mode at log end */
635f6e214c7SGavin Maltby fmdump_arg_t pl_arg; /* arguments */
636f6e214c7SGavin Maltby };
637f6e214c7SGavin Maltby
638f6e214c7SGavin Maltby enum fmdump_pipestate {
639f6e214c7SGavin Maltby FMDUMP_PIPE_PROCESSING = 0x1000,
640f6e214c7SGavin Maltby FMDUMP_PIPE_RECORDAVAIL,
641f6e214c7SGavin Maltby FMDUMP_PIPE_POLLING,
642f6e214c7SGavin Maltby FMDUMP_PIPE_DONE
643f6e214c7SGavin Maltby };
644f6e214c7SGavin Maltby
645f6e214c7SGavin Maltby /*
646f6e214c7SGavin Maltby * Each pipeline has an associated output slot in the serializer. This
647f6e214c7SGavin Maltby * must be updated with the serializer locked. After update evaluate
648f6e214c7SGavin Maltby * whether there are enough slots decided that we should select a
649f6e214c7SGavin Maltby * record to output.
650f6e214c7SGavin Maltby */
651f6e214c7SGavin Maltby struct fmdump_srlzer_slot {
652f6e214c7SGavin Maltby enum fmdump_pipestate ss_state;
653f6e214c7SGavin Maltby uint64_t ss_sec;
654f6e214c7SGavin Maltby uint64_t ss_nsec;
655f6e214c7SGavin Maltby };
656f6e214c7SGavin Maltby
657f6e214c7SGavin Maltby /*
658f6e214c7SGavin Maltby * All pipelines are linked to a single serializer. The serializer
659f6e214c7SGavin Maltby * structure must be updated under the ds_lock; this mutex is also
660f6e214c7SGavin Maltby * paired with the pl_cv of individual pipelines (one mutex, many condvars)
661f6e214c7SGavin Maltby * in pausing and continuing individual pipelines.
662f6e214c7SGavin Maltby */
663f6e214c7SGavin Maltby struct fmdump_srlzer {
664f6e214c7SGavin Maltby struct fmdump_pipeline *ds_pipearr; /* pipeline array */
665f6e214c7SGavin Maltby pthread_mutex_t ds_lock; /* see above */
666f6e214c7SGavin Maltby uint32_t ds_pipecnt; /* number of pipelines */
667f6e214c7SGavin Maltby uint32_t ds_pollcnt; /* pipelines in poll mode */
668f6e214c7SGavin Maltby uint32_t ds_nrecordavail; /* pipelines with a record */
669f6e214c7SGavin Maltby uint32_t ds_ndone; /* completed pipelines */
670f6e214c7SGavin Maltby struct fmdump_srlzer_slot *ds_slot; /* slot array */
671f6e214c7SGavin Maltby };
672f6e214c7SGavin Maltby
673f6e214c7SGavin Maltby /*
674f6e214c7SGavin Maltby * All known log types. When aggregation is requested an no file list
675f6e214c7SGavin Maltby * is provided we will process the logs identified here (if lt_enabled
676f6e214c7SGavin Maltby * is true and not over-ridden by environment settings). We also
677f6e214c7SGavin Maltby * use this in determining the appropriate ops structure for each distinct
678f6e214c7SGavin Maltby * label.
679f6e214c7SGavin Maltby */
680f6e214c7SGavin Maltby static struct fmdump_logtype {
681f6e214c7SGavin Maltby const char *lt_label; /* label from log header */
682f6e214c7SGavin Maltby boolean_t lt_enabled; /* include in merge? */
683f6e214c7SGavin Maltby const char *lt_logname; /* var/fm/fmd/%s */
684f6e214c7SGavin Maltby const fmdump_ops_t *lt_ops;
685f6e214c7SGavin Maltby } logtypes[] = {
686f6e214c7SGavin Maltby {
687f6e214c7SGavin Maltby "error",
688f6e214c7SGavin Maltby B_TRUE,
689f6e214c7SGavin Maltby "errlog",
690f6e214c7SGavin Maltby &fmdump_err_ops
691f6e214c7SGavin Maltby },
692f6e214c7SGavin Maltby {
693f6e214c7SGavin Maltby "fault",
694f6e214c7SGavin Maltby B_TRUE,
695f6e214c7SGavin Maltby "fltlog",
696f6e214c7SGavin Maltby &fmdump_flt_ops
697f6e214c7SGavin Maltby },
698f6e214c7SGavin Maltby {
699f6e214c7SGavin Maltby "info",
700f6e214c7SGavin Maltby B_TRUE,
701f6e214c7SGavin Maltby "infolog",
702f6e214c7SGavin Maltby &fmdump_info_ops
703f6e214c7SGavin Maltby },
704f6e214c7SGavin Maltby {
705f6e214c7SGavin Maltby "info",
706f6e214c7SGavin Maltby B_TRUE,
707f6e214c7SGavin Maltby "infolog_hival",
708f6e214c7SGavin Maltby &fmdump_info_ops
709f6e214c7SGavin Maltby },
710f6e214c7SGavin Maltby {
711f6e214c7SGavin Maltby "asru",
712f6e214c7SGavin Maltby B_FALSE, /* not included unless in file list */
713f6e214c7SGavin Maltby NULL,
714f6e214c7SGavin Maltby &fmdump_asru_ops /* but we need ops when it is */
715f6e214c7SGavin Maltby }
716f6e214c7SGavin Maltby };
717f6e214c7SGavin Maltby
718f6e214c7SGavin Maltby /*
719f6e214c7SGavin Maltby * Disable logtypes per environment setting. Does not apply when a list
720f6e214c7SGavin Maltby * of logs is provided on the command line.
721f6e214c7SGavin Maltby */
722f6e214c7SGavin Maltby static void
do_disables(void)723f6e214c7SGavin Maltby do_disables(void)
724f6e214c7SGavin Maltby {
725f6e214c7SGavin Maltby char *env = getenv("FMDUMP_AGGREGATE_IGNORE");
726f6e214c7SGavin Maltby char *dup, *start, *tofree;
727f6e214c7SGavin Maltby int i;
728f6e214c7SGavin Maltby
729f6e214c7SGavin Maltby if (env == NULL)
730f6e214c7SGavin Maltby return;
731f6e214c7SGavin Maltby
732f6e214c7SGavin Maltby tofree = dup = strdup(env);
733f6e214c7SGavin Maltby
734f6e214c7SGavin Maltby while (dup != NULL) {
735f6e214c7SGavin Maltby start = strsep(&dup, ",");
736f6e214c7SGavin Maltby for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) {
737f6e214c7SGavin Maltby if (logtypes[i].lt_logname == NULL)
738f6e214c7SGavin Maltby continue;
739f6e214c7SGavin Maltby
740f6e214c7SGavin Maltby if (strcmp(start, logtypes[i].lt_label) == 0 ||
741f6e214c7SGavin Maltby strcmp(start, logtypes[i].lt_logname) == 0) {
742f6e214c7SGavin Maltby logtypes[i].lt_enabled = B_FALSE;
743f6e214c7SGavin Maltby }
744f6e214c7SGavin Maltby }
745f6e214c7SGavin Maltby }
746f6e214c7SGavin Maltby
747f6e214c7SGavin Maltby free(tofree);
748f6e214c7SGavin Maltby }
749f6e214c7SGavin Maltby
750f6e214c7SGavin Maltby static void
srlzer_enter(struct fmdump_pipeline * pl)751f6e214c7SGavin Maltby srlzer_enter(struct fmdump_pipeline *pl)
752f6e214c7SGavin Maltby {
753f6e214c7SGavin Maltby struct fmdump_srlzer *srlzer = pl->pl_srlzer;
754f6e214c7SGavin Maltby
755f6e214c7SGavin Maltby (void) pthread_mutex_lock(&srlzer->ds_lock);
756f6e214c7SGavin Maltby }
757f6e214c7SGavin Maltby
758f6e214c7SGavin Maltby static void
srlzer_exit(struct fmdump_pipeline * pl)759f6e214c7SGavin Maltby srlzer_exit(struct fmdump_pipeline *pl)
760f6e214c7SGavin Maltby {
761f6e214c7SGavin Maltby struct fmdump_srlzer *srlzer = pl->pl_srlzer;
762f6e214c7SGavin Maltby
763f6e214c7SGavin Maltby ASSERT(MUTEX_HELD(&srlzer->ds_lock));
764f6e214c7SGavin Maltby (void) pthread_mutex_unlock(&srlzer->ds_lock);
765f6e214c7SGavin Maltby }
766f6e214c7SGavin Maltby
767f6e214c7SGavin Maltby static struct fmdump_pipeline *
srlzer_choose(struct fmdump_srlzer * srlzer)768f6e214c7SGavin Maltby srlzer_choose(struct fmdump_srlzer *srlzer)
769f6e214c7SGavin Maltby {
770f6e214c7SGavin Maltby struct fmdump_srlzer_slot *slot, *oldest;
771f6e214c7SGavin Maltby int oldestidx = -1;
772f6e214c7SGavin Maltby int first = 1;
773f6e214c7SGavin Maltby int i;
774f6e214c7SGavin Maltby
775f6e214c7SGavin Maltby ASSERT(MUTEX_HELD(&srlzer->ds_lock));
776f6e214c7SGavin Maltby
777f6e214c7SGavin Maltby for (i = 0, slot = &srlzer->ds_slot[0]; i < srlzer->ds_pipecnt;
778f6e214c7SGavin Maltby i++, slot++) {
779f6e214c7SGavin Maltby if (slot->ss_state != FMDUMP_PIPE_RECORDAVAIL)
780f6e214c7SGavin Maltby continue;
781f6e214c7SGavin Maltby
782f6e214c7SGavin Maltby if (first) {
783f6e214c7SGavin Maltby oldest = slot;
784f6e214c7SGavin Maltby oldestidx = i;
785f6e214c7SGavin Maltby first = 0;
786f6e214c7SGavin Maltby continue;
787f6e214c7SGavin Maltby }
788f6e214c7SGavin Maltby
789f6e214c7SGavin Maltby if (slot->ss_sec < oldest->ss_sec ||
790f6e214c7SGavin Maltby slot->ss_sec == oldest->ss_sec &&
791f6e214c7SGavin Maltby slot->ss_nsec < oldest->ss_nsec) {
792f6e214c7SGavin Maltby oldest = slot;
793f6e214c7SGavin Maltby oldestidx = i;
794f6e214c7SGavin Maltby }
795f6e214c7SGavin Maltby }
796f6e214c7SGavin Maltby
797f6e214c7SGavin Maltby return (oldestidx >= 0 ? &srlzer->ds_pipearr[oldestidx] : NULL);
798f6e214c7SGavin Maltby }
799f6e214c7SGavin Maltby
800f6e214c7SGavin Maltby static void
pipeline_stall(struct fmdump_pipeline * pl)801f6e214c7SGavin Maltby pipeline_stall(struct fmdump_pipeline *pl)
802f6e214c7SGavin Maltby {
803f6e214c7SGavin Maltby struct fmdump_srlzer *srlzer = pl->pl_srlzer;
804f6e214c7SGavin Maltby
805f6e214c7SGavin Maltby ASSERT(MUTEX_HELD(&srlzer->ds_lock));
806f6e214c7SGavin Maltby (void) pthread_cond_wait(&pl->pl_cv, &srlzer->ds_lock);
807f6e214c7SGavin Maltby }
808f6e214c7SGavin Maltby
809f6e214c7SGavin Maltby static void
pipeline_continue(struct fmdump_pipeline * pl)810f6e214c7SGavin Maltby pipeline_continue(struct fmdump_pipeline *pl)
811f6e214c7SGavin Maltby {
812f6e214c7SGavin Maltby struct fmdump_srlzer *srlzer = pl->pl_srlzer;
813f6e214c7SGavin Maltby
814f6e214c7SGavin Maltby ASSERT(MUTEX_HELD(&srlzer->ds_lock));
815f6e214c7SGavin Maltby (void) pthread_cond_signal(&srlzer->ds_pipearr[pl->pl_srlzeridx].pl_cv);
816f6e214c7SGavin Maltby }
817f6e214c7SGavin Maltby
818f6e214c7SGavin Maltby /*
819f6e214c7SGavin Maltby * Called on each pipeline record iteration to make a new record
820f6e214c7SGavin Maltby * available for input to the serializer. Returns 0 to indicate that
821f6e214c7SGavin Maltby * the caller must stall the pipeline, or 1 to indicate that the
822f6e214c7SGavin Maltby * caller should go ahead and render their record. If this record
823f6e214c7SGavin Maltby * addition fills the serializer then choose a pipeline that must
824f6e214c7SGavin Maltby * render output.
825f6e214c7SGavin Maltby */
826f6e214c7SGavin Maltby static int
pipeline_output(struct fmdump_pipeline * pl,const fmd_log_record_t * rp)827f6e214c7SGavin Maltby pipeline_output(struct fmdump_pipeline *pl, const fmd_log_record_t *rp)
828f6e214c7SGavin Maltby {
829f6e214c7SGavin Maltby struct fmdump_srlzer *srlzer = pl->pl_srlzer;
830f6e214c7SGavin Maltby struct fmdump_srlzer_slot *slot;
831f6e214c7SGavin Maltby struct fmdump_pipeline *wpl;
832f6e214c7SGavin Maltby int thisidx = pl->pl_srlzeridx;
833f6e214c7SGavin Maltby
834f6e214c7SGavin Maltby ASSERT(MUTEX_HELD(&srlzer->ds_lock));
835f6e214c7SGavin Maltby
836f6e214c7SGavin Maltby slot = &srlzer->ds_slot[thisidx];
837f6e214c7SGavin Maltby slot->ss_state = FMDUMP_PIPE_RECORDAVAIL;
838f6e214c7SGavin Maltby slot->ss_sec = rp->rec_sec;
839f6e214c7SGavin Maltby slot->ss_nsec = rp->rec_nsec;
840f6e214c7SGavin Maltby srlzer->ds_nrecordavail++;
841f6e214c7SGavin Maltby
842f6e214c7SGavin Maltby /*
843f6e214c7SGavin Maltby * Once all pipelines are polling we just render in arrival order.
844f6e214c7SGavin Maltby */
845f6e214c7SGavin Maltby if (srlzer->ds_pollcnt == srlzer->ds_pipecnt)
846f6e214c7SGavin Maltby return (1);
847f6e214c7SGavin Maltby
848f6e214c7SGavin Maltby /*
849f6e214c7SGavin Maltby * If not all pipelines have asserted an output yet then the
850f6e214c7SGavin Maltby * caller must block.
851f6e214c7SGavin Maltby */
852f6e214c7SGavin Maltby if (srlzer->ds_nrecordavail + srlzer->ds_ndone +
853f6e214c7SGavin Maltby srlzer->ds_pollcnt < srlzer->ds_pipecnt)
854f6e214c7SGavin Maltby return (0);
855f6e214c7SGavin Maltby
856f6e214c7SGavin Maltby /*
857f6e214c7SGavin Maltby * Right so it's time to turn the crank by choosing which of the
858f6e214c7SGavin Maltby * filled line of slots should produce output. If it is the slot
859f6e214c7SGavin Maltby * for our caller then return their index to them, otherwise return
860f6e214c7SGavin Maltby * -1 to the caller to make them block and cv_signal the winner.
861f6e214c7SGavin Maltby */
862f6e214c7SGavin Maltby wpl = srlzer_choose(srlzer);
863f6e214c7SGavin Maltby ASSERT(wpl != NULL);
864f6e214c7SGavin Maltby
865f6e214c7SGavin Maltby if (wpl == pl)
866f6e214c7SGavin Maltby return (1);
867f6e214c7SGavin Maltby
868f6e214c7SGavin Maltby /* Wake the oldest, and return 0 to put the caller to sleep */
869f6e214c7SGavin Maltby pipeline_continue(wpl);
870f6e214c7SGavin Maltby
871f6e214c7SGavin Maltby return (0);
872f6e214c7SGavin Maltby }
873f6e214c7SGavin Maltby
874f6e214c7SGavin Maltby static void
pipeline_mark_consumed(struct fmdump_pipeline * pl)875f6e214c7SGavin Maltby pipeline_mark_consumed(struct fmdump_pipeline *pl)
876f6e214c7SGavin Maltby {
877f6e214c7SGavin Maltby struct fmdump_srlzer *srlzer = pl->pl_srlzer;
878f6e214c7SGavin Maltby
879f6e214c7SGavin Maltby ASSERT(MUTEX_HELD(&srlzer->ds_lock));
880f6e214c7SGavin Maltby srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_PROCESSING;
881f6e214c7SGavin Maltby srlzer->ds_nrecordavail--;
882f6e214c7SGavin Maltby }
883f6e214c7SGavin Maltby
884f6e214c7SGavin Maltby static void
pipeline_done(struct fmdump_pipeline * pl)885f6e214c7SGavin Maltby pipeline_done(struct fmdump_pipeline *pl)
886f6e214c7SGavin Maltby {
887f6e214c7SGavin Maltby struct fmdump_srlzer *srlzer = pl->pl_srlzer;
888f6e214c7SGavin Maltby struct fmdump_pipeline *wpl;
889f6e214c7SGavin Maltby
890f6e214c7SGavin Maltby srlzer_enter(pl);
891f6e214c7SGavin Maltby
892f6e214c7SGavin Maltby srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_DONE;
893f6e214c7SGavin Maltby srlzer->ds_ndone++;
894f6e214c7SGavin Maltby wpl = srlzer_choose(srlzer);
895f6e214c7SGavin Maltby if (wpl != NULL)
896f6e214c7SGavin Maltby pipeline_continue(wpl);
897f6e214c7SGavin Maltby
898f6e214c7SGavin Maltby srlzer_exit(pl);
899f6e214c7SGavin Maltby }
900f6e214c7SGavin Maltby
901f6e214c7SGavin Maltby static void
pipeline_pollmode(struct fmdump_pipeline * pl)902f6e214c7SGavin Maltby pipeline_pollmode(struct fmdump_pipeline *pl)
903f6e214c7SGavin Maltby {
904f6e214c7SGavin Maltby struct fmdump_srlzer *srlzer = pl->pl_srlzer;
905f6e214c7SGavin Maltby struct fmdump_pipeline *wpl;
906f6e214c7SGavin Maltby
907f6e214c7SGavin Maltby if (srlzer->ds_slot[pl->pl_srlzeridx].ss_state == FMDUMP_PIPE_POLLING)
908f6e214c7SGavin Maltby return;
909f6e214c7SGavin Maltby
910f6e214c7SGavin Maltby srlzer_enter(pl);
911f6e214c7SGavin Maltby
912f6e214c7SGavin Maltby srlzer->ds_slot[pl->pl_srlzeridx].ss_state = FMDUMP_PIPE_POLLING;
913f6e214c7SGavin Maltby if (++srlzer->ds_pollcnt + srlzer->ds_nrecordavail ==
914f6e214c7SGavin Maltby srlzer->ds_pipecnt && (wpl = srlzer_choose(srlzer)) != NULL)
915f6e214c7SGavin Maltby pipeline_continue(wpl);
916f6e214c7SGavin Maltby
917f6e214c7SGavin Maltby srlzer_exit(pl);
918f6e214c7SGavin Maltby }
919f6e214c7SGavin Maltby
920f6e214c7SGavin Maltby static int
pipeline_err(fmd_log_t * lp,void * arg)921f6e214c7SGavin Maltby pipeline_err(fmd_log_t *lp, void *arg)
922f6e214c7SGavin Maltby {
923f6e214c7SGavin Maltby struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg;
924f6e214c7SGavin Maltby
925f6e214c7SGavin Maltby fmdump_warn("skipping record in %s: %s\n", pl->pl_processing,
926f6e214c7SGavin Maltby fmd_log_errmsg(lp, fmd_log_errno(lp)));
927f6e214c7SGavin Maltby g_errs++;
928f6e214c7SGavin Maltby
929f6e214c7SGavin Maltby return (0);
930f6e214c7SGavin Maltby }
931f6e214c7SGavin Maltby
932f6e214c7SGavin Maltby static int
pipeline_cb(fmd_log_t * lp,const fmd_log_record_t * rp,void * arg)933f6e214c7SGavin Maltby pipeline_cb(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg)
934f6e214c7SGavin Maltby {
935f6e214c7SGavin Maltby struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg;
936f6e214c7SGavin Maltby int rc;
937f6e214c7SGavin Maltby
938f6e214c7SGavin Maltby fmd_log_rec_f *func = pl->pl_arg.da_fmt->do_func;
939f6e214c7SGavin Maltby
940f6e214c7SGavin Maltby srlzer_enter(pl);
941f6e214c7SGavin Maltby
942f6e214c7SGavin Maltby if (!pipeline_output(pl, rp))
943f6e214c7SGavin Maltby pipeline_stall(pl);
944f6e214c7SGavin Maltby
945f6e214c7SGavin Maltby rc = func(lp, rp, pl->pl_arg.da_fp);
946f6e214c7SGavin Maltby pipeline_mark_consumed(pl);
947f6e214c7SGavin Maltby
948f6e214c7SGavin Maltby srlzer_exit(pl);
949f6e214c7SGavin Maltby
950f6e214c7SGavin Maltby return (rc);
951f6e214c7SGavin Maltby }
952f6e214c7SGavin Maltby
953f6e214c7SGavin Maltby static void
pipeline_process(struct fmdump_pipeline * pl,char * logpath,boolean_t follow)954f6e214c7SGavin Maltby pipeline_process(struct fmdump_pipeline *pl, char *logpath, boolean_t follow)
955f6e214c7SGavin Maltby {
956f6e214c7SGavin Maltby fmd_log_header_t log;
957f6e214c7SGavin Maltby fmd_log_t *lp;
958f6e214c7SGavin Maltby int err;
959f6e214c7SGavin Maltby int i;
960f6e214c7SGavin Maltby
961f6e214c7SGavin Maltby pl->pl_processing = logpath;
962f6e214c7SGavin Maltby
963f6e214c7SGavin Maltby if ((lp = fmd_log_open(FMD_LOG_VERSION, logpath, &err)) == NULL) {
964f6e214c7SGavin Maltby fmdump_warn("failed to open %s: %s\n",
965f6e214c7SGavin Maltby logpath, fmd_log_errmsg(NULL, err));
966f6e214c7SGavin Maltby g_errs++;
967f6e214c7SGavin Maltby return;
968f6e214c7SGavin Maltby }
969f6e214c7SGavin Maltby
970f6e214c7SGavin Maltby fmd_log_header(lp, &log);
971f6e214c7SGavin Maltby for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) {
972f6e214c7SGavin Maltby if (strcmp(log.log_label, logtypes[i].lt_label) == 0) {
973f6e214c7SGavin Maltby pl->pl_ops = logtypes[i].lt_ops;
974f6e214c7SGavin Maltby pl->pl_arg.da_fmt =
975f6e214c7SGavin Maltby &pl->pl_ops->do_formats[pl->pl_fmt];
976f6e214c7SGavin Maltby break;
977f6e214c7SGavin Maltby }
978f6e214c7SGavin Maltby }
979f6e214c7SGavin Maltby
980f6e214c7SGavin Maltby if (pl->pl_ops == NULL) {
981f6e214c7SGavin Maltby fmdump_warn("unknown log type %s for %s\n",
982f6e214c7SGavin Maltby log.log_label, logpath);
983f6e214c7SGavin Maltby g_errs++;
984f6e214c7SGavin Maltby return;
985f6e214c7SGavin Maltby }
986f6e214c7SGavin Maltby
987f6e214c7SGavin Maltby do {
988f6e214c7SGavin Maltby if (fmd_log_xiter(lp, FMD_LOG_XITER_REFS, pl->pl_arg.da_fc,
989f6e214c7SGavin Maltby pl->pl_arg.da_fv, pipeline_cb, pipeline_err, (void *)pl,
990f6e214c7SGavin Maltby NULL) != 0) {
991f6e214c7SGavin Maltby fmdump_warn("failed to dump %s: %s\n",
992f6e214c7SGavin Maltby logpath, fmd_log_errmsg(lp, fmd_log_errno(lp)));
993f6e214c7SGavin Maltby g_errs++;
994f6e214c7SGavin Maltby fmd_log_close(lp);
995f6e214c7SGavin Maltby return;
996f6e214c7SGavin Maltby }
997f6e214c7SGavin Maltby
998f6e214c7SGavin Maltby if (follow) {
999f6e214c7SGavin Maltby pipeline_pollmode(pl);
1000f6e214c7SGavin Maltby (void) sleep(1);
1001f6e214c7SGavin Maltby }
1002f6e214c7SGavin Maltby
1003f6e214c7SGavin Maltby } while (follow);
1004f6e214c7SGavin Maltby
1005f6e214c7SGavin Maltby fmd_log_close(lp);
1006f6e214c7SGavin Maltby }
1007f6e214c7SGavin Maltby
1008f6e214c7SGavin Maltby static void *
pipeline_thr(void * arg)1009f6e214c7SGavin Maltby pipeline_thr(void *arg)
1010f6e214c7SGavin Maltby {
1011f6e214c7SGavin Maltby struct fmdump_pipeline *pl = (struct fmdump_pipeline *)arg;
1012f6e214c7SGavin Maltby struct loglink *ll;
1013f6e214c7SGavin Maltby
1014f6e214c7SGavin Maltby (void) pthread_mutex_lock(&pl->pl_lock);
1015f6e214c7SGavin Maltby pl->pl_started = 1;
1016f6e214c7SGavin Maltby (void) pthread_mutex_unlock(&pl->pl_lock);
1017f6e214c7SGavin Maltby (void) pthread_cond_signal(&pl->pl_cv);
1018f6e214c7SGavin Maltby
1019f6e214c7SGavin Maltby for (ll = pl->pl_rotated; ll != NULL; ll = ll->next)
1020f6e214c7SGavin Maltby pipeline_process(pl, ll->path, B_FALSE);
1021f6e214c7SGavin Maltby
1022f6e214c7SGavin Maltby pipeline_process(pl, pl->pl_logpath, pl->pl_follow);
1023f6e214c7SGavin Maltby pipeline_done(pl);
1024f6e214c7SGavin Maltby
1025f6e214c7SGavin Maltby return (NULL);
1026f6e214c7SGavin Maltby }
1027f6e214c7SGavin Maltby
1028f6e214c7SGavin Maltby
1029f6e214c7SGavin Maltby 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,int opt_j)1030f6e214c7SGavin Maltby aggregate(char **ifiles, int n_ifiles, int opt_f,
1031f6e214c7SGavin Maltby fmd_log_filter_t *fv, uint_t fc,
1032*2db6d663SJoshua M. Clulow int opt_v, int opt_V, int opt_p, int opt_j)
1033f6e214c7SGavin Maltby {
1034f6e214c7SGavin Maltby struct fmdump_pipeline *pipeline, *pl;
1035f6e214c7SGavin Maltby struct fmdump_srlzer srlzer;
1036f6e214c7SGavin Maltby uint32_t npipe;
1037f6e214c7SGavin Maltby int fmt;
1038f6e214c7SGavin Maltby int i;
1039f6e214c7SGavin Maltby
1040f6e214c7SGavin Maltby if (ifiles != NULL) {
1041f6e214c7SGavin Maltby npipe = n_ifiles;
1042f6e214c7SGavin Maltby pipeline = calloc(npipe, sizeof (struct fmdump_pipeline));
1043f6e214c7SGavin Maltby if (!pipeline)
1044f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
1045f6e214c7SGavin Maltby
1046f6e214c7SGavin Maltby for (i = 0; i < n_ifiles; i++)
1047f6e214c7SGavin Maltby pipeline[i].pl_logpath = ifiles[i];
1048f6e214c7SGavin Maltby } else {
1049f6e214c7SGavin Maltby pipeline = calloc(sizeof (logtypes) / sizeof (logtypes[0]),
1050f6e214c7SGavin Maltby sizeof (struct fmdump_pipeline));
1051f6e214c7SGavin Maltby if (!pipeline)
1052f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
1053f6e214c7SGavin Maltby
1054f6e214c7SGavin Maltby do_disables();
1055f6e214c7SGavin Maltby
1056f6e214c7SGavin Maltby npipe = 0;
1057f6e214c7SGavin Maltby for (i = 0; i < sizeof (logtypes) / sizeof (logtypes[0]); i++) {
1058f6e214c7SGavin Maltby struct fmdump_logtype *ltp = &logtypes[i];
1059f6e214c7SGavin Maltby char *logpath;
1060f6e214c7SGavin Maltby
1061f6e214c7SGavin Maltby if (ltp->lt_enabled == B_FALSE)
1062f6e214c7SGavin Maltby continue;
1063f6e214c7SGavin Maltby
1064f6e214c7SGavin Maltby if ((logpath = malloc(PATH_MAX)) == NULL)
1065f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
1066f6e214c7SGavin Maltby
1067f6e214c7SGavin Maltby (void) snprintf(logpath, PATH_MAX,
1068f6e214c7SGavin Maltby "%s/var/fm/fmd/%s",
1069f6e214c7SGavin Maltby g_root ? g_root : "", ltp->lt_logname);
1070f6e214c7SGavin Maltby
1071f6e214c7SGavin Maltby pipeline[npipe].pl_rotated =
1072f6e214c7SGavin Maltby get_rotated_logs(logpath);
1073f6e214c7SGavin Maltby
1074f6e214c7SGavin Maltby pipeline[npipe++].pl_logpath = logpath;
1075f6e214c7SGavin Maltby }
1076f6e214c7SGavin Maltby }
1077f6e214c7SGavin Maltby
1078f6e214c7SGavin Maltby if (opt_V)
1079*2db6d663SJoshua M. Clulow fmt = opt_p ? FMDUMP_PRETTY : opt_j ? FMDUMP_JSON :
1080*2db6d663SJoshua M. Clulow FMDUMP_VERB2;
1081f6e214c7SGavin Maltby else if (opt_v)
1082f6e214c7SGavin Maltby fmt = FMDUMP_VERB1;
1083f6e214c7SGavin Maltby else
1084f6e214c7SGavin Maltby fmt = FMDUMP_SHORT;
1085f6e214c7SGavin Maltby
1086f6e214c7SGavin Maltby bzero(&srlzer, sizeof (srlzer));
1087f6e214c7SGavin Maltby srlzer.ds_pipearr = pipeline;
1088f6e214c7SGavin Maltby srlzer.ds_pipecnt = npipe;
1089f6e214c7SGavin Maltby srlzer.ds_slot = calloc(npipe, sizeof (struct fmdump_srlzer_slot));
1090f6e214c7SGavin Maltby if (!srlzer.ds_slot)
1091f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
1092f6e214c7SGavin Maltby (void) pthread_mutex_init(&srlzer.ds_lock, NULL);
1093f6e214c7SGavin Maltby
1094f6e214c7SGavin Maltby for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++) {
1095f6e214c7SGavin Maltby (void) pthread_mutex_init(&pl->pl_lock, NULL);
1096f6e214c7SGavin Maltby (void) pthread_cond_init(&pl->pl_cv, NULL);
1097f6e214c7SGavin Maltby srlzer.ds_slot[i].ss_state = FMDUMP_PIPE_PROCESSING;
1098f6e214c7SGavin Maltby pl->pl_srlzer = &srlzer;
1099f6e214c7SGavin Maltby pl->pl_srlzeridx = i;
1100f6e214c7SGavin Maltby pl->pl_follow = opt_f ? B_TRUE : B_FALSE;
1101f6e214c7SGavin Maltby pl->pl_fmt = fmt;
1102f6e214c7SGavin Maltby pl->pl_arg.da_fv = fv;
1103f6e214c7SGavin Maltby pl->pl_arg.da_fc = fc;
1104f6e214c7SGavin Maltby pl->pl_arg.da_fp = stdout;
1105f6e214c7SGavin Maltby
1106f6e214c7SGavin Maltby (void) pthread_mutex_lock(&pl->pl_lock);
1107f6e214c7SGavin Maltby
1108f6e214c7SGavin Maltby if (pthread_create(&pl->pl_thr, NULL,
1109f6e214c7SGavin Maltby pipeline_thr, (void *)pl) != 0)
1110f6e214c7SGavin Maltby fmdump_fatal("pthread_create for pipeline %d failed",
1111f6e214c7SGavin Maltby i);
1112f6e214c7SGavin Maltby }
1113f6e214c7SGavin Maltby
1114f6e214c7SGavin Maltby for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++) {
1115f6e214c7SGavin Maltby while (!pl->pl_started)
1116f6e214c7SGavin Maltby (void) pthread_cond_wait(&pl->pl_cv, &pl->pl_lock);
1117f6e214c7SGavin Maltby
1118f6e214c7SGavin Maltby (void) pthread_mutex_unlock(&pl->pl_lock);
1119f6e214c7SGavin Maltby }
1120f6e214c7SGavin Maltby
1121f6e214c7SGavin Maltby for (i = 0, pl = &pipeline[0]; i < npipe; i++, pl++)
1122f6e214c7SGavin Maltby (void) pthread_join(pl->pl_thr, NULL);
1123f6e214c7SGavin Maltby
1124f6e214c7SGavin Maltby if (ifiles == NULL) {
1125f6e214c7SGavin Maltby for (i = 0; i < npipe; i++)
1126f6e214c7SGavin Maltby free(pipeline[i].pl_logpath);
1127f6e214c7SGavin Maltby }
1128f6e214c7SGavin Maltby
1129f6e214c7SGavin Maltby free(srlzer.ds_slot);
1130f6e214c7SGavin Maltby
1131f6e214c7SGavin Maltby free(pipeline);
1132f6e214c7SGavin Maltby
1133f6e214c7SGavin Maltby return (FMDUMP_EXIT_SUCCESS);
1134f6e214c7SGavin Maltby }
1135f6e214c7SGavin Maltby
1136f6e214c7SGavin Maltby static void
cleanup(char ** ifiles,int n_ifiles)1137f6e214c7SGavin Maltby cleanup(char **ifiles, int n_ifiles)
1138f6e214c7SGavin Maltby {
1139f6e214c7SGavin Maltby int i;
1140f6e214c7SGavin Maltby
1141f6e214c7SGavin Maltby if (ifiles == NULL)
1142f6e214c7SGavin Maltby return;
1143f6e214c7SGavin Maltby
1144f6e214c7SGavin Maltby for (i = 0; i < n_ifiles; i++) {
1145f6e214c7SGavin Maltby if (ifiles[i] != NULL) {
1146f6e214c7SGavin Maltby free(ifiles[i]);
1147f6e214c7SGavin Maltby ifiles[i] = NULL;
1148f6e214c7SGavin Maltby }
1149f6e214c7SGavin Maltby }
1150f6e214c7SGavin Maltby
1151f6e214c7SGavin Maltby free(ifiles);
1152f6e214c7SGavin Maltby }
1153f6e214c7SGavin Maltby
11547c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])11557c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
11567c478bd9Sstevel@tonic-gate {
1157f6e214c7SGavin Maltby int opt_a = 0, opt_e = 0, opt_f = 0, opt_H = 0, opt_m = 0, opt_p = 0;
1158*2db6d663SJoshua M. Clulow int opt_u = 0, opt_v = 0, opt_V = 0, opt_j = 0;
1159f6e214c7SGavin Maltby int opt_i = 0, opt_I = 0;
1160f6e214c7SGavin Maltby int opt_A = 0;
1161f6e214c7SGavin Maltby char **ifiles = NULL;
1162f6e214c7SGavin Maltby char *ifile = NULL;
1163f6e214c7SGavin Maltby int n_ifiles;
1164f6e214c7SGavin Maltby int ifileidx = 0;
11657c478bd9Sstevel@tonic-gate int iflags = 0;
11667c478bd9Sstevel@tonic-gate
11677c478bd9Sstevel@tonic-gate fmdump_arg_t arg;
11687c478bd9Sstevel@tonic-gate fmdump_lyr_t lyr;
11697c478bd9Sstevel@tonic-gate const fmdump_ops_t *ops;
11707c478bd9Sstevel@tonic-gate fmd_log_filter_t *filtv;
11717c478bd9Sstevel@tonic-gate uint_t filtc;
11727c478bd9Sstevel@tonic-gate
11737c478bd9Sstevel@tonic-gate fmd_log_filter_t *errfv, *fltfv, *allfv;
11747c478bd9Sstevel@tonic-gate uint_t errfc = 0, fltfc = 0, allfc = 0;
11757c478bd9Sstevel@tonic-gate
11767c478bd9Sstevel@tonic-gate fmd_log_header_t log;
11777c478bd9Sstevel@tonic-gate fmd_log_rec_f *func;
11787c478bd9Sstevel@tonic-gate void *farg;
11797c478bd9Sstevel@tonic-gate fmd_log_t *lp;
11807c478bd9Sstevel@tonic-gate int c, err;
11817c478bd9Sstevel@tonic-gate off64_t off = 0;
1182c93c462eSCheng Sean Ye ulong_t recs;
1183c93c462eSCheng Sean Ye struct loglink *rotated_logs = NULL, *llp;
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate g_pname = argv[0];
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate errfv = alloca(sizeof (fmd_log_filter_t) * argc);
11887c478bd9Sstevel@tonic-gate fltfv = alloca(sizeof (fmd_log_filter_t) * argc);
11897c478bd9Sstevel@tonic-gate allfv = alloca(sizeof (fmd_log_filter_t) * argc);
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate while (optind < argc) {
1192602ca9eaScth while ((c =
1193*2db6d663SJoshua M. Clulow getopt(argc, argv, "Aac:efHiIjmn:O:pR:t:T:u:vV")) != EOF) {
11947c478bd9Sstevel@tonic-gate switch (c) {
1195f6e214c7SGavin Maltby case 'A':
1196f6e214c7SGavin Maltby opt_A++;
1197f6e214c7SGavin Maltby break;
11987c478bd9Sstevel@tonic-gate case 'a':
11997c478bd9Sstevel@tonic-gate opt_a++;
12007c478bd9Sstevel@tonic-gate break;
12017c478bd9Sstevel@tonic-gate case 'c':
12027c478bd9Sstevel@tonic-gate errfv[errfc].filt_func = fmd_log_filter_class;
12037c478bd9Sstevel@tonic-gate errfv[errfc].filt_arg = optarg;
12047c478bd9Sstevel@tonic-gate allfv[allfc++] = errfv[errfc++];
12057c478bd9Sstevel@tonic-gate break;
12067c478bd9Sstevel@tonic-gate case 'e':
1207f6e214c7SGavin Maltby if (opt_i)
1208f6e214c7SGavin Maltby return (usage(stderr));
12097c478bd9Sstevel@tonic-gate opt_e++;
12107c478bd9Sstevel@tonic-gate break;
12117c478bd9Sstevel@tonic-gate case 'f':
12127c478bd9Sstevel@tonic-gate opt_f++;
12137c478bd9Sstevel@tonic-gate break;
12147c478bd9Sstevel@tonic-gate case 'H':
12157c478bd9Sstevel@tonic-gate opt_H++;
12167c478bd9Sstevel@tonic-gate break;
1217f6e214c7SGavin Maltby case 'i':
1218f6e214c7SGavin Maltby if (opt_e || opt_I)
1219f6e214c7SGavin Maltby return (usage(stderr));
1220f6e214c7SGavin Maltby opt_i++;
1221f6e214c7SGavin Maltby break;
1222f6e214c7SGavin Maltby case 'I':
1223f6e214c7SGavin Maltby if (opt_e || opt_i)
1224f6e214c7SGavin Maltby return (usage(stderr));
1225f6e214c7SGavin Maltby opt_I++;
1226f6e214c7SGavin Maltby break;
1227*2db6d663SJoshua M. Clulow case 'j':
1228*2db6d663SJoshua M. Clulow if (opt_p)
1229*2db6d663SJoshua M. Clulow return (usage(stderr));
1230*2db6d663SJoshua M. Clulow opt_j++;
1231*2db6d663SJoshua M. Clulow break;
1232b6955755SRobert Johnston case 'm':
1233b6955755SRobert Johnston opt_m++;
1234b6955755SRobert Johnston break;
12357c478bd9Sstevel@tonic-gate case 'O':
12367c478bd9Sstevel@tonic-gate off = strtoull(optarg, NULL, 16);
12377c478bd9Sstevel@tonic-gate iflags |= FMD_LOG_XITER_OFFS;
12387c478bd9Sstevel@tonic-gate break;
1239f6e214c7SGavin Maltby case 'p':
1240*2db6d663SJoshua M. Clulow if (opt_j)
1241*2db6d663SJoshua M. Clulow return (usage(stderr));
1242f6e214c7SGavin Maltby opt_p++;
1243f6e214c7SGavin Maltby break;
12447c478bd9Sstevel@tonic-gate case 'R':
12457c478bd9Sstevel@tonic-gate g_root = optarg;
12467c478bd9Sstevel@tonic-gate break;
12477c478bd9Sstevel@tonic-gate case 't':
12487c478bd9Sstevel@tonic-gate errfv[errfc].filt_func = fmd_log_filter_after;
12497c478bd9Sstevel@tonic-gate errfv[errfc].filt_arg = gettimeopt(optarg);
12507c478bd9Sstevel@tonic-gate allfv[allfc++] = errfv[errfc++];
12517c478bd9Sstevel@tonic-gate break;
12527c478bd9Sstevel@tonic-gate case 'T':
12537c478bd9Sstevel@tonic-gate errfv[errfc].filt_func = fmd_log_filter_before;
12547c478bd9Sstevel@tonic-gate errfv[errfc].filt_arg = gettimeopt(optarg);
12557c478bd9Sstevel@tonic-gate allfv[allfc++] = errfv[errfc++];
12567c478bd9Sstevel@tonic-gate break;
12577c478bd9Sstevel@tonic-gate case 'u':
12587c478bd9Sstevel@tonic-gate fltfv[fltfc].filt_func = fmd_log_filter_uuid;
12597c478bd9Sstevel@tonic-gate fltfv[fltfc].filt_arg = optarg;
12607c478bd9Sstevel@tonic-gate allfv[allfc++] = fltfv[fltfc++];
12617c478bd9Sstevel@tonic-gate opt_u++;
12627c478bd9Sstevel@tonic-gate opt_a++; /* -u implies -a */
12637c478bd9Sstevel@tonic-gate break;
1264602ca9eaScth case 'n': {
1265602ca9eaScth fltfv[fltfc].filt_func = fmd_log_filter_nv;
1266602ca9eaScth fltfv[fltfc].filt_arg = setupnamevalue(optarg);
1267602ca9eaScth allfv[allfc++] = fltfv[fltfc++];
1268602ca9eaScth break;
1269602ca9eaScth }
12707c478bd9Sstevel@tonic-gate case 'v':
12717c478bd9Sstevel@tonic-gate opt_v++;
12727c478bd9Sstevel@tonic-gate break;
12737c478bd9Sstevel@tonic-gate case 'V':
12747c478bd9Sstevel@tonic-gate opt_V++;
12757c478bd9Sstevel@tonic-gate break;
12767c478bd9Sstevel@tonic-gate default:
12777c478bd9Sstevel@tonic-gate return (usage(stderr));
12787c478bd9Sstevel@tonic-gate }
12797c478bd9Sstevel@tonic-gate }
12807c478bd9Sstevel@tonic-gate
1281f6e214c7SGavin Maltby if (opt_A && (opt_e || opt_i || opt_I || opt_m || opt_u))
1282f6e214c7SGavin Maltby fmdump_usage("-A excludes all of "
1283f6e214c7SGavin Maltby "-e, -i, -I, -m and -u\n");
1284f6e214c7SGavin Maltby
12857c478bd9Sstevel@tonic-gate if (optind < argc) {
1286f6e214c7SGavin Maltby char *dest;
1287f6e214c7SGavin Maltby
1288f6e214c7SGavin Maltby if (ifiles == NULL) {
1289f6e214c7SGavin Maltby n_ifiles = argc - optind;
1290f6e214c7SGavin Maltby ifiles = calloc(n_ifiles, sizeof (char *));
1291f6e214c7SGavin Maltby if (ifiles == NULL) {
1292f6e214c7SGavin Maltby fmdump_fatal(
1293f6e214c7SGavin Maltby "failed to allocate memory for "
1294f6e214c7SGavin Maltby "%d input file%s", n_ifiles,
1295f6e214c7SGavin Maltby n_ifiles > 1 ? "s" : "");
12967c478bd9Sstevel@tonic-gate }
12977c478bd9Sstevel@tonic-gate }
12987c478bd9Sstevel@tonic-gate
1299f6e214c7SGavin Maltby if (ifileidx > 0 && !opt_A)
1300f6e214c7SGavin Maltby fmdump_usage("illegal argument -- %s\n",
1301f6e214c7SGavin Maltby argv[optind]);
1302f6e214c7SGavin Maltby
1303f6e214c7SGavin Maltby if ((dest = malloc(PATH_MAX)) == NULL)
1304f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
1305f6e214c7SGavin Maltby
1306f6e214c7SGavin Maltby (void) strlcpy(dest, argv[optind++], PATH_MAX);
1307f6e214c7SGavin Maltby ifiles[ifileidx++] = dest;
1308f6e214c7SGavin Maltby }
1309f6e214c7SGavin Maltby }
1310f6e214c7SGavin Maltby
1311f6e214c7SGavin Maltby if (opt_A) {
1312f6e214c7SGavin Maltby int rc;
1313f6e214c7SGavin Maltby
1314f6e214c7SGavin Maltby if (!opt_a) {
1315f6e214c7SGavin Maltby fltfv[fltfc].filt_func = log_filter_silent;
1316f6e214c7SGavin Maltby fltfv[fltfc].filt_arg = (void *)1;
1317f6e214c7SGavin Maltby allfv[allfc++] = fltfv[fltfc++];
1318f6e214c7SGavin Maltby }
1319f6e214c7SGavin Maltby
1320f6e214c7SGavin Maltby rc = aggregate(ifiles, n_ifiles, opt_f,
1321f6e214c7SGavin Maltby allfv, allfc,
1322*2db6d663SJoshua M. Clulow opt_v, opt_V, opt_p, opt_j);
1323f6e214c7SGavin Maltby
1324f6e214c7SGavin Maltby cleanup(ifiles, n_ifiles);
1325f6e214c7SGavin Maltby return (rc);
1326f6e214c7SGavin Maltby } else {
1327f6e214c7SGavin Maltby if (ifiles == NULL) {
1328f6e214c7SGavin Maltby if ((ifile = calloc(1, PATH_MAX)) == NULL)
1329f6e214c7SGavin Maltby fmdump_fatal("failed to allocate memory");
1330f6e214c7SGavin Maltby } else {
1331f6e214c7SGavin Maltby ifile = ifiles[0];
1332f6e214c7SGavin Maltby }
1333f6e214c7SGavin Maltby }
1334f6e214c7SGavin Maltby
1335f6e214c7SGavin Maltby
13367c478bd9Sstevel@tonic-gate if (*ifile == '\0') {
1337f6e214c7SGavin Maltby const char *pfx, *sfx;
1338f6e214c7SGavin Maltby
1339f6e214c7SGavin Maltby if (opt_u || (!opt_e && !opt_i && !opt_I)) {
1340f6e214c7SGavin Maltby pfx = "flt";
1341f6e214c7SGavin Maltby sfx = "";
1342f6e214c7SGavin Maltby } else {
1343f6e214c7SGavin Maltby if (opt_e) {
1344f6e214c7SGavin Maltby pfx = "err";
1345f6e214c7SGavin Maltby sfx = "";
1346f6e214c7SGavin Maltby } else {
1347f6e214c7SGavin Maltby pfx = "info";
1348f6e214c7SGavin Maltby sfx = opt_I ? "_hival" : "";
1349f6e214c7SGavin Maltby }
1350f6e214c7SGavin Maltby }
1351f6e214c7SGavin Maltby
1352f6e214c7SGavin Maltby (void) snprintf(ifile, PATH_MAX, "%s/var/fm/fmd/%slog%s",
1353f6e214c7SGavin Maltby g_root ? g_root : "", pfx, sfx);
1354c93c462eSCheng Sean Ye /*
1355c93c462eSCheng Sean Ye * logadm may rotate the logs. When no input file is specified,
1356c93c462eSCheng Sean Ye * we try to dump all the rotated logs as well in the right
1357c93c462eSCheng Sean Ye * order.
1358c93c462eSCheng Sean Ye */
1359c93c462eSCheng Sean Ye if (!opt_H && off == 0)
1360c93c462eSCheng Sean Ye rotated_logs = get_rotated_logs(ifile);
13617c478bd9Sstevel@tonic-gate } else if (g_root != NULL) {
1362f6e214c7SGavin Maltby fmdump_usage("-R option is not appropriate "
1363f6e214c7SGavin Maltby "when file operand is present\n");
13647c478bd9Sstevel@tonic-gate }
13657c478bd9Sstevel@tonic-gate
1366f6e214c7SGavin Maltby if ((g_msg = fmd_msg_init(g_root, FMD_MSG_VERSION)) == NULL)
1367f6e214c7SGavin Maltby fmdump_fatal("failed to initialize libfmd_msg");
1368b6955755SRobert Johnston
13697c478bd9Sstevel@tonic-gate if ((lp = fmd_log_open(FMD_LOG_VERSION, ifile, &err)) == NULL) {
1370f6e214c7SGavin Maltby fmdump_fatal("failed to open %s: %s\n", ifile,
1371f6e214c7SGavin Maltby fmd_log_errmsg(NULL, err));
13727c478bd9Sstevel@tonic-gate }
13737c478bd9Sstevel@tonic-gate
13747c478bd9Sstevel@tonic-gate if (opt_H) {
13757c478bd9Sstevel@tonic-gate fmd_log_header(lp, &log);
13767c478bd9Sstevel@tonic-gate
13777c478bd9Sstevel@tonic-gate (void) printf("EXD_CREATOR = %s\n", log.log_creator);
13787c478bd9Sstevel@tonic-gate (void) printf("EXD_HOSTNAME = %s\n", log.log_hostname);
13797c478bd9Sstevel@tonic-gate (void) printf("EXD_FMA_LABEL = %s\n", log.log_label);
13807c478bd9Sstevel@tonic-gate (void) printf("EXD_FMA_VERSION = %s\n", log.log_version);
13817c478bd9Sstevel@tonic-gate (void) printf("EXD_FMA_OSREL = %s\n", log.log_osrelease);
13827c478bd9Sstevel@tonic-gate (void) printf("EXD_FMA_OSVER = %s\n", log.log_osversion);
13837c478bd9Sstevel@tonic-gate (void) printf("EXD_FMA_PLAT = %s\n", log.log_platform);
13847ee93e3bSdilpreet (void) printf("EXD_FMA_UUID = %s\n", log.log_uuid);
13857c478bd9Sstevel@tonic-gate
13867c478bd9Sstevel@tonic-gate return (FMDUMP_EXIT_SUCCESS);
13877c478bd9Sstevel@tonic-gate }
13887c478bd9Sstevel@tonic-gate
13897c478bd9Sstevel@tonic-gate if (off != 0 && fmd_log_seek(lp, off) != 0) {
1390f6e214c7SGavin Maltby fmdump_fatal("failed to seek %s: %s\n", ifile,
1391f6e214c7SGavin Maltby fmd_log_errmsg(lp, fmd_log_errno(lp)));
13927c478bd9Sstevel@tonic-gate }
13937c478bd9Sstevel@tonic-gate
13947c478bd9Sstevel@tonic-gate if (opt_e && opt_u)
13957c478bd9Sstevel@tonic-gate ops = &fmdump_err_ops;
13967c478bd9Sstevel@tonic-gate else if (strcmp(fmd_log_label(lp), fmdump_flt_ops.do_label) == 0)
13977c478bd9Sstevel@tonic-gate ops = &fmdump_flt_ops;
13987c478bd9Sstevel@tonic-gate else if (strcmp(fmd_log_label(lp), fmdump_asru_ops.do_label) == 0)
13997c478bd9Sstevel@tonic-gate ops = &fmdump_asru_ops;
1400f6e214c7SGavin Maltby else if (strcmp(fmd_log_label(lp), fmdump_info_ops.do_label) == 0)
1401f6e214c7SGavin Maltby ops = &fmdump_info_ops;
14027c478bd9Sstevel@tonic-gate else
14037c478bd9Sstevel@tonic-gate ops = &fmdump_err_ops;
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate if (!opt_a && ops == &fmdump_flt_ops) {
14067c478bd9Sstevel@tonic-gate fltfv[fltfc].filt_func = log_filter_silent;
14077c478bd9Sstevel@tonic-gate fltfv[fltfc].filt_arg = NULL;
14087c478bd9Sstevel@tonic-gate allfv[allfc++] = fltfv[fltfc++];
14097c478bd9Sstevel@tonic-gate }
14107c478bd9Sstevel@tonic-gate
14117c478bd9Sstevel@tonic-gate if (opt_V) {
1412f6e214c7SGavin Maltby arg.da_fmt =
1413*2db6d663SJoshua M. Clulow &ops->do_formats[opt_p ? FMDUMP_PRETTY :
1414*2db6d663SJoshua M. Clulow opt_j ? FMDUMP_JSON : FMDUMP_VERB2];
14157c478bd9Sstevel@tonic-gate iflags |= FMD_LOG_XITER_REFS;
14167c478bd9Sstevel@tonic-gate } else if (opt_v) {
14177c478bd9Sstevel@tonic-gate arg.da_fmt = &ops->do_formats[FMDUMP_VERB1];
1418b6955755SRobert Johnston } else if (opt_m) {
1419b6955755SRobert Johnston arg.da_fmt = &ops->do_formats[FMDUMP_MSG];
14207c478bd9Sstevel@tonic-gate } else
14217c478bd9Sstevel@tonic-gate arg.da_fmt = &ops->do_formats[FMDUMP_SHORT];
14227c478bd9Sstevel@tonic-gate
1423b6955755SRobert Johnston if (opt_m && arg.da_fmt->do_func == NULL) {
1424f6e214c7SGavin Maltby fmdump_usage("-m mode is not supported for "
1425f6e214c7SGavin Maltby "log of type %s: %s\n", fmd_log_label(lp), ifile);
1426b6955755SRobert Johnston }
1427b6955755SRobert Johnston
14287c478bd9Sstevel@tonic-gate arg.da_fv = errfv;
14297c478bd9Sstevel@tonic-gate arg.da_fc = errfc;
14307c478bd9Sstevel@tonic-gate arg.da_fp = stdout;
14317c478bd9Sstevel@tonic-gate
14327c478bd9Sstevel@tonic-gate if (iflags & FMD_LOG_XITER_OFFS)
14337c478bd9Sstevel@tonic-gate fmdump_printf(arg.da_fp, "%16s ", "OFFSET");
14347c478bd9Sstevel@tonic-gate
1435540db9a9SStephen Hanson if (arg.da_fmt->do_hdr && !(opt_V && ops == &fmdump_flt_ops))
14367c478bd9Sstevel@tonic-gate fmdump_printf(arg.da_fp, "%s\n", arg.da_fmt->do_hdr);
14377c478bd9Sstevel@tonic-gate
14387c478bd9Sstevel@tonic-gate if (opt_e && opt_u) {
14397c478bd9Sstevel@tonic-gate iflags |= FMD_LOG_XITER_REFS;
14407c478bd9Sstevel@tonic-gate func = xref_iter;
14417c478bd9Sstevel@tonic-gate farg = &arg;
14427c478bd9Sstevel@tonic-gate filtc = fltfc;
14437c478bd9Sstevel@tonic-gate filtv = fltfv;
14447c478bd9Sstevel@tonic-gate } else {
14457c478bd9Sstevel@tonic-gate func = arg.da_fmt->do_func;
14467c478bd9Sstevel@tonic-gate farg = arg.da_fp;
14477c478bd9Sstevel@tonic-gate filtc = allfc;
14487c478bd9Sstevel@tonic-gate filtv = allfv;
14497c478bd9Sstevel@tonic-gate }
14507c478bd9Sstevel@tonic-gate
14517c478bd9Sstevel@tonic-gate if (iflags & FMD_LOG_XITER_OFFS) {
14527c478bd9Sstevel@tonic-gate lyr.dy_func = func;
14537c478bd9Sstevel@tonic-gate lyr.dy_arg = farg;
14547c478bd9Sstevel@tonic-gate lyr.dy_fp = arg.da_fp;
14557c478bd9Sstevel@tonic-gate func = xoff_iter;
14567c478bd9Sstevel@tonic-gate farg = &lyr;
14577c478bd9Sstevel@tonic-gate }
14587c478bd9Sstevel@tonic-gate
1459c93c462eSCheng Sean Ye for (llp = rotated_logs; llp != NULL; llp = llp->next) {
1460c93c462eSCheng Sean Ye fmd_log_t *rlp;
1461c93c462eSCheng Sean Ye
1462c93c462eSCheng Sean Ye if ((rlp = fmd_log_open(FMD_LOG_VERSION, llp->path, &err))
1463c93c462eSCheng Sean Ye == NULL) {
1464f6e214c7SGavin Maltby fmdump_warn("failed to open %s: %s\n",
1465f6e214c7SGavin Maltby llp->path, fmd_log_errmsg(NULL, err));
1466c93c462eSCheng Sean Ye g_errs++;
1467c93c462eSCheng Sean Ye continue;
1468c93c462eSCheng Sean Ye }
1469c93c462eSCheng Sean Ye
1470c93c462eSCheng Sean Ye recs = 0;
1471c93c462eSCheng Sean Ye if (fmd_log_xiter(rlp, iflags, filtc, filtv,
1472c93c462eSCheng Sean Ye func, error, farg, &recs) != 0) {
1473f6e214c7SGavin Maltby fmdump_warn("failed to dump %s: %s\n", llp->path,
1474c93c462eSCheng Sean Ye fmd_log_errmsg(rlp, fmd_log_errno(rlp)));
1475c93c462eSCheng Sean Ye g_errs++;
1476c93c462eSCheng Sean Ye }
1477c93c462eSCheng Sean Ye g_recs += recs;
1478c93c462eSCheng Sean Ye
1479c93c462eSCheng Sean Ye fmd_log_close(rlp);
1480c93c462eSCheng Sean Ye }
1481c93c462eSCheng Sean Ye
14827c478bd9Sstevel@tonic-gate do {
1483c93c462eSCheng Sean Ye recs = 0;
14847c478bd9Sstevel@tonic-gate if (fmd_log_xiter(lp, iflags, filtc, filtv,
1485c93c462eSCheng Sean Ye func, error, farg, &recs) != 0) {
1486f6e214c7SGavin Maltby fmdump_warn("failed to dump %s: %s\n", ifile,
14877c478bd9Sstevel@tonic-gate fmd_log_errmsg(lp, fmd_log_errno(lp)));
14887c478bd9Sstevel@tonic-gate g_errs++;
14897c478bd9Sstevel@tonic-gate }
1490c93c462eSCheng Sean Ye g_recs += recs;
14917c478bd9Sstevel@tonic-gate
14927c478bd9Sstevel@tonic-gate if (opt_f)
14937c478bd9Sstevel@tonic-gate (void) sleep(1);
14947c478bd9Sstevel@tonic-gate
14957c478bd9Sstevel@tonic-gate } while (opt_f);
14967c478bd9Sstevel@tonic-gate
14977c478bd9Sstevel@tonic-gate if (!opt_f && g_recs == 0 && isatty(STDOUT_FILENO))
1498f6e214c7SGavin Maltby fmdump_warn("%s is empty\n", ifile);
14997c478bd9Sstevel@tonic-gate
1500b6955755SRobert Johnston if (g_thp != NULL)
1501b6955755SRobert Johnston topo_close(g_thp);
1502b6955755SRobert Johnston
15037c478bd9Sstevel@tonic-gate fmd_log_close(lp);
1504b6955755SRobert Johnston fmd_msg_fini(g_msg);
1505b6955755SRobert Johnston
1506f6e214c7SGavin Maltby if (ifiles == NULL)
1507f6e214c7SGavin Maltby free(ifile);
1508f6e214c7SGavin Maltby else
1509f6e214c7SGavin Maltby cleanup(ifiles, n_ifiles);
1510f6e214c7SGavin Maltby
15117c478bd9Sstevel@tonic-gate return (g_errs ? FMDUMP_EXIT_ERROR : FMDUMP_EXIT_SUCCESS);
15127c478bd9Sstevel@tonic-gate }
1513