import: Only read last time from sql if --incremental lacks timestamp
[nagios-reports-module.git] / showlog.c
blob449ba127e080fbf1fbbfaee6d4941e4e83cc65c2
1 #define _GNU_SOURCE 1
2 #include <sys/types.h>
3 #include <signal.h>
4 #include <stdarg.h>
6 #include "logging.h"
7 #include "hash.h"
8 #include "lparse.h"
9 #include "logutils.h"
10 #include "cfgfile.h"
11 #include "auth.h"
12 #include "state.h"
14 #define MAX_NVECS 16
15 #define HASH_TABLE_SIZE 128
17 static time_t first_time, last_time; /* first and last timestamp to show */
18 static time_t last_ltime, ltime; /* timestamp of last and current log-line */
19 static uint last_severity, severity = -1;
20 static const char *image_url = "/ninja/application/views/themes/default/icons/16x16";
21 static int reverse_parse_files;
22 static unsigned long long ltime_skews, skip, limit;
23 static int hide_state_dupes; /* if set, we hide duplicate state messages */
25 #define EVT_PROCESS (1 << 0)
26 #define EVT_NOTIFY (1 << 1)
27 #define EVT_ALERT (1 << 2)
28 #define EVT_COMMAND (1 << 3)
29 #define EVT_STATE (1 << 4)
30 #define EVT_FLAPPING (1 << 5)
31 #define EVT_DOWNTIME (1 << 6)
32 #define EVT_LROTATE (1 << 7)
33 #define EVT_EHANDLER (1 << 8)
34 #define EVT_START (1 << 9)
35 #define EVT_STOP (1 << 10)
37 #define EVT_HOST (1 << 20)
38 #define EVT_SERVICE (1 << 21)
40 static uint event_filter = ~0;
41 static int host_state_filter = -1;
42 static int service_state_filter = -1;
43 static int statetype_filter = (1 << HARD_STATE) | (1 << SOFT_STATE);
45 #define add_event(string, eventcode) add_code(0, string, eventcode)
46 static struct string_code event_codes[] = {
47 add_event("Error", EVT_PROCESS),
48 add_event("Warning", EVT_PROCESS),
49 add_event("HOST NOTIFICATION", EVT_NOTIFY | EVT_SERVICE),
50 add_event("HOST FLAPPING ALERT", EVT_FLAPPING | EVT_HOST),
51 add_event("SERVICE NOTIFICATION", EVT_NOTIFY | EVT_SERVICE),
52 add_event("SERVICE FLAPPING ALERT", EVT_FLAPPING | EVT_SERVICE),
53 add_event("LOG ROTATION", EVT_LROTATE),
54 add_event("HOST EVENT HANDLER", EVT_EHANDLER | EVT_HOST),
55 add_event("SERVICE EVENT HANDLER", EVT_EHANDLER | EVT_SERVICE),
56 add_event("LOG VERSION", EVT_PROCESS),
57 add_event("EXTERNAL COMMAND", EVT_COMMAND),
59 add_code(5, "HOST ALERT", EVT_ALERT | EVT_HOST),
60 add_code(5, "INITIAL HOST STATE", EVT_STATE | EVT_HOST),
61 add_code(5, "CURRENT HOST STATE", EVT_STATE | EVT_HOST),
62 add_code(6, "SERVICE ALERT", EVT_ALERT | EVT_SERVICE),
63 add_code(6, "INITIAL SERVICE STATE", EVT_STATE | EVT_SERVICE),
64 add_code(6, "CURRENT SERVICE STATE", EVT_STATE | EVT_SERVICE),
65 add_code(3, "HOST DOWNTIME ALERT", EVT_DOWNTIME | EVT_HOST),
66 add_code(4, "SERVICE DOWNTIME ALERT", EVT_DOWNTIME | EVT_SERVICE),
67 { 0, NULL, 0, 0 },
70 static void print_time_iso8601(struct tm *t)
72 printf("[%d-%02d-%02d %02d:%02d:%02d] ",
73 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
74 t->tm_hour, t->tm_min, t->tm_sec);
77 static void print_time_div_iso8601(struct tm *t)
79 printf("%d-%02d-%02d %02d:00 ",
80 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour);
83 static void print_time_duration(struct tm *t)
85 printf("[%6lu] ", ltime - last_ltime);
88 static void print_time_raw(struct tm *t)
90 printf("[%lu] ", ltime);
93 static struct {
94 char *name;
95 void (*func)(struct tm *);
96 void (*func_div)(struct tm *);
97 } time_format_selections[] = {
98 { "iso8601", print_time_iso8601, print_time_div_iso8601 },
99 { "raw", print_time_raw, NULL },
100 { "duration", print_time_duration, NULL },
101 { NULL },
103 static void (*print_time)(struct tm *) = print_time_iso8601;
104 static void (*print_time_div)(struct tm *) = print_time_div_iso8601;
106 static void parse_time_format(const char *selection)
108 int i;
110 if (selection) for (i = 0; time_format_selections[i].name; i++) {
111 if (strcasecmp(selection, time_format_selections[i].name))
112 continue;
113 print_time = time_format_selections[i].func;
114 print_time_div = time_format_selections[i].func_div;
115 return;
118 crash("Illegal timeformat selection: '%s'\n", selection);
121 static inline void pre_print_mangle_line(struct tm *t, char *line, uint len)
123 uint i;
125 for (i = 0; i < len; i++) {
126 if (!line[i])
127 line[i] = ';';
130 localtime_r(&ltime, t);
134 static void print_line_ascii(int type, struct tm *t, char *line, uint len)
136 print_time(t);
137 puts(line);
141 static void print_line_ansi(int type, struct tm *t, char *line, uint len)
143 const char *color = NULL;
145 switch (type) {
146 case EVT_ALERT | EVT_HOST:
147 case EVT_STATE | EVT_HOST:
148 if (severity == HOST_UP)
149 color = CLR_GREEN;
150 else
151 color = CLR_RED;
152 break;
154 case EVT_ALERT | EVT_SERVICE:
155 case EVT_STATE | EVT_SERVICE:
156 switch (severity) {
157 case SERVICE_OK: color = CLR_GREEN; break;
158 case SERVICE_WARNING: color = CLR_YELLOW; break;
159 case SERVICE_CRITICAL: color = CLR_RED; break;
160 case SERVICE_UNKNOWN: color = CLR_BROWN; break;
162 break;
164 case EVT_DOWNTIME | EVT_HOST:
165 case EVT_DOWNTIME | EVT_SERVICE:
166 color = CLR_BRIGHT_CYAN;
167 break;
169 case EVT_FLAPPING | EVT_HOST:
170 case EVT_FLAPPING | EVT_SERVICE:
171 color = CLR_CYAN;
172 break;
174 case EVT_NOTIFY | EVT_HOST:
175 case EVT_NOTIFY | EVT_SERVICE:
176 color = CLR_BRIGHT_RED;
177 break;
179 case EVT_PROCESS:
180 color = CLR_MAGENTA;
181 break;
183 case EVT_LROTATE:
184 color = CLR_BOLD;
185 break;
187 case EVT_COMMAND:
188 color = CLR_BRIGHT_MAGENTA;
189 break;
191 case EVT_START: case EVT_STOP:
192 color = CLR_BRIGHT_BLUE;
193 break;
196 if (color) {
197 printf("%s", color);
198 print_time(t);
199 printf("%s%s\n", line, CLR_RESET);
200 } else {
201 print_time(t);
202 puts(line);
207 static void print_time_break(struct tm *t)
209 struct tm h;
211 memcpy(&h, t, sizeof(h));
212 h.tm_min = h.tm_sec = 0;
213 if (reverse_parse_files) {
214 /* using mktime and localtime_r again here means we never
215 * have to worry about changing date, month or year in
216 * case we overshoot by one */
217 time_t when = mktime(&h) + 3600;
218 localtime_r(&when, &h);
221 printf("<h2>");
222 print_time_div(&h);
223 puts("</h2>");
227 static void print_line_html(int type, struct tm *t, char *line, uint len)
229 const char *image = NULL;
230 static time_t last_time_break = 0;
232 switch (type) {
233 case EVT_ALERT | EVT_HOST:
234 case EVT_STATE | EVT_HOST:
235 if (severity == HOST_UP)
236 image = "shield-ok.png";
237 else
238 image = "shield-critical.png";
239 break;
241 case EVT_ALERT | EVT_SERVICE:
242 case EVT_STATE | EVT_SERVICE:
243 switch (severity) {
244 case SERVICE_OK: image = "shield-ok.png"; break;
245 case SERVICE_WARNING: image = "shield-warning.png"; break;
246 case SERVICE_CRITICAL: image = "shield-critical.png"; break;
247 case SERVICE_UNKNOWN: image = "shield-unknown.png"; break;
249 break;
251 case EVT_DOWNTIME | EVT_HOST:
252 case EVT_DOWNTIME | EVT_SERVICE:
253 image = "scheduled-downtime.png";
254 break;
256 case EVT_FLAPPING | EVT_HOST:
257 case EVT_FLAPPING | EVT_SERVICE:
258 image = "flapping.gif";
259 break;
261 case EVT_NOTIFY | EVT_HOST:
262 case EVT_NOTIFY | EVT_SERVICE:
263 image = "notify-send.png";
264 break;
266 case EVT_COMMAND:
267 image = "command.png";
268 break;
270 case EVT_LROTATE:
271 image = "logrotate.png";
272 break;
274 case EVT_EHANDLER | EVT_HOST:
275 image = "hostevent.gif";
276 break;
278 case EVT_EHANDLER | EVT_SERVICE:
279 image = "serviceevent.gif";
280 break;
282 case EVT_START:
283 image = "start.png";
284 break;
286 case EVT_STOP:
287 image = "stop.png";
288 break;
291 if (!image)
292 image = "shield-info.png";
294 if (last_time_break != ltime / 3600) {
295 print_time_break(t);
296 last_time_break = ltime / 3600;
299 printf("<img src=\"%s/%s\" alt=\"%s\" /> ", image_url, image, image);
300 print_time(t);
301 printf("%s<br />\n", line);
305 static void (*real_print_line)(int type, struct tm *, char *, uint) = print_line_ascii;
306 static void print_line(int type, char *line, uint len)
308 static int last_type = 0;
309 static char *last_line = NULL;
310 static uint last_len = 0;
311 struct tm t;
313 /* are we still skipping? If so, return early */
314 if (skip) {
315 skip--;
316 return;
319 pre_print_mangle_line(&t, line, len);
320 if (print_time == print_time_duration) {
321 int cur_severity = severity;
322 if (last_line) {
323 severity = last_severity;
324 real_print_line(last_type, &t, last_line, last_len);
325 severity = cur_severity;
326 free(last_line);
328 last_severity = severity;
329 if (line)
330 last_line = strdup(line);
331 last_type = type;
332 last_len = len;
333 last_ltime = ltime;
334 } else {
335 real_print_line(type, &t, line, len);
338 /* if we've printed all the lines we should, just exit */
339 if (limit) {
340 if (!--limit)
341 exit(0);
346 static int parse_line(char *orig_line, uint len)
348 char *ptr, *colon, *line;
349 int nvecs = 0;
350 struct string_code *sc;
351 int hard;
352 static time_t prev_ltime = 0;
354 line_no++;
356 /* ignore empty lines */
357 if (!len)
358 return 0;
360 /* skip obviously bogus lines */
361 if (len < 12 || *orig_line != '[') {
362 warn("line %d; len too short, or line doesn't start with '[' (%s)",
363 line_no, orig_line);
364 return -1;
367 ltime = strtoul(orig_line + 1, &ptr, 10);
368 if (orig_line + 1 == ptr) {
369 crash("Failed to parse log timestamp from '%s'. I can't handle malformed logdata",
370 orig_line);
371 return -1;
374 /* only print lines in the interesting interval */
375 if (ltime < first_time || ltime > last_time)
376 return 0;
379 * if ltime is less than the previously parsed ltime,
380 * increment the skew count. otherwise, update prev_ltime
381 * so timestamps stay incremental and skews are counted
382 * accurately
384 if (ltime < prev_ltime) {
385 ltime_skews++;
386 } else {
387 prev_ltime = ltime;
390 while (*ptr == ']' || *ptr == ' ')
391 ptr++;
393 line = ptr;
394 len -= line - orig_line;
396 if (!is_interesting(ptr))
397 return 0;
399 if (!(colon = strchr(ptr, ':'))) {
400 /* stupid heuristic, but might be good for something,
401 * somewhere, sometime. if nothing else, it should suppress
402 * annoying output */
403 if (!(event_filter & EVT_PROCESS))
404 return 0;
406 if (is_start_event(ptr)) {
407 print_line(EVT_START, line, len);
408 } else if (is_stop_event(ptr)) {
409 print_line(EVT_STOP, line, len);
412 return 0;
415 if (!(sc = get_event_type(ptr, colon - ptr))) {
416 return 0;
419 if (sc->code == IGNORE_LINE)
420 return 0;
421 if ((sc->code & event_filter) != sc->code)
422 return 0;
424 severity = -1;
425 ptr = colon + 1;
426 while (*ptr == ' ')
427 ptr++;
429 if (sc->nvecs) {
430 int i;
432 nvecs = vectorize_string(ptr, sc->nvecs);
434 if (nvecs != sc->nvecs) {
435 /* broken line */
436 warn("Line %d in %s seems to not have all the fields it should",
437 line_no, cur_file->path);
438 return -1;
441 for (i = 0; i < sc->nvecs; i++) {
442 if (!strv[i]) {
443 /* this should never happen */
444 warn("Line %d in %s seems to be broken, or we failed to parse it into a vector",
445 line_no, cur_file->path);
446 return -1;
451 switch (sc->code) {
452 case EVT_ALERT | EVT_HOST:
453 case EVT_STATE | EVT_HOST:
454 hard = soft_hard(strv[2]);
455 if (!(statetype_filter & (1 << hard)))
456 return 0;
457 severity = parse_host_state(strv[1]);
458 if (!(host_state_filter & (1 << severity)))
459 return 0;
460 if (!auth_host_ok(strv[0]))
461 return 0;
462 if (!is_interesting_host(strv[0]))
463 return 0;
464 if (hide_state_dupes && !host_has_new_state(strv[0], severity, hard))
465 return 0;
467 break;
469 case EVT_ALERT | EVT_SERVICE:
470 case EVT_STATE | EVT_SERVICE:
471 hard = soft_hard(strv[3]);
472 if (!(statetype_filter & (1 << hard)))
473 return 0;
474 severity = parse_service_state(strv[2]);
475 if (!(service_state_filter & (1 << severity)))
476 return 0;
477 if (!auth_service_ok(strv[0], strv[1]))
478 return 0;
479 if (!is_interesting_service(strv[0], strv[1]))
480 return 0;
481 if (hide_state_dupes && !service_has_new_state(strv[0], strv[1], severity, hard))
482 return 0;
484 break;
486 case EVT_FLAPPING | EVT_HOST:
487 case EVT_DOWNTIME | EVT_HOST:
488 if (!auth_host_ok(strv[0]))
489 return 0;
490 if (!is_interesting_host(strv[0]))
491 return 0;
492 break;
494 case EVT_FLAPPING | EVT_SERVICE:
495 case EVT_DOWNTIME | EVT_SERVICE:
496 if (!auth_service_ok(strv[0], strv[1]))
497 return 0;
498 if (!is_interesting_service(strv[0], strv[1]))
499 return 0;
500 break;
502 case EVT_NOTIFY | EVT_HOST:
503 if (!auth_host_ok(strv[1]))
504 return 0;
505 if (!is_interesting_host(strv[1]))
506 return 0;
508 case EVT_NOTIFY | EVT_SERVICE:
509 if (!auth_service_ok(strv[1], strv[2]))
510 return 0;
511 if (!is_interesting_service(strv[1], strv[2]))
512 return 0;
515 print_line(sc->code, line, len);
516 return 0;
520 * hashes one line from an "interesting"-file. We use (void *)1
521 * to mark this as "present in hash-table" as we have no real
522 * data to lookup but still want hash_find{,2} to return non-NULL
523 * when it finds a match
525 static int hash_one_line(char *line, uint len)
527 return add_interesting_object(line);
530 static int hash_interesting(const char *path)
532 struct stat st;
534 if (stat(path, &st) < 0)
535 crash("failed to stat %s: %s", path, strerror(errno));
537 lparse_path(path, st.st_size, hash_one_line);
539 return 0;
542 static void parse_host_state_filter(char *p)
544 host_state_filter = 0;
545 for (; *p; p++) {
546 switch (*p) {
547 case 'a': case '*':
548 host_state_filter = -1;
549 break;
550 case 'u':
551 host_state_filter |= 1 << HOST_UNREACHABLE;
552 break;
553 case 'd':
554 host_state_filter |= 1 << HOST_DOWN;
555 break;
556 case 'r':
557 host_state_filter |= 1 << HOST_UP;
558 break;
563 static void parse_service_state_filter(char *p)
565 service_state_filter = 0;
566 for (; *p; p++) {
567 switch (*p) {
568 case 'a': case '*':
569 service_state_filter = -1;
570 break;
571 case 'r':
572 service_state_filter |= 1 << SERVICE_OK;
573 break;
574 case 'w':
575 service_state_filter |= 1 << SERVICE_WARNING;
576 break;
577 case 'c':
578 service_state_filter |= 1 << SERVICE_CRITICAL;
579 break;
580 case 'u':
581 service_state_filter |= 1 << SERVICE_UNKNOWN;
586 extern const char *__progname;
587 __attribute__((__format__(__printf__, 1, 2)))
588 static void usage(const char *fmt, ...)
590 int i;
592 if (fmt && *fmt) {
593 va_list ap;
595 va_start(ap, fmt);
596 vprintf(fmt, ap);
597 va_end(ap);
600 printf("usage: %s [options] [logfiles]\n\n", __progname);
601 printf(" <logfiles> refers to all the nagios logfiles you want to search through\n");
602 printf(" If --nagios-cfg is given or can be inferred no logfiles need to be supplied\n");
603 printf("Options:\n");
604 printf(" --reverse parse (and print) logs in reverse\n");
605 printf(" --help this cruft\n");
606 printf(" --debug print debugging information\n");
607 printf(" --html print html output\n");
608 printf(" --ansi force-colorize the output\n");
609 printf(" --ascii don't colorize the output\n"),
610 printf(" --user=<username> show only logs this user can see\n");
611 printf(" --cgi-cfg=</path/to/cgi.cfg> path to cgi.cfg\n");
612 printf(" --nagios-cfg=</path/to/nagios.cfg> path to nagios.cfg\n");
613 printf(" --object-cache=</path/to/objects.cache> path to objects.cache\n");
614 printf(" --image-url=<image url> url to images. Implies --html\n");
615 printf(" --hide-state-dupes hide duplicate status messages\n");
616 printf(" --hide-flapping hide flapping messages\n");
617 printf(" --hide-downtime hide downtime messages\n");
618 printf(" --hide-process hide process messages\n");
619 printf(" --hide-command hide external command messages\n");
620 printf(" --hide-notifications hide notification messages\n");
621 printf(" --hide-logrotation hide log rotation messages\n");
622 printf(" --hide-initial hide INITIAL and CURRENT states\n");
623 printf(" --hide-all hide all events\n");
624 printf(" --show-ltime-skews print logtime clock skews\n");
625 printf(" --skip=<integer> number of filtered in messages to skip\n");
626 printf(" --limit=<integer> max number of messages to print\n");
627 printf(" --host=<host_name> show log entries for the named host\n");
628 printf(" --service=<hostname;servicedescription> show log entries for the named service\n");
629 printf(" --first=<timestamp> first log-entry to show\n");
630 printf(" --last=<timestamp> last log-entry to show\n");
631 printf(" --state-type=[hard|soft] state-types to show. default is all\n");
632 printf(" --host-states=[*ardu] host-states to show. can be mixed\n");
633 printf(" 'a' and '*' shows 'all'\n");
634 printf(" 'r' shows 'recovery'\n");
635 printf(" 'd' shows 'down'\n");
636 printf(" 'u' shows 'unreachable'\n");
637 printf(" --service-states=[*arwcu] service-states to show. can be mixed\n");
638 printf(" 'a' and '*' shows 'all'\n");
639 printf(" 'r' shows 'recovery'\n");
640 printf(" 'w' shows 'warning'\n");
641 printf(" 'c' shows 'critical'\n");
642 printf(" 'u' shows 'unknown'\n");
643 printf(" --time-format=[");
644 for (i = 0; time_format_selections[i].name; i++) {
645 printf("%s", time_format_selections[i].name);
646 if (time_format_selections[i + 1].name)
647 printf("|");
649 printf("] set timeformat for log-entries\n");
651 putchar('\n');
653 if (fmt && *fmt)
654 exit(1);
656 exit(0);
659 #define OPT_SHOW 0
660 #define OPT_HIDE 1
661 #define show_hide_code(s, opt) { 0, s, sizeof(#s) - 1, opt }
662 int show_hide(char *arg, char *opt)
664 int what;
665 uint filter = 0, show_filter = 0;
667 if (!prefixcmp(arg, "--hide"))
668 what = OPT_HIDE;
669 else if (!prefixcmp(arg, "--show"))
670 what = OPT_SHOW;
671 else
672 return -1;
674 if (arg[6] == '-') {
675 arg = arg + 7;
676 } else {
677 arg = opt;
680 for (;;) {
681 char *comma = strchr(arg, ',');
682 if (comma)
683 *comma = 0;
686 * 'filter' must be OR'ed to here, since we only OR or
687 * reverse-AND it once after the loop is done
689 if (!prefixcmp(arg, "flapping")) {
690 filter |= EVT_FLAPPING;
691 show_filter |= EVT_HOST | EVT_SERVICE;
692 } else if (!prefixcmp(arg, "downtime")) {
693 filter |= EVT_DOWNTIME;
694 show_filter |= EVT_HOST | EVT_SERVICE;
695 } else if (!prefixcmp(arg, "process")) {
696 filter |= EVT_PROCESS;
697 } else if (!prefixcmp(arg, "command")) {
698 filter |= EVT_COMMAND;
699 } else if (!prefixcmp(arg, "notification")) {
700 filter |= EVT_NOTIFY;
701 } else if (!prefixcmp(arg, "logrotat")) {
702 filter |= EVT_LROTATE;
703 } else if (!prefixcmp(arg, "initial")) {
704 filter |= EVT_STATE;
705 show_filter |= (EVT_HOST | EVT_SERVICE);
706 } else if (!prefixcmp(arg, "all")) {
707 filter |= -1;
708 } else {
709 usage("Unknown %s option: %s\n",
710 what == OPT_SHOW ? "show" : "hide", comma);
713 if (!comma)
714 break;
715 *comma = ',';
716 arg = comma + 1;
719 if (what == OPT_SHOW) {
720 event_filter |= filter | show_filter;
721 } else {
722 event_filter &= ~filter;
725 return 0;
728 int main(int argc, char **argv)
730 int i, show_ltime_skews = 0;
731 unsigned long long tot_lines = 0;
732 const char *nagios_cfg = NULL, *cgi_cfg = NULL, *object_cache = NULL;
734 strv = calloc(sizeof(char *), MAX_NVECS);
735 if (!strv)
736 crash("Failed to alloc initial structs");
738 if (isatty(fileno(stdout))) {
739 real_print_line = print_line_ansi;
740 event_filter &= ~(EVT_LROTATE | EVT_PROCESS);
743 for (i = 1; i < argc; i++) {
744 char *opt, *arg = argv[i];
745 int arg_len, eq_opt = 0;
747 if ((opt = strchr(arg, '='))) {
748 *opt++ = '\0';
749 eq_opt = 1;
751 else if (i < argc - 1) {
752 opt = argv[i + 1];
755 if (!strcmp(arg, "--reverse")) {
756 reverse_parse_files = 1;
757 continue;
759 if (!strcmp(arg, "--html")) {
760 real_print_line = print_line_html;
761 continue;
763 if (!strcmp(arg, "--ansi")) {
764 real_print_line = print_line_ansi;
765 continue;
767 if (!strcmp(arg, "--ascii")) {
768 real_print_line = print_line_ascii;
769 continue;
771 if (!strcmp(arg, "--debug") || !strcmp(arg, "-d")) {
772 debug_level++;
773 continue;
775 if (!strcmp(arg, "--help")) {
776 usage(NULL);
777 continue;
779 /* these must come before the more general "show/hide" below */
780 if (!prefixcmp(arg, "--show-ltime-skews")) {
781 show_ltime_skews = 1;
782 continue;
784 if (!prefixcmp(arg, "--hide-state-dupes")) {
785 hide_state_dupes = 1;
786 continue;
788 if (!prefixcmp(arg, "--hide") || !prefixcmp(arg, "--show")) {
789 if (show_hide(arg, eq_opt ? opt : NULL) < 0) {
790 usage("Illegal option for '%s': %s\n", arg, opt);
792 continue;
796 if (!prefixcmp(arg, "--")) {
797 if (!opt)
798 usage("Option '%s' requires an argument\n", arg);
799 if (!eq_opt)
800 i++;
803 /* options parsed below require arguments */
804 if (!strcmp(arg, "--user")) {
805 auth_set_user(opt);
806 continue;
808 if (!prefixcmp(arg, "--object-cache")) {
809 object_cache = opt;
810 continue;
812 if (!strcmp(arg, "--nagios-cfg")) {
813 nagios_cfg = opt;
814 continue;
816 if (!strcmp(arg, "--cgi-cfg")) {
817 cgi_cfg = opt;
818 continue;
820 if (!strcmp(arg, "--skip")) {
821 skip = strtoull(opt, NULL, 0);
822 continue;
824 if (!strcmp(arg, "--limit")) {
825 limit = strtoull(opt, NULL, 0);
826 continue;
828 if (!strcmp(arg, "--host")) {
829 event_filter |= EVT_HOST;
830 add_interesting_object(opt);
831 continue;
833 if (!strcmp(arg, "--service")) {
834 event_filter |= EVT_SERVICE;
835 add_interesting_object(opt);
836 continue;
838 if (!strcmp(arg, "--image-url")) {
839 real_print_line = print_line_html;
840 image_url = opt;
841 continue;
843 if (!strcmp(arg, "--interesting") || !strcmp(arg, "-i")) {
844 if (!opt || !*opt)
845 usage("%s requires a filename as argument", arg);
846 hash_interesting(opt);
847 continue;
849 if (!strcmp(arg, "--first") || !strcmp(arg, "--last")) {
850 time_t when;
852 if (!opt || !*opt)
853 crash("%s requires a timestamp as argument", arg);
854 when = strtoul(opt, NULL, 0);
855 if (opt && !eq_opt)
856 i++;
857 if (!strcmp(arg, "--first"))
858 first_time = when;
859 else
860 last_time = when;
861 continue;
863 if (!strcmp(arg, "--state-type")) {
864 if (!strcasecmp(opt, "hard"))
865 statetype_filter = (1 << HARD_STATE);
866 if (!strcasecmp(opt, "soft"))
867 statetype_filter = (1 << SOFT_STATE);
868 continue;
870 if (!strcmp(arg, "--host-states")) {
871 event_filter |= EVT_HOST;
872 parse_host_state_filter(opt);
873 continue;
875 if (!strcmp(arg, "--service-states")) {
876 event_filter |= EVT_SERVICE;
877 parse_service_state_filter(opt);
878 continue;
880 if (!strcmp(arg, "--time-format")) {
881 parse_time_format(opt);
882 continue;
885 /* non-argument, so treat as config- or log-file */
886 arg_len = strlen(arg);
887 if (arg_len > 7 && !strcmp(&arg[arg_len - 7], "cgi.cfg")) {
888 cgi_cfg = arg;
889 } else if (!strcmp(&arg[strlen(arg) - 10], "nagios.cfg")) {
890 nagios_cfg = arg;
891 } else {
892 add_naglog_path(arg);
896 if (limit && print_time == print_time_duration) {
897 limit++;
900 if (debug_level)
901 print_interesting_objects();
903 /* fallback for op5 systems */
904 if (auth_get_user() || (!nagios_cfg && !num_nfile)) {
905 struct cfg_comp *conf;
907 conf = cfg_parse_file(cgi_cfg ? cgi_cfg : "/opt/monitor/etc/cgi.cfg");
908 if (conf) {
909 int i;
910 for (i = 0; i < conf->vars; i++) {
911 struct cfg_var *v = conf->vlist[i];
912 if (!nagios_cfg && !strcmp(v->key, "main_config_file")) {
913 nagios_cfg = strdup(v->value);
915 if (!prefixcmp(v->key, "authorized_for_")) {
916 auth_parse_permission(v->key, v->value);
919 cfg_destroy_compound(conf);
920 } else {
921 if (cgi_cfg) {
922 crash("Failed to parse cgi.cfg file '%s'\n", cgi_cfg);
924 if (auth_get_user()) {
925 crash("--user given, but no suitable cgi.cfg file found\n");
930 if (!nagios_cfg && !num_nfile) {
931 nagios_cfg = "/opt/monitor/etc/nagios.cfg";
933 if (nagios_cfg) {
934 struct cfg_comp *conf;
936 conf = cfg_parse_file(nagios_cfg);
937 if (!conf)
938 usage("Failed to parse nagios' main config file '%s'\n", nagios_cfg);
939 for (i = 0; i < conf->vars; i++) {
940 struct cfg_var *v = conf->vlist[i];
941 if (!strcmp(v->key, "log_file")) {
942 add_naglog_path(v->value);
944 if (!strcmp(v->key, "log_archive_path")) {
945 add_naglog_path(v->value);
947 if (!object_cache && !strcmp(v->key, "object_cache_file")) {
948 object_cache = v->value;
953 if (!num_nfile)
954 usage(NULL);
956 if (auth_get_user() && object_cache) {
957 auth_init(object_cache);
960 if (hide_state_dupes)
961 state_init();
963 /* make sure first_time and last_time are set */
964 last_time = last_time ? last_time : time(NULL);
965 first_time = first_time ? first_time : 1;
967 /* flip them if the user made an error (common when reverse-importing) */
968 if (last_time < first_time) {
969 int temp = last_time;
970 last_time = first_time;
971 first_time = temp;
974 /* make sure we always have last_ltime */
975 last_ltime = first_time;
977 if (reverse_parse_files)
978 qsort(nfile, num_nfile, sizeof(*nfile), nfile_rev_cmp);
979 else
980 qsort(nfile, num_nfile, sizeof(*nfile), nfile_cmp);
982 for (i = 0; i < num_nfile; i++) {
983 struct naglog_file *nf = &nfile[i];
984 time_t last; /* last possible timestamp in current file */
986 if (reverse_parse_files)
987 last = i ? nfile[i - 1].first : time(NULL);
988 else
989 last = i + 1 < num_nfile ? nfile[i + 1].first : time(NULL);
991 if (first_time > last || last_time < nf->first) {
992 continue;
995 cur_file = nf;
996 debug("importing from %s (%lu : %u)\n", nf->path, nf->first, nf->cmp);
997 tot_lines += line_no;
998 line_no = 0;
999 lparse_path_real(reverse_parse_files, nf->path, nf->size, parse_line);
1002 if (print_time == print_time_duration) {
1003 /* duration should be calculated til the end of the period */
1004 ltime = last_time;
1005 print_line(0, NULL, 0);
1008 if (show_ltime_skews) {
1009 printf("%llu ltime skews in %llu lines. %f%%\n",
1010 ltime_skews, tot_lines,
1011 ((float)ltime_skews / (float)tot_lines) * 100);
1014 if (warnings && debug_level)
1015 fprintf(stderr, "Total warnings: %d\n", warnings);
1017 print_unhandled_events();
1019 return 0;