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
;
15 int parse_service_state(const char *str
)
17 if (!strcmp(str
, "OK"))
19 if (!strcmp(str
, "WARNING"))
20 return SERVICE_WARNING
;
21 if (!strcmp(str
, "UNKNOWN"))
22 return SERVICE_UNKNOWN
;
23 if (!strcmp(str
, "CRITICAL"))
24 return SERVICE_CRITICAL
;
26 crash("bad value for service state: '%s'", str
);
29 int parse_host_state(const char *str
)
31 if (!strcmp(str
, "UP"))
33 if (!strcmp(str
, "DOWN"))
35 if (!strcmp(str
, "UNREACHABLE"))
36 return HOST_UNREACHABLE
;
38 crash("bad value for host state: '%s'", str
);
41 int soft_hard(const char *str
)
43 if (!strcmp(str
, "HARD"))
46 if (!strcmp(str
, "SOFT"))
48 crash("wtf kind of value is '%s' to determine 'soft' or 'hard' from?", str
);
51 static int print_string(void *data
)
53 const char *str
= data
;
55 printf("%p: %s\n", str
, str
);
60 * prints the objects we consider interesting
62 void print_interesting_objects(void)
64 if (interesting_hosts
) {
65 printf("\nInteresting hosts:\n");
66 hash_walk_data(interesting_hosts
, print_string
);
68 if (interesting_services
) {
69 printf("\nInteresting services:\n");
70 hash_walk_data(interesting_services
, print_string
);
72 if (interesting_hosts
|| interesting_services
)
76 /* marks one object as 'interesting' */
77 int add_interesting_object(const char *orig_str
)
79 char *semi_colon
, *str
;
81 str
= strdup(orig_str
);
82 semi_colon
= strchr(str
, ';');
84 if (!interesting_hosts
)
85 interesting_hosts
= hash_init(512);
86 if (!interesting_hosts
)
87 crash("Failed to initialize hash table for interesting hosts");
88 hash_add(interesting_hosts
, str
, strdup(orig_str
));
90 if (!interesting_services
)
91 interesting_services
= hash_init(512);
92 if (!interesting_services
)
93 crash("Failed to initialize hash table for interesting services");
95 hash_add2(interesting_services
, str
, semi_colon
, strdup(orig_str
));
101 int is_interesting_host(const char *host
)
103 if (interesting_hosts
)
104 return !!hash_find(interesting_hosts
, host
);
109 int is_interesting_service(const char *host
, const char *service
)
111 /* fall back to checking if host is interesting */
112 if (!service
|| !interesting_services
)
113 return is_interesting_host(host
);
115 return !!hash_find2(interesting_services
, host
, service
);
118 struct unhandled_event
{
122 struct unhandled_event
*next
;
125 static struct unhandled_event
*event_list
;
127 * This is a fairly toothless function, since we can encounter
128 * pretty much any kind of message in the logfiles. In order to
129 * make sure we don't miss anything important though, we stash
130 * the messages and print them at the end if we're debugging.
132 void handle_unknown_event(const char *line
)
134 struct unhandled_event
*event
;
138 if (!(event
= malloc(sizeof(*event
))) || !(event
->line
= strdup(line
))) {
139 crash("Failed to allocate memory for unhandled event [%s]\n", line
);
143 event
->line_no
= line_no
;
144 event
->file
= cur_file
->path
;
146 /* add to "top" of list. we'll print in reverse order */
147 event
->next
= event_list
;
151 void print_unhandled_events(void)
153 struct unhandled_event
*event
;
159 printf("\n%u Unhandled events encountered:\n" \
160 "------------------------------", num_unhandled
);
162 for (x
= 1; num_unhandled
> (x
* 10); x
*= 10)
166 for (event
= event_list
; event
; event
= event
->next
) {
167 printf("%s:%d:\n%s\n----\n", event
->file
, event
->line_no
, event
->line
);
171 int vectorize_string(char *str
, int nvecs
)
177 for (p
= str
; *p
&& i
< nvecs
; p
++) {
188 get_string_code(struct string_code
*codes
, const char *str
, uint len
)
192 for (i
= 0; codes
[i
].str
; i
++)
193 if (codes
[i
].len
== len
&& !memcmp(str
, codes
[i
].str
, len
))
199 int is_interesting(const char *ptr
)
201 if (!prefixcmp(ptr
, "Auto-save of retention data"))
203 if (!prefixcmp(ptr
, "Event broker module"))
205 if (!prefixcmp(ptr
, "You do not have permission"))
207 if (!prefixcmp(ptr
, "Local time is"))
213 int is_start_event(const char *ptr
)
215 if (!prefixcmp(ptr
, "Finished daemonizing..."))
217 if (!prefixcmp(ptr
, "Caught SIGHUP"))
219 if (strstr(ptr
, "starting..."))
225 int is_stop_event(const char *ptr
)
227 if (!prefixcmp(ptr
, "PROGRAM_RESTART"))
229 if (!prefixcmp(ptr
, "Caught SIGTERM"))
231 if (!prefixcmp(ptr
, "Successfully shutdown..."))
233 if (!prefixcmp(ptr
, "Bailing out"))
235 if (!prefixcmp(ptr
, "Lockfile"))
237 if (strstr(ptr
, "shutting down..."))
243 int strtotimet(const char *str
, time_t *val
)
247 *val
= strtoul(str
, &endp
, 10);
249 warn("strtotimet(): %s is not a valid time_t\n", str
);
256 /*** general utility functions ***/
257 void __attribute__((__noreturn__
)) crash(const char *fmt
, ...)
262 vfprintf(stderr
, fmt
, ap
);
267 fprintf(stderr
, "crash() called when parsing line %u in %s\n",
268 line_no
, cur_file
->path
);
274 void pdebug(int lvl
, const char *fmt
, ...)
278 if (debug_level
< lvl
)
284 if (fmt
[strlen(fmt
) - 1] != '\n')
288 void warn(const char *fmt
, ...)
307 * Returns an increasing numeric value for a nagios logfile
308 * For a file with a name such as:
309 * nagios-12-01-2002-00.log
314 uint
path_cmp_number(char *path
)
319 unsigned long part
[NUM_PARTS
];
321 dash
= strrchr(path
, '/');
328 * we special-case nagios.log as always being the
329 * last file to be parsed. It has to be, since it's
330 * the currently active logfile
332 if (!strcmp(dash
, "nagios.log"))
333 return 1 << ((8 * sizeof(ret
)) - 1);
336 if (len
< 18 || strcmp(&dash
[len
- 4], ".log"))
339 for (i
= 0; i
< NUM_PARTS
; i
++) {
342 dash
= strchr(dash
, '-');
347 part
[i
] = strtoul(dash
, &endp
, 10);
348 if (!part
[i
] && dash
== endp
)
354 if (part
[0] < 1 || part
[0] > 12)
356 if (part
[1] < 1 || part
[1] > 31)
360 ret
= part
[2] * 1000000;
361 ret
+= part
[0] * 10000;
362 ret
+= part
[1] * 100;
368 #define min(a, b) ((a) < (b) ? (a) : (b))
369 void first_log_time(struct naglog_file
*nf
)
375 if (!(fd
= open(nf
->path
, O_RDONLY
)))
376 crash("Failed to open %s: %s", nf
->path
, strerror(errno
));
379 * since we're looking at every file in here anyway,
380 * we also determine the size of them so we can do an
381 * arena allocation large enough to fit the largest
382 * file + an added newline later
384 if (fstat(fd
, &st
) < 0)
385 crash("Failed to stat %s: %s", nf
->path
, strerror(errno
));
387 nf
->size
= st
.st_size
;
389 if (read(fd
, buf
, sizeof(buf
)) < min(sizeof(buf
), st
.st_size
))
390 crash("Incomplete read of %s", nf
->path
);
392 buf
[sizeof(buf
) - 1] = 0;
393 /* skip empty lines at top of file */
394 while (i
< sizeof(buf
) - 12 && (buf
[i
] == '\n' || buf
[i
] == '\r'))
397 if (strtotimet(buf
+ i
+ 1, &nf
->first
))
398 crash("'%s' has no timestamp for us to parse", buf
);
400 nf
->cmp
= path_cmp_number(nf
->path
);
404 static void filesort_mismatch(const struct naglog_file
*a
, const struct naglog_file
*b
)
406 printf("filesort mismatch:\n");
407 printf(" %s:\n cmp: %d\n first: %lu\n", a
->path
, a
->cmp
, a
->first
);
408 printf(" %s:\n cmp: %d\n first: %lu\n", b
->path
, b
->cmp
, b
->first
);
409 crash("%s and %s have same 'first' and 'cmp'? Bizarre...", a
->path
, b
->path
);
413 * sort function for nagios logfiles. Sorts based on
414 * first logged timestamp and then on filename, ascendingly
416 int nfile_cmp(const void *p1
, const void *p2
)
418 const struct naglog_file
*a
= p1
;
419 const struct naglog_file
*b
= p2
;
421 if (a
->first
> b
->first
)
423 if (b
->first
> a
->first
)
431 filesort_mismatch(a
, b
);
435 /* same as above, but sorts in reverse order */
436 int nfile_rev_cmp(const void *p1
, const void *p2
)
438 const struct naglog_file
*a
= p1
;
439 const struct naglog_file
*b
= p2
;
441 if (a
->first
< b
->first
)
443 if (b
->first
< a
->first
)
451 filesort_mismatch(a
, b
);
457 # define PATH_MAX 4096
459 /* recurse into a log-archive path and find all logfiles there */
460 static int add_naglog_directory(const char *dir
)
465 uint dlen
= strlen(dir
);
469 crash("Failed to opendir(%s): %s\n", dir
, strerror(errno
));
471 memcpy(path
, dir
, dlen
);
473 while ((de
= readdir(dirp
))) {
476 if (prefixcmp(de
->d_name
, "nagios"))
478 name_len
= strlen(de
->d_name
);
479 if (strcmp(&de
->d_name
[name_len
- 4], ".log"))
482 /* build some sort of path to the file */
483 memcpy(&path
[dlen
], de
->d_name
, name_len
);
484 path
[dlen
+ name_len
] = 0;
485 add_naglog_path(path
);
491 /* Handles both files and directories */
492 int add_naglog_path(char *path
)
497 /* make sure we never add duplicate files */
498 for (i
= 0; i
< num_nfile
; i
++) {
499 if (!strcmp(nfile
[i
].path
, path
))
503 if (stat(path
, &st
) < 0) {
504 crash("Failed to stat '%s': %s", path
, strerror(errno
));
506 if (S_ISDIR(st
.st_mode
)) {
507 return add_naglog_directory(path
);
510 if (num_nfile
>= nfile_alloc
- 1) {
512 nfile
= realloc(nfile
, nfile_alloc
* sizeof(*nfile
));
515 nfile
[num_nfile
].path
= strdup(path
);
516 first_log_time(&nfile
[num_nfile
]);