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