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