1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <alloca.h> 27 #include <unistd.h> 28 #include <limits.h> 29 #include <strings.h> 30 #include <stdlib.h> 31 #include <stdarg.h> 32 #include <stdio.h> 33 #include <errno.h> 34 #include <time.h> 35 #include <ctype.h> 36 #include <regex.h> 37 #include <dirent.h> 38 39 #include <fmdump.h> 40 41 #define FMDUMP_EXIT_SUCCESS 0 42 #define FMDUMP_EXIT_FATAL 1 43 #define FMDUMP_EXIT_USAGE 2 44 #define FMDUMP_EXIT_ERROR 3 45 46 const char *g_pname; 47 ulong_t g_errs; 48 ulong_t g_recs; 49 char *g_root; 50 struct topo_hdl *g_thp; 51 52 /*PRINTFLIKE2*/ 53 void 54 fmdump_printf(FILE *fp, const char *format, ...) 55 { 56 va_list ap; 57 58 va_start(ap, format); 59 60 if (vfprintf(fp, format, ap) < 0) { 61 (void) fprintf(stderr, "%s: failed to print record: %s\n", 62 g_pname, strerror(errno)); 63 g_errs++; 64 } 65 66 va_end(ap); 67 } 68 69 void 70 fmdump_vwarn(const char *format, va_list ap) 71 { 72 int err = errno; 73 74 (void) fprintf(stderr, "%s: warning: ", g_pname); 75 (void) vfprintf(stderr, format, ap); 76 77 if (strchr(format, '\n') == NULL) 78 (void) fprintf(stderr, ": %s\n", strerror(err)); 79 80 g_errs++; 81 } 82 83 /*PRINTFLIKE1*/ 84 void 85 fmdump_warn(const char *format, ...) 86 { 87 va_list ap; 88 89 va_start(ap, format); 90 fmdump_vwarn(format, ap); 91 va_end(ap); 92 } 93 94 char * 95 fmdump_date(char *buf, size_t len, const fmd_log_record_t *rp) 96 { 97 if (rp->rec_sec > LONG_MAX) { 98 fmdump_warn("record time is too large for 32-bit utility\n"); 99 (void) snprintf(buf, len, "0x%llx", rp->rec_sec); 100 } else { 101 time_t tod = (time_t)rp->rec_sec; 102 time_t now = time(NULL); 103 if (tod > now+60 || 104 tod < now - 6L*30L*24L*60L*60L) { /* 6 months ago */ 105 (void) strftime(buf, len, "%b %d %Y %T", 106 localtime(&tod)); 107 } else { 108 size_t sz; 109 sz = strftime(buf, len, "%b %d %T", localtime(&tod)); 110 (void) snprintf(buf + sz, len - sz, ".%4.4llu", 111 rp->rec_nsec / (NANOSEC / 10000)); 112 } 113 } 114 115 return (buf); 116 } 117 118 char * 119 fmdump_year(char *buf, size_t len, const fmd_log_record_t *rp) 120 { 121 #ifdef _ILP32 122 if (rp->rec_sec > LONG_MAX) { 123 fmdump_warn("record time is too large for 32-bit utility\n"); 124 (void) snprintf(buf, len, "0x%llx", rp->rec_sec); 125 } else { 126 #endif 127 time_t tod = (time_t)rp->rec_sec; 128 (void) strftime(buf, len, "%b %d %Y %T", localtime(&tod)); 129 #ifdef _ILP32 130 } 131 #endif 132 return (buf); 133 } 134 135 static int 136 usage(FILE *fp) 137 { 138 (void) fprintf(fp, "Usage: %s [-efvV] [-c class] [-R root] [-t time] " 139 "[-T time] [-u uuid]\n\t\t[-n name[.name]*[=value]] [file]\n", 140 g_pname); 141 142 (void) fprintf(fp, 143 "\t-c select events that match the specified class\n" 144 "\t-e display error log content instead of fault log content\n" 145 "\t-f follow growth of log file by waiting for additional data\n" 146 "\t-R set root directory for pathname expansions\n" 147 "\t-t select events that occurred after the specified time\n" 148 "\t-T select events that occurred before the specified time\n" 149 "\t-u select events that match the specified uuid\n" 150 "\t-n select events containing named nvpair " 151 "(with matching value)\n" 152 "\t-v set verbose mode: display additional event detail\n" 153 "\t-V set very verbose mode: display complete event contents\n"); 154 155 return (FMDUMP_EXIT_USAGE); 156 } 157 158 /*ARGSUSED*/ 159 static int 160 error(fmd_log_t *lp, void *private) 161 { 162 fmdump_warn("skipping record: %s\n", 163 fmd_log_errmsg(lp, fmd_log_errno(lp))); 164 return (0); 165 } 166 167 /* 168 * Yet another disgusting argument parsing function (TM). We attempt to parse 169 * a time argument in a variety of strptime(3C) formats, in which case it is 170 * interpreted as a local time and is converted to a timeval using mktime(3C). 171 * If those formats fail, we look to see if the time is a decimal integer 172 * followed by one of our magic suffixes, in which case the time is interpreted 173 * as a time delta *before* the current time-of-day (i.e. "1h" = "1 hour ago"). 174 */ 175 static struct timeval * 176 gettimeopt(const char *arg) 177 { 178 const struct { 179 const char *name; 180 hrtime_t mul; 181 } suffix[] = { 182 { "ns", NANOSEC / NANOSEC }, 183 { "nsec", NANOSEC / NANOSEC }, 184 { "us", NANOSEC / MICROSEC }, 185 { "usec", NANOSEC / MICROSEC }, 186 { "ms", NANOSEC / MILLISEC }, 187 { "msec", NANOSEC / MILLISEC }, 188 { "s", NANOSEC / SEC }, 189 { "sec", NANOSEC / SEC }, 190 { "m", NANOSEC * (hrtime_t)60 }, 191 { "min", NANOSEC * (hrtime_t)60 }, 192 { "h", NANOSEC * (hrtime_t)(60 * 60) }, 193 { "hour", NANOSEC * (hrtime_t)(60 * 60) }, 194 { "d", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 195 { "day", NANOSEC * (hrtime_t)(24 * 60 * 60) }, 196 { NULL } 197 }; 198 199 struct timeval *tvp = malloc(sizeof (struct timeval)); 200 struct timeval tod; 201 struct tm tm; 202 char *p; 203 204 if (tvp == NULL) { 205 (void) fprintf(stderr, "%s: failed to allocate memory: %s\n", 206 g_pname, strerror(errno)); 207 exit(FMDUMP_EXIT_FATAL); 208 } 209 210 if (gettimeofday(&tod, NULL) != 0) { 211 (void) fprintf(stderr, "%s: failed to get tod: %s\n", 212 g_pname, strerror(errno)); 213 exit(FMDUMP_EXIT_FATAL); 214 } 215 216 /* 217 * First try a variety of strptime() calls. If these all fail, we'll 218 * try parsing an integer followed by one of our suffix[] strings. 219 * NOTE: any form using %y must appear *before* the equivalent %Y form; 220 * otherwise %Y will accept the two year digits but infer century zero. 221 * Any form ending in %y must additionally check isdigit(*p) to ensure 222 * that it does not inadvertently match 2 digits of a 4-digit year. 223 * 224 * Beware: Any strptime() sequence containing consecutive %x sequences 225 * may fall victim to SCCS expanding it as a keyword! If this happens 226 * we use separate string constant that ANSI C will concatenate. 227 */ 228 if ((p = strptime(arg, "%m/%d/%y" "%t" "%H:%M:%S", &tm)) == NULL && 229 (p = strptime(arg, "%m/%d/%Y" "%t" "%H:%M:%S", &tm)) == NULL && 230 (p = strptime(arg, "%m/%d/%y" "%t" "%H:%M", &tm)) == NULL && 231 (p = strptime(arg, "%m/%d/%Y" "%t" "%H:%M", &tm)) == NULL && 232 ((p = strptime(arg, "%m/%d/%y", &tm)) == NULL || isdigit(*p)) && 233 (p = strptime(arg, "%m/%d/%Y", &tm)) == NULL && 234 (p = strptime(arg, "%y-%m-%dT%H:%M:%S", &tm)) == NULL && 235 (p = strptime(arg, "%Y-%m-%dT%H:%M:%S", &tm)) == NULL && 236 (p = strptime(arg, "%y-%m-%dT%H:%M", &tm)) == NULL && 237 (p = strptime(arg, "%Y-%m-%dT%H:%M", &tm)) == NULL && 238 (p = strptime(arg, "%y-%m-%d", &tm)) == NULL && 239 (p = strptime(arg, "%Y-%m-%d", &tm)) == NULL && 240 (p = strptime(arg, "%d%b%y" "%t" "%H:%M:%S", &tm)) == NULL && 241 (p = strptime(arg, "%d%b%Y" "%t" "%H:%M:%S", &tm)) == NULL && 242 (p = strptime(arg, "%d%b%y" "%t" "%H:%M", &tm)) == NULL && 243 (p = strptime(arg, "%d%b%Y" "%t" "%H:%M", &tm)) == NULL && 244 ((p = strptime(arg, "%d%b%y", &tm)) == NULL || isdigit(*p)) && 245 (p = strptime(arg, "%d%b%Y", &tm)) == NULL && 246 (p = strptime(arg, "%b%t%d" "%t" "%H:%M:%S", &tm)) == NULL && 247 (p = strptime(arg, "%b%t%d" "%t" "%H:%M:%S", &tm)) == NULL && 248 (p = strptime(arg, "%H:%M:%S", &tm)) == NULL && 249 (p = strptime(arg, "%H:%M", &tm)) == NULL) { 250 251 hrtime_t nsec; 252 int i; 253 254 errno = 0; 255 nsec = strtol(arg, (char **)&p, 10); 256 257 if (errno != 0 || nsec == 0 || p == arg || *p == '\0') { 258 (void) fprintf(stderr, "%s: illegal time " 259 "format -- %s\n", g_pname, arg); 260 exit(FMDUMP_EXIT_USAGE); 261 } 262 263 for (i = 0; suffix[i].name != NULL; i++) { 264 if (strcasecmp(suffix[i].name, p) == 0) { 265 nsec *= suffix[i].mul; 266 break; 267 } 268 } 269 270 if (suffix[i].name == NULL) { 271 (void) fprintf(stderr, "%s: illegal time " 272 "format -- %s\n", g_pname, arg); 273 exit(FMDUMP_EXIT_USAGE); 274 } 275 276 tvp->tv_sec = nsec / NANOSEC; 277 tvp->tv_usec = (nsec % NANOSEC) / (NANOSEC / MICROSEC); 278 279 if (tvp->tv_sec > tod.tv_sec) { 280 (void) fprintf(stderr, "%s: time delta precedes " 281 "UTC time origin -- %s\n", g_pname, arg); 282 exit(FMDUMP_EXIT_USAGE); 283 } 284 285 tvp->tv_sec = tod.tv_sec - tvp->tv_sec; 286 287 } else if (*p == '\0' || *p == '.') { 288 /* 289 * If tm_year is zero, we matched [%b %d] %H:%M[:%S]; use 290 * the result of localtime(&tod.tv_sec) to fill in the rest. 291 */ 292 if (tm.tm_year == 0) { 293 int h = tm.tm_hour; 294 int m = tm.tm_min; 295 int s = tm.tm_sec; 296 int b = tm.tm_mon; 297 int d = tm.tm_mday; 298 299 bcopy(localtime(&tod.tv_sec), &tm, sizeof (tm)); 300 tm.tm_isdst = 0; /* see strptime(3C) and below */ 301 302 if (d > 0) { 303 tm.tm_mon = b; 304 tm.tm_mday = d; 305 } 306 307 tm.tm_hour = h; 308 tm.tm_min = m; 309 tm.tm_sec = s; 310 } 311 312 errno = 0; 313 tvp->tv_sec = mktime(&tm); 314 tvp->tv_usec = 0; 315 316 if (tvp->tv_sec == -1L && errno != 0) { 317 (void) fprintf(stderr, "%s: failed to compose " 318 "time %s: %s\n", g_pname, arg, strerror(errno)); 319 exit(FMDUMP_EXIT_ERROR); 320 } 321 322 /* 323 * If our mktime() set tm_isdst, adjust the result for DST by 324 * subtracting the offset between the main and alternate zones. 325 */ 326 if (tm.tm_isdst) 327 tvp->tv_sec -= timezone - altzone; 328 329 if (p[0] == '.') { 330 arg = p; 331 errno = 0; 332 tvp->tv_usec = 333 (suseconds_t)(strtod(arg, &p) * (double)MICROSEC); 334 335 if (errno != 0 || p == arg || *p != '\0') { 336 (void) fprintf(stderr, "%s: illegal time " 337 "suffix -- .%s\n", g_pname, arg); 338 exit(FMDUMP_EXIT_USAGE); 339 } 340 } 341 342 } else { 343 (void) fprintf(stderr, "%s: unexpected suffix after " 344 "time %s -- %s\n", g_pname, arg, p); 345 exit(FMDUMP_EXIT_USAGE); 346 } 347 348 return (tvp); 349 } 350 351 /* 352 * If the -u option is specified in combination with the -e option, we iterate 353 * over each record in the fault log with a matching UUID finding xrefs to the 354 * error log, and then use this function to iterate over every xref'd record. 355 */ 356 int 357 xref_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 358 { 359 const fmd_log_record_t *xrp = rp->rec_xrefs; 360 fmdump_arg_t *dap = arg; 361 int i, rv = 0; 362 363 for (i = 0; rv == 0 && i < rp->rec_nrefs; i++, xrp++) { 364 if (fmd_log_filter(lp, dap->da_fc, dap->da_fv, xrp)) 365 rv = dap->da_fmt->do_func(lp, xrp, dap->da_fp); 366 } 367 368 return (rv); 369 } 370 371 int 372 xoff_iter(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 373 { 374 fmdump_lyr_t *dyp = arg; 375 376 fmdump_printf(dyp->dy_fp, "%16llx ", (u_longlong_t)rp->rec_off); 377 return (dyp->dy_func(lp, rp, dyp->dy_arg)); 378 } 379 380 /* 381 * Initialize fmd_log_filter_nvarg_t from -n name=value argument string. 382 */ 383 static fmd_log_filter_nvarg_t * 384 setupnamevalue(char *namevalue) 385 { 386 fmd_log_filter_nvarg_t *argt; 387 char *value; 388 regex_t *value_regex = NULL; 389 char errstr[128]; 390 int rv; 391 392 if ((value = strchr(namevalue, '=')) == NULL) { 393 value_regex = NULL; 394 } else { 395 *value++ = '\0'; /* separate name and value string */ 396 397 /* 398 * Skip white space before value to facilitate direct 399 * cut/paste from previous fmdump output. 400 */ 401 while (isspace(*value)) 402 value++; 403 404 if ((value_regex = malloc(sizeof (regex_t))) == NULL) { 405 (void) fprintf(stderr, "%s: failed to allocate memory: " 406 "%s\n", g_pname, strerror(errno)); 407 exit(FMDUMP_EXIT_FATAL); 408 } 409 410 /* compile regular expression for possible string match */ 411 if ((rv = regcomp(value_regex, value, 412 REG_NOSUB|REG_NEWLINE)) != 0) { 413 (void) regerror(rv, value_regex, errstr, 414 sizeof (errstr)); 415 (void) fprintf(stderr, "unexpected regular expression " 416 "in %s: %s\n", value, errstr); 417 free(value_regex); 418 exit(FMDUMP_EXIT_USAGE); 419 } 420 } 421 422 if ((argt = malloc(sizeof (fmd_log_filter_nvarg_t))) == NULL) { 423 (void) fprintf(stderr, "%s: failed to allocate memory: %s\n", 424 g_pname, strerror(errno)); 425 exit(FMDUMP_EXIT_FATAL); 426 } 427 argt->nvarg_name = namevalue; /* now just name */ 428 argt->nvarg_value = value; 429 argt->nvarg_value_regex = value_regex; 430 return (argt); 431 } 432 433 /* 434 * If the -a option is not present, filter out fault records that correspond 435 * to events that the producer requested not be messaged for administrators. 436 */ 437 /*ARGSUSED*/ 438 int 439 log_filter_silent(fmd_log_t *lp, const fmd_log_record_t *rp, void *arg) 440 { 441 boolean_t msg; 442 443 return (nvlist_lookup_boolean_value(rp->rec_nvl, 444 FM_SUSPECT_MESSAGE, &msg) != 0 || msg != 0); 445 } 446 447 struct loglink { 448 char *path; 449 long suffix; 450 struct loglink *next; 451 }; 452 453 static void 454 addlink(struct loglink **llp, char *dirname, char *logname, long suffix) 455 { 456 struct loglink *newp; 457 size_t len; 458 char *str; 459 460 newp = malloc(sizeof (struct loglink)); 461 len = strlen(dirname) + strlen(logname) + 2; 462 str = malloc(len); 463 if (newp == NULL || str == NULL) { 464 (void) fprintf(stderr, "%s: failed to allocate memory: %s\n", 465 g_pname, strerror(errno)); 466 exit(FMDUMP_EXIT_FATAL); 467 } 468 469 (void) snprintf(str, len, "%s/%s", dirname, logname); 470 newp->path = str; 471 newp->suffix = suffix; 472 473 while (*llp != NULL && suffix < (*llp)->suffix) 474 llp = &(*llp)->next; 475 476 newp->next = *llp; 477 *llp = newp; 478 } 479 480 /* 481 * Find and return all the rotated logs. 482 */ 483 static struct loglink * 484 get_rotated_logs(char *logpath) 485 { 486 char dirname[PATH_MAX], *logname, *endptr; 487 DIR *dirp; 488 struct dirent *dp; 489 long len, suffix; 490 struct loglink *head = NULL; 491 492 (void) strlcpy(dirname, logpath, sizeof (dirname)); 493 logname = strrchr(dirname, '/'); 494 *logname++ = '\0'; 495 len = strlen(logname); 496 497 if ((dirp = opendir(dirname)) == NULL) { 498 (void) fprintf(stderr, "%s: failed to opendir `%s': %s\n", 499 g_pname, dirname, strerror(errno)); 500 return (NULL); 501 } 502 503 while ((dp = readdir(dirp)) != NULL) { 504 /* 505 * Search the log directory for logs named "<logname>.0", 506 * "<logname>.1", etc and add to the link in the 507 * reverse numeric order. 508 */ 509 if (strlen(dp->d_name) < len + 2 || 510 strncmp(dp->d_name, logname, len) != 0 || 511 dp->d_name[len] != '.') 512 continue; 513 514 /* 515 * "*.0-" file normally should not be seen. It may 516 * exist when user manually run 'fmadm rotate'. 517 * In such case, we put it at the end of the list so 518 * it'll be dumped after all the rotated logs, before 519 * the current one. 520 */ 521 if (strcmp(dp->d_name + len + 1, "0-") == 0) 522 addlink(&head, dirname, dp->d_name, -1); 523 else if ((suffix = strtol(dp->d_name + len + 1, 524 &endptr, 10)) >= 0 && *endptr == '\0') 525 addlink(&head, dirname, dp->d_name, suffix); 526 } 527 528 (void) closedir(dirp); 529 530 return (head); 531 } 532 533 int 534 main(int argc, char *argv[]) 535 { 536 int opt_a = 0, opt_e = 0, opt_f = 0, opt_H = 0; 537 int opt_u = 0, opt_v = 0, opt_V = 0; 538 539 char ifile[PATH_MAX] = ""; 540 int iflags = 0; 541 542 fmdump_arg_t arg; 543 fmdump_lyr_t lyr; 544 const fmdump_ops_t *ops; 545 fmd_log_filter_t *filtv; 546 uint_t filtc; 547 548 fmd_log_filter_t *errfv, *fltfv, *allfv; 549 uint_t errfc = 0, fltfc = 0, allfc = 0; 550 551 fmd_log_header_t log; 552 fmd_log_rec_f *func; 553 void *farg; 554 fmd_log_t *lp; 555 int c, err; 556 off64_t off = 0; 557 ulong_t recs; 558 struct loglink *rotated_logs = NULL, *llp; 559 560 g_pname = argv[0]; 561 562 errfv = alloca(sizeof (fmd_log_filter_t) * argc); 563 fltfv = alloca(sizeof (fmd_log_filter_t) * argc); 564 allfv = alloca(sizeof (fmd_log_filter_t) * argc); 565 566 while (optind < argc) { 567 while ((c = 568 getopt(argc, argv, "ac:efHn:O:R:t:T:u:vV")) != EOF) { 569 switch (c) { 570 case 'a': 571 opt_a++; 572 break; 573 case 'c': 574 errfv[errfc].filt_func = fmd_log_filter_class; 575 errfv[errfc].filt_arg = optarg; 576 allfv[allfc++] = errfv[errfc++]; 577 break; 578 case 'e': 579 opt_e++; 580 break; 581 case 'f': 582 opt_f++; 583 break; 584 case 'H': 585 opt_H++; 586 break; 587 case 'O': 588 off = strtoull(optarg, NULL, 16); 589 iflags |= FMD_LOG_XITER_OFFS; 590 break; 591 case 'R': 592 g_root = optarg; 593 break; 594 case 't': 595 errfv[errfc].filt_func = fmd_log_filter_after; 596 errfv[errfc].filt_arg = gettimeopt(optarg); 597 allfv[allfc++] = errfv[errfc++]; 598 break; 599 case 'T': 600 errfv[errfc].filt_func = fmd_log_filter_before; 601 errfv[errfc].filt_arg = gettimeopt(optarg); 602 allfv[allfc++] = errfv[errfc++]; 603 break; 604 case 'u': 605 fltfv[fltfc].filt_func = fmd_log_filter_uuid; 606 fltfv[fltfc].filt_arg = optarg; 607 allfv[allfc++] = fltfv[fltfc++]; 608 opt_u++; 609 opt_a++; /* -u implies -a */ 610 break; 611 case 'n': { 612 fltfv[fltfc].filt_func = fmd_log_filter_nv; 613 fltfv[fltfc].filt_arg = setupnamevalue(optarg); 614 allfv[allfc++] = fltfv[fltfc++]; 615 break; 616 } 617 case 'v': 618 opt_v++; 619 break; 620 case 'V': 621 opt_V++; 622 break; 623 default: 624 return (usage(stderr)); 625 } 626 } 627 628 if (optind < argc) { 629 if (*ifile != '\0') { 630 (void) fprintf(stderr, "%s: illegal " 631 "argument -- %s\n", g_pname, argv[optind]); 632 return (FMDUMP_EXIT_USAGE); 633 } else { 634 (void) strlcpy(ifile, 635 argv[optind++], sizeof (ifile)); 636 } 637 } 638 } 639 640 if (*ifile == '\0') { 641 (void) snprintf(ifile, sizeof (ifile), "%s/var/fm/fmd/%slog", 642 g_root ? g_root : "", opt_e && !opt_u ? "err" : "flt"); 643 /* 644 * logadm may rotate the logs. When no input file is specified, 645 * we try to dump all the rotated logs as well in the right 646 * order. 647 */ 648 if (!opt_H && off == 0) 649 rotated_logs = get_rotated_logs(ifile); 650 } else if (g_root != NULL) { 651 (void) fprintf(stderr, "%s: -R option is not appropriate " 652 "when file operand is present\n", g_pname); 653 return (FMDUMP_EXIT_USAGE); 654 } 655 656 if ((lp = fmd_log_open(FMD_LOG_VERSION, ifile, &err)) == NULL) { 657 (void) fprintf(stderr, "%s: failed to open %s: %s\n", 658 g_pname, ifile, fmd_log_errmsg(NULL, err)); 659 return (FMDUMP_EXIT_FATAL); 660 } 661 662 if (opt_H) { 663 fmd_log_header(lp, &log); 664 665 (void) printf("EXD_CREATOR = %s\n", log.log_creator); 666 (void) printf("EXD_HOSTNAME = %s\n", log.log_hostname); 667 (void) printf("EXD_FMA_LABEL = %s\n", log.log_label); 668 (void) printf("EXD_FMA_VERSION = %s\n", log.log_version); 669 (void) printf("EXD_FMA_OSREL = %s\n", log.log_osrelease); 670 (void) printf("EXD_FMA_OSVER = %s\n", log.log_osversion); 671 (void) printf("EXD_FMA_PLAT = %s\n", log.log_platform); 672 (void) printf("EXD_FMA_UUID = %s\n", log.log_uuid); 673 674 return (FMDUMP_EXIT_SUCCESS); 675 } 676 677 if (off != 0 && fmd_log_seek(lp, off) != 0) { 678 (void) fprintf(stderr, "%s: failed to seek %s: %s\n", 679 g_pname, ifile, fmd_log_errmsg(lp, fmd_log_errno(lp))); 680 return (FMDUMP_EXIT_FATAL); 681 } 682 683 if (opt_e && opt_u) 684 ops = &fmdump_err_ops; 685 else if (strcmp(fmd_log_label(lp), fmdump_flt_ops.do_label) == 0) 686 ops = &fmdump_flt_ops; 687 else if (strcmp(fmd_log_label(lp), fmdump_asru_ops.do_label) == 0) 688 ops = &fmdump_asru_ops; 689 else 690 ops = &fmdump_err_ops; 691 692 if (!opt_a && ops == &fmdump_flt_ops) { 693 fltfv[fltfc].filt_func = log_filter_silent; 694 fltfv[fltfc].filt_arg = NULL; 695 allfv[allfc++] = fltfv[fltfc++]; 696 } 697 698 if (opt_V) { 699 arg.da_fmt = &ops->do_formats[FMDUMP_VERB2]; 700 iflags |= FMD_LOG_XITER_REFS; 701 } else if (opt_v) { 702 arg.da_fmt = &ops->do_formats[FMDUMP_VERB1]; 703 } else 704 arg.da_fmt = &ops->do_formats[FMDUMP_SHORT]; 705 706 arg.da_fv = errfv; 707 arg.da_fc = errfc; 708 arg.da_fp = stdout; 709 710 if (iflags & FMD_LOG_XITER_OFFS) 711 fmdump_printf(arg.da_fp, "%16s ", "OFFSET"); 712 713 if (arg.da_fmt->do_hdr) 714 fmdump_printf(arg.da_fp, "%s\n", arg.da_fmt->do_hdr); 715 716 if (opt_e && opt_u) { 717 iflags |= FMD_LOG_XITER_REFS; 718 func = xref_iter; 719 farg = &arg; 720 filtc = fltfc; 721 filtv = fltfv; 722 } else { 723 func = arg.da_fmt->do_func; 724 farg = arg.da_fp; 725 filtc = allfc; 726 filtv = allfv; 727 } 728 729 if (iflags & FMD_LOG_XITER_OFFS) { 730 lyr.dy_func = func; 731 lyr.dy_arg = farg; 732 lyr.dy_fp = arg.da_fp; 733 func = xoff_iter; 734 farg = &lyr; 735 } 736 737 for (llp = rotated_logs; llp != NULL; llp = llp->next) { 738 fmd_log_t *rlp; 739 740 if ((rlp = fmd_log_open(FMD_LOG_VERSION, llp->path, &err)) 741 == NULL) { 742 (void) fprintf(stderr, "%s: failed to open %s: %s\n", 743 g_pname, llp->path, fmd_log_errmsg(NULL, err)); 744 g_errs++; 745 continue; 746 } 747 748 recs = 0; 749 if (fmd_log_xiter(rlp, iflags, filtc, filtv, 750 func, error, farg, &recs) != 0) { 751 (void) fprintf(stderr, 752 "%s: failed to dump %s: %s\n", g_pname, llp->path, 753 fmd_log_errmsg(rlp, fmd_log_errno(rlp))); 754 g_errs++; 755 } 756 g_recs += recs; 757 758 fmd_log_close(rlp); 759 } 760 761 do { 762 recs = 0; 763 if (fmd_log_xiter(lp, iflags, filtc, filtv, 764 func, error, farg, &recs) != 0) { 765 (void) fprintf(stderr, 766 "%s: failed to dump %s: %s\n", g_pname, ifile, 767 fmd_log_errmsg(lp, fmd_log_errno(lp))); 768 g_errs++; 769 } 770 g_recs += recs; 771 772 if (opt_f) 773 (void) sleep(1); 774 775 } while (opt_f); 776 777 if (!opt_f && g_recs == 0 && isatty(STDOUT_FILENO)) 778 (void) fprintf(stderr, "%s: %s is empty\n", g_pname, ifile); 779 780 fmd_log_close(lp); 781 return (g_errs ? FMDUMP_EXIT_ERROR : FMDUMP_EXIT_SUCCESS); 782 } 783