6 struct naglog_file
*nfile
;
8 struct naglog_file
*cur_file
; /* the file we're currently importing */
10 uint num_unhandled
= 0;
12 static hash_table
*interesting_hosts
, *interesting_services
;
14 #define host_code(S) { 0, #S, sizeof(#S) - 1, HOST_##S }
15 static struct string_code host_state
[] = {
18 host_code(UNREACHABLE
),
21 #define service_code(S) { 0, #S, sizeof(#S) - 1, SERVICE_##S }
22 static struct string_code service_state
[] = {
24 service_code(WARNING
),
25 service_code(CRITICAL
),
26 service_code(UNKNOWN
),
29 #define notification_code(S) { 0, #S, sizeof(#S) - 1, NOTIFICATION_##S }
30 static struct string_code notification_reason
[] = {
31 notification_code(ACKNOWLEDGEMENT
),
32 notification_code(FLAPPINGSTART
),
33 notification_code(DOWNTIMESTART
),
34 notification_code(FLAPPINGSTOP
),
35 notification_code(FLAPPINGDISABLED
),
36 notification_code(DOWNTIMESTART
),
37 notification_code(DOWNTIMEEND
),
38 notification_code(DOWNTIMECANCELLED
),
39 notification_code(CUSTOM
),
42 int parse_service_state_gently(const char *str
)
46 for (i
= 0; i
< ARRAY_SIZE(service_state
); i
++) {
47 if (!strcmp(str
, service_state
[i
].str
))
48 return service_state
[i
].code
;
54 int parse_service_state(const char *str
)
56 int ret
= parse_service_state_gently(str
);
59 crash("bad value for service state: '%s'", str
);
64 int parse_host_state_gently(const char *str
)
68 for (i
= 0; i
< ARRAY_SIZE(host_state
); i
++) {
69 if (!strcmp(str
, host_state
[i
].str
))
70 return host_state
[i
].code
;
76 int parse_host_state(const char *str
)
78 int ret
= parse_host_state_gently(str
);
81 crash("bad value for host state: '%s'", str
);
86 int parse_notification_reason(const char *str
)
90 for (i
= 0; i
< ARRAY_SIZE(notification_reason
); i
++) {
91 if (!prefixcmp(str
, notification_reason
[i
].str
))
92 return notification_reason
[i
].code
;
95 return NOTIFICATION_NORMAL
;
98 int soft_hard(const char *str
)
100 if (!strcmp(str
, "HARD"))
103 if (!strcmp(str
, "SOFT"))
105 crash("wtf kind of value is '%s' to determine 'soft' or 'hard' from?", str
);
108 static int print_string(void *data
)
110 const char *str
= data
;
112 printf("%p: %s\n", str
, str
);
117 * prints the objects we consider interesting
119 void print_interesting_objects(void)
121 if (interesting_hosts
) {
122 printf("\nInteresting hosts:\n");
123 hash_walk_data(interesting_hosts
, print_string
);
125 if (interesting_services
) {
126 printf("\nInteresting services:\n");
127 hash_walk_data(interesting_services
, print_string
);
129 if (interesting_hosts
|| interesting_services
)
133 /* marks one object as 'interesting' */
134 int add_interesting_object(const char *orig_str
)
136 char *semi_colon
, *str
;
138 str
= strdup(orig_str
);
139 semi_colon
= strchr(str
, ';');
141 if (!interesting_hosts
)
142 interesting_hosts
= hash_init(512);
143 if (!interesting_hosts
)
144 crash("Failed to initialize hash table for interesting hosts");
145 hash_add(interesting_hosts
, str
, strdup(orig_str
));
147 if (!interesting_services
)
148 interesting_services
= hash_init(512);
149 if (!interesting_services
)
150 crash("Failed to initialize hash table for interesting services");
152 hash_add2(interesting_services
, str
, semi_colon
, strdup(orig_str
));
158 int is_interesting_host(const char *host
)
160 if (interesting_hosts
)
161 return !!hash_find(interesting_hosts
, host
);
166 int is_interesting_service(const char *host
, const char *service
)
168 /* fall back to checking if host is interesting */
169 if (!service
|| !interesting_services
)
170 return is_interesting_host(host
);
172 return !!hash_find2(interesting_services
, host
, service
);
175 struct unhandled_event
{
179 struct unhandled_event
*next
;
182 static struct unhandled_event
*event_list
;
184 * This is a fairly toothless function, since we can encounter
185 * pretty much any kind of message in the logfiles. In order to
186 * make sure we don't miss anything important though, we stash
187 * the messages and print them at the end if we're debugging.
189 void handle_unknown_event(const char *line
)
191 struct unhandled_event
*event
;
195 if (!(event
= malloc(sizeof(*event
))) || !(event
->line
= strdup(line
))) {
196 crash("Failed to allocate memory for unhandled event [%s]\n", line
);
200 event
->line_no
= line_no
;
201 event
->file
= cur_file
->path
;
203 /* add to "top" of list. we'll print in reverse order */
204 event
->next
= event_list
;
208 void print_unhandled_events(void)
210 struct unhandled_event
*event
;
216 printf("\n%u Unhandled events encountered:\n" \
217 "------------------------------", num_unhandled
);
219 for (x
= 1; num_unhandled
> (x
* 10); x
*= 10)
223 for (event
= event_list
; event
; event
= event
->next
) {
224 printf("%s:%d:\n%s\n----\n", event
->file
, event
->line_no
, event
->line
);
228 int vectorize_string(char *str
, int nvecs
)
234 for (p
= str
; *p
&& i
< nvecs
; p
++) {
245 get_string_code(struct string_code
*codes
, const char *str
, uint len
)
249 for (i
= 0; codes
[i
].str
; i
++)
250 if (codes
[i
].len
== len
&& !memcmp(str
, codes
[i
].str
, len
))
256 int is_interesting(const char *ptr
)
258 if (!prefixcmp(ptr
, "Auto-save of retention data"))
260 if (!prefixcmp(ptr
, "Event broker module"))
262 if (!prefixcmp(ptr
, "You do not have permission"))
264 if (!prefixcmp(ptr
, "Local time is"))
270 int is_start_event(const char *ptr
)
272 if (!prefixcmp(ptr
, "Finished daemonizing..."))
274 if (!prefixcmp(ptr
, "Caught SIGHUP"))
276 if (strstr(ptr
, "starting..."))
282 int is_stop_event(const char *ptr
)
284 if (!prefixcmp(ptr
, "PROGRAM_RESTART"))
286 if (!prefixcmp(ptr
, "Caught SIGTERM"))
288 if (!prefixcmp(ptr
, "Successfully shutdown..."))
290 if (!prefixcmp(ptr
, "Bailing out"))
292 if (!prefixcmp(ptr
, "Lockfile"))
294 if (strstr(ptr
, "shutting down..."))
300 int strtotimet(const char *str
, time_t *val
)
304 *val
= strtoul(str
, &endp
, 10);
306 warn("strtotimet(): %s is not a valid time_t\n", str
);
313 /*** general utility functions ***/
314 void __attribute__((__noreturn__
)) crash(const char *fmt
, ...)
319 vfprintf(stderr
, fmt
, ap
);
324 fprintf(stderr
, "crash() called when parsing line %u in %s\n",
325 line_no
, cur_file
->path
);
331 void pdebug(int lvl
, const char *fmt
, ...)
335 if (debug_level
< lvl
)
341 if (fmt
[strlen(fmt
) - 1] != '\n')
345 void warn(const char *fmt
, ...)
364 * Returns an increasing numeric value for a nagios logfile
365 * For a file with a name such as:
366 * nagios-12-01-2002-00.log
371 uint
path_cmp_number(char *path
)
376 unsigned long part
[NUM_PARTS
];
378 dash
= strrchr(path
, '/');
385 * we special-case nagios.log as always being the
386 * last file to be parsed. It has to be, since it's
387 * the currently active logfile
389 if (!strcmp(dash
, "nagios.log"))
390 return 1 << ((8 * sizeof(ret
)) - 1);
393 if (len
< 18 || strcmp(&dash
[len
- 4], ".log"))
396 for (i
= 0; i
< NUM_PARTS
; i
++) {
399 dash
= strchr(dash
, '-');
404 part
[i
] = strtoul(dash
, &endp
, 10);
405 if (!part
[i
] && dash
== endp
)
411 if (part
[0] < 1 || part
[0] > 12)
413 if (part
[1] < 1 || part
[1] > 31)
417 ret
= part
[2] * 1000000;
418 ret
+= part
[0] * 10000;
419 ret
+= part
[1] * 100;
425 #define min(a, b) ((a) < (b) ? (a) : (b))
426 void first_log_time(struct naglog_file
*nf
)
432 if (!(fd
= open(nf
->path
, O_RDONLY
)))
433 crash("Failed to open %s: %s", nf
->path
, strerror(errno
));
436 * since we're looking at every file in here anyway,
437 * we also determine the size of them so we can do an
438 * arena allocation large enough to fit the largest
439 * file + an added newline later
441 if (fstat(fd
, &st
) < 0)
442 crash("Failed to stat %s: %s", nf
->path
, strerror(errno
));
444 nf
->size
= st
.st_size
;
446 if (read(fd
, buf
, sizeof(buf
)) < min(sizeof(buf
), st
.st_size
))
447 crash("Incomplete read of %s", nf
->path
);
449 buf
[sizeof(buf
) - 1] = 0;
450 /* skip empty lines at top of file */
451 while (i
< sizeof(buf
) - 12 && (buf
[i
] == '\n' || buf
[i
] == '\r'))
454 if (strtotimet(buf
+ i
+ 1, &nf
->first
))
455 crash("'%s' has no timestamp for us to parse", buf
);
457 nf
->cmp
= path_cmp_number(nf
->path
);
461 static void filesort_mismatch(const struct naglog_file
*a
, const struct naglog_file
*b
)
463 printf("filesort mismatch:\n");
464 printf(" %s:\n cmp: %d\n first: %lu\n", a
->path
, a
->cmp
, a
->first
);
465 printf(" %s:\n cmp: %d\n first: %lu\n", b
->path
, b
->cmp
, b
->first
);
466 crash("%s and %s have same 'first' and 'cmp'? Bizarre...", a
->path
, b
->path
);
470 * sort function for nagios logfiles. Sorts based on
471 * first logged timestamp and then on filename, ascendingly
473 int nfile_cmp(const void *p1
, const void *p2
)
475 const struct naglog_file
*a
= p1
;
476 const struct naglog_file
*b
= p2
;
478 if (a
->first
> b
->first
)
480 if (b
->first
> a
->first
)
488 filesort_mismatch(a
, b
);
492 /* same as above, but sorts in reverse order */
493 int nfile_rev_cmp(const void *p1
, const void *p2
)
495 const struct naglog_file
*a
= p1
;
496 const struct naglog_file
*b
= p2
;
498 if (a
->first
< b
->first
)
500 if (b
->first
< a
->first
)
508 filesort_mismatch(a
, b
);
514 # define PATH_MAX 4096
516 /* recurse into a log-archive path and find all logfiles there */
517 static int add_naglog_directory(const char *dir
)
522 uint dlen
= strlen(dir
);
526 crash("Failed to opendir(%s): %s\n", dir
, strerror(errno
));
528 memcpy(path
, dir
, dlen
);
530 while ((de
= readdir(dirp
))) {
533 if (prefixcmp(de
->d_name
, "nagios"))
535 name_len
= strlen(de
->d_name
);
536 if (strcmp(&de
->d_name
[name_len
- 4], ".log"))
539 /* build some sort of path to the file */
540 memcpy(&path
[dlen
], de
->d_name
, name_len
);
541 path
[dlen
+ name_len
] = 0;
542 add_naglog_path(path
);
548 /* Handles both files and directories */
549 int add_naglog_path(char *path
)
554 /* make sure we never add duplicate files */
555 for (i
= 0; i
< num_nfile
; i
++) {
556 if (!strcmp(nfile
[i
].path
, path
))
560 if (stat(path
, &st
) < 0) {
561 crash("Failed to stat '%s': %s", path
, strerror(errno
));
563 if (S_ISDIR(st
.st_mode
)) {
564 return add_naglog_directory(path
);
567 if (num_nfile
>= nfile_alloc
- 1) {
569 nfile
= realloc(nfile
, nfile_alloc
* sizeof(*nfile
));
572 nfile
[num_nfile
].path
= strdup(path
);
573 first_log_time(&nfile
[num_nfile
]);