import: Add support for passive host and service checks
[nagios-reports-module.git] / logutils.c
blob55f9fc6480183c68f8fdae5e83143e543aa4b9d5
1 #include "logutils.h"
3 char **strv = NULL;
4 int num_nfile = 0;
5 int debug_level = 0;
6 struct naglog_file *cur_file; /* the file we're currently importing */
7 uint line_no = 0;
8 uint num_unhandled = 0;
9 uint warnings = 0;
10 static hash_table *interesting_hosts, *interesting_services;
13 int parse_service_state(const char *str)
15 if (!strcmp(str, "OK"))
16 return SERVICE_OK;
17 if (!strcmp(str, "WARNING"))
18 return SERVICE_WARNING;
19 if (!strcmp(str, "UNKNOWN"))
20 return SERVICE_UNKNOWN;
21 if (!strcmp(str, "CRITICAL"))
22 return SERVICE_CRITICAL;
24 crash("bad value for service state: '%s'", str);
27 int parse_host_state(const char *str)
29 if (!strcmp(str, "UP"))
30 return HOST_UP;
31 if (!strcmp(str, "DOWN"))
32 return HOST_DOWN;
33 if (!strcmp(str, "UNREACHABLE"))
34 return HOST_UNREACHABLE;
36 crash("bad value for host state: '%s'", str);
39 int soft_hard(const char *str)
41 if (!strcmp(str, "HARD"))
42 return HARD_STATE;
44 if (!strcmp(str, "SOFT"))
45 return SOFT_STATE;
46 crash("wtf kind of value is '%s' to determine 'soft' or 'hard' from?", str);
49 static int print_string(void *data)
51 const char *str = data;
53 printf("%p: %s\n", str, str);
54 return 0;
58 * prints the objects we consider interesting
60 void print_interesting_objects(void)
62 if (interesting_hosts) {
63 printf("\nInteresting hosts:\n");
64 hash_walk_data(interesting_hosts, print_string);
66 if (interesting_services) {
67 printf("\nInteresting services:\n");
68 hash_walk_data(interesting_services, print_string);
70 if (interesting_hosts || interesting_services)
71 putchar('\n');
74 /* marks one object as 'interesting' */
75 int add_interesting_object(const char *orig_str)
77 char *semi_colon, *str;
79 str = strdup(orig_str);
80 semi_colon = strchr(str, ';');
81 if (!semi_colon) {
82 if (!interesting_hosts)
83 interesting_hosts = hash_init(512);
84 if (!interesting_hosts)
85 crash("Failed to initialize hash table for interesting hosts");
86 hash_add(interesting_hosts, str, strdup(orig_str));
87 } else {
88 if (!interesting_services)
89 interesting_services = hash_init(512);
90 if (!interesting_services)
91 crash("Failed to initialize hash table for interesting services");
92 *semi_colon++ = 0;
93 hash_add2(interesting_services, str, semi_colon, strdup(orig_str));
96 return 0;
99 int is_interesting_host(const char *host)
101 if (interesting_hosts)
102 return !!hash_find(interesting_hosts, host);
104 return 1;
107 int is_interesting_service(const char *host, const char *service)
109 /* fall back to checking if host is interesting */
110 if (!service || !interesting_services)
111 return is_interesting_host(host);
113 return !!hash_find2(interesting_services, host, service);
116 struct unhandled_event {
117 char *file;
118 const char *line;
119 unsigned line_no;
120 struct unhandled_event *next;
123 static struct unhandled_event *event_list;
125 * This is a fairly toothless function, since we can encounter
126 * pretty much any kind of message in the logfiles. In order to
127 * make sure we don't miss anything important though, we stash
128 * the messages and print them at the end if we're debugging.
130 void handle_unknown_event(const char *line)
132 struct unhandled_event *event;
134 num_unhandled++;
136 if (!(event = malloc(sizeof(*event))) || !(event->line = strdup(line))) {
137 crash("Failed to allocate memory for unhandled event [%s]\n", line);
138 return;
141 event->line_no = line_no;
142 event->file = cur_file->path;
144 /* add to "top" of list. we'll print in reverse order */
145 event->next = event_list;
146 event_list = event;
149 void print_unhandled_events(void)
151 struct unhandled_event *event;
152 int x = 1;
154 if (!num_unhandled)
155 return;
157 printf("\n%u Unhandled events encountered:\n" \
158 "------------------------------", num_unhandled);
160 for (x = 1; num_unhandled > (x * 10); x *= 10)
161 putchar('-');
163 putchar('\n');
164 for (event = event_list; event; event = event->next) {
165 printf("%s:%d:\n%s\n----\n", event->file, event->line_no, event->line);
169 int vectorize_string(char *str, int nvecs)
171 char *p;
172 int i = 0;
174 strv[i++] = str;
175 for (p = str; *p && i < nvecs; p++) {
176 if (*p == ';') {
177 *p = 0;
178 strv[i++] = ++p;
182 return i;
185 struct string_code *
186 get_string_code(struct string_code *codes, const char *str, uint len)
188 int i;
190 for (i = 0; codes[i].str; i++)
191 if (codes[i].len == len && !memcmp(str, codes[i].str, len))
192 return &codes[i];
194 return NULL;
197 int is_interesting(const char *ptr)
199 if (!prefixcmp(ptr, "Auto-save of retention data"))
200 return 0;
201 if (!prefixcmp(ptr, "Event broker module"))
202 return 0;
203 if (!prefixcmp(ptr, "You do not have permission"))
204 return 0;
205 if (!prefixcmp(ptr, "Local time is"))
206 return 0;
208 return 1;
211 int is_start_event(const char *ptr)
213 if (!prefixcmp(ptr, "Finished daemonizing..."))
214 return 1;
215 if (!prefixcmp(ptr, "Caught SIGHUP"))
216 return 1;
217 if (strstr(ptr, "starting..."))
218 return 1;
220 return 0;
223 int is_stop_event(const char *ptr)
225 if (!prefixcmp(ptr, "PROGRAM_RESTART"))
226 return 1;
227 if (!prefixcmp(ptr, "Caught SIGTERM"))
228 return 1;
229 if (!prefixcmp(ptr, "Successfully shutdown..."))
230 return 1;
231 if (!prefixcmp(ptr, "Bailing out"))
232 return 1;
233 if (!prefixcmp(ptr, "Lockfile"))
234 return 1;
235 if (strstr(ptr, "shutting down..."))
236 return 1;
238 return 0;
241 int strtotimet(const char *str, time_t *val)
243 char *endp;
245 *val = strtoul(str, &endp, 10);
246 if (endp == str) {
247 warn("strtotimet(): %s is not a valid time_t\n", str);
248 return -1;
251 return 0;
254 /*** general utility functions ***/
255 void __attribute__((__noreturn__)) crash(const char *fmt, ...)
257 va_list ap;
259 va_start(ap, fmt);
260 vfprintf(stderr, fmt, ap);
261 va_end(ap);
262 fputc('\n', stderr);
264 if (cur_file) {
265 fprintf(stderr, "crash() called when parsing line %u in %s\n",
266 line_no, cur_file->path);
269 exit(1);
272 void pdebug(int lvl, const char *fmt, ...)
274 va_list ap;
276 if (debug_level < lvl)
277 return;
279 va_start(ap, fmt);
280 vprintf(fmt, ap);
281 va_end(ap);
282 if (fmt[strlen(fmt) - 1] != '\n')
283 putchar('\n');
286 void warn(const char *fmt, ...)
288 va_list ap;
290 warnings++;
292 if (!debug_level)
293 return;
295 printf("WARNING: ");
296 va_start(ap, fmt);
297 vprintf(fmt, ap);
298 va_end(ap);
299 putchar('\n');
305 * Returns an increasing numeric value for a nagios logfile
306 * For a file with a name such as:
307 * nagios-12-01-2002-00.log
308 * it will return
309 * 2002120100
311 #define NUM_PARTS 4
312 uint path_cmp_number(char *path)
314 uint ret, len;
315 char *dash = NULL;
316 int i;
317 unsigned long part[NUM_PARTS];
319 dash = strrchr(path, '/');
320 if (!dash)
321 dash = path;
322 else
323 dash++;
326 * we special-case nagios.log as always being the
327 * last file to be parsed. It has to be, since it's
328 * the currently active logfile
330 if (!strcmp(dash, "nagios.log"))
331 return 1 << ((8 * sizeof(ret)) - 1);
333 len = strlen(dash);
334 if (len < 18 || strcmp(&dash[len - 4], ".log"))
335 return 0;
337 for (i = 0; i < NUM_PARTS; i++) {
338 char *endp;
340 dash = strchr(dash, '-');
341 if (!dash)
342 crash("dash is not");
344 dash++;
345 part[i] = strtoul(dash, &endp, 10);
346 if (!part[i] && dash == endp)
347 return 0;
348 if (!endp)
349 return 0;
350 dash = endp;
352 if (part[0] < 1 || part[0] > 12)
353 return 0;
354 if (part[1] < 1 || part[1] > 31)
355 return 0;
356 if (!part[2])
357 return 0;
358 ret = part[2] * 1000000;
359 ret += part[0] * 10000;
360 ret += part[1] * 100;
361 ret += part[3];
363 return ret;
366 #define min(a, b) ((a) < (b) ? (a) : (b))
367 void first_log_time(struct naglog_file *nf)
369 int fd, i = 0;
370 char buf[1024];
371 struct stat st;
373 if (!(fd = open(nf->path, O_RDONLY)))
374 crash("Failed to open %s: %s", nf->path, strerror(errno));
377 * since we're looking at every file in here anyway,
378 * we also determine the size of them so we can do an
379 * arena allocation large enough to fit the largest
380 * file + an added newline later
382 if (fstat(fd, &st) < 0)
383 crash("Failed to stat %s: %s", nf->path, strerror(errno));
385 nf->size = st.st_size;
387 if (read(fd, buf, sizeof(buf)) < min(sizeof(buf), st.st_size))
388 crash("Incomplete read of %s", nf->path);
390 buf[sizeof(buf) - 1] = 0;
391 /* skip empty lines at top of file */
392 while (i < sizeof(buf) - 12 && (buf[i] == '\n' || buf[i] == '\r'))
393 i++;
395 if (strtotimet(buf + i + 1, &nf->first))
396 crash("'%s' has no timestamp for us to parse", buf);
398 nf->cmp = path_cmp_number(nf->path);
399 close(fd);
402 static void filesort_mismatch(const struct naglog_file *a, const struct naglog_file *b)
404 printf("filesort mismatch:\n");
405 printf(" %s:\n cmp: %d\n first: %lu\n", a->path, a->cmp, a->first);
406 printf(" %s:\n cmp: %d\n first: %lu\n", b->path, b->cmp, b->first);
407 crash("%s and %s have same 'first' and 'cmp'? Bizarre...", a->path, b->path);
411 * sort function for nagios logfiles. Sorts based on
412 * first logged timestamp and then on filename, ascendingly
414 int nfile_cmp(const void *p1, const void *p2)
416 const struct naglog_file *a = p1;
417 const struct naglog_file *b = p2;
419 if (a->first > b->first)
420 return 1;
421 if (b->first > a->first)
422 return -1;
424 if (a->cmp > b->cmp)
425 return 1;
426 if (b->cmp > a->cmp)
427 return -1;
429 filesort_mismatch(a, b);
430 return 0;
433 /* same as above, but sorts in reverse order */
434 int nfile_rev_cmp(const void *p1, const void *p2)
436 const struct naglog_file *a = p1;
437 const struct naglog_file *b = p2;
439 if (a->first < b->first)
440 return 1;
441 if (b->first < a->first)
442 return -1;
444 if (a->cmp < b->cmp)
445 return 1;
446 if (b->cmp < a->cmp)
447 return -1;
449 filesort_mismatch(a, b);
450 return 0;