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 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 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 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 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 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 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 * 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 * 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 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 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 * 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 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 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 * 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 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 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 * 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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