1 /* (C) 2006-2010 by folkert@vanheusden.com GPLv2 applies */
2 
3 #include <stdio.h>
4 #include <time.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stddef.h>
12 #include <errno.h>
13 #include <sys/select.h>
14 #include <signal.h>
15 #include <sys/ioctl.h>
16 #include <ctype.h>
17 
18 extern "C" {
19 #include "error.h"
20 }
21 #include "utils.h"
22 #include "br.h"
23 #include "pl.h"
24 
25 static struct v2_0_config v2_0_config_elements[] = {
26 	{"acknowledgement_type",	STATS_OFFSET(acknowledgement_type),	VARTYPE_INT},
27 	{"active_checks_enabled",	STATS_OFFSET(active_checks_enabled),	VARTYPE_INT},
28 	{"author",			STATS_OFFSET(author),			VARTYPE_PCHAR},
29 	{"check_command",		STATS_OFFSET(check_command),		VARTYPE_PCHAR},
30 	{"check_execution_time",	STATS_OFFSET(check_execution_time),	VARTYPE_DOUBLE},
31 	{"check_interval",		STATS_OFFSET(check_interval),		VARTYPE_DOUBLE},
32 	{"check_latency",		STATS_OFFSET(check_latency),		VARTYPE_DOUBLE},
33 	{"check_options",		STATS_OFFSET(check_options),		VARTYPE_INT},
34 	{"check_period",		STATS_OFFSET(check_period),		VARTYPE_PCHAR},
35 	{"check_type",			STATS_OFFSET(check_type),		VARTYPE_INT},
36 	{"comment",			STATS_OFFSET(comment),			VARTYPE_PCHAR},
37 	{"comment_data",		STATS_OFFSET(comment_data),		VARTYPE_PCHAR},
38 	{"comment_id",			STATS_OFFSET(comment_id),		VARTYPE_INT},
39 	{"current_attempt",		STATS_OFFSET(current_attempt),		VARTYPE_INT},
40 	{"current_event_id",		STATS_OFFSET(current_event_id),		VARTYPE_INT},
41 	{"current_notification_id",	STATS_OFFSET(current_notification_id),	VARTYPE_INT},
42 	{"current_notification_number",	STATS_OFFSET(current_notification_number),	VARTYPE_DOUBLE},
43 	{"current_problem_id",		STATS_OFFSET(current_problem_id),	VARTYPE_INT},
44 	{"current_state",		STATS_OFFSET(current_state),		VARTYPE_INT},
45 	{"downtime_id",			STATS_OFFSET(downtime_id),		VARTYPE_INT},
46 	{"duration",			STATS_OFFSET(duration),			VARTYPE_INT},
47 	{"end_time",			STATS_OFFSET(end_time),			VARTYPE_TIMET},
48 	{"entry_time",			STATS_OFFSET(entry_time),		VARTYPE_TIMET},
49 	{"entry_type",			STATS_OFFSET(entry_type),		VARTYPE_INT},
50 	{"event_handler",		STATS_OFFSET(event_handler),		VARTYPE_INT},
51 	{"event_handler_enabled",	STATS_OFFSET(event_handler_enabled),	VARTYPE_INT},
52 	{"expire_time",			STATS_OFFSET(expire_time),		VARTYPE_TIMET},
53 	{"expires",			STATS_OFFSET(expires),			VARTYPE_INT},
54 	{"failure_prediction_enabled",	STATS_OFFSET(failure_prediction_enabled),	VARTYPE_INT},
55 	{"fixed",			STATS_OFFSET(fixed),			VARTYPE_INT},
56 	{"flap_detection_enabled",	STATS_OFFSET(flap_detection_enabled),	VARTYPE_INT},
57 	{"has_been_checked",		STATS_OFFSET(has_been_checked),		VARTYPE_INT},
58 	{"host_name",			STATS_OFFSET(host_name),		VARTYPE_PCHAR},
59 	{"host_notification_period",	STATS_OFFSET(host_notification_period),	VARTYPE_PCHAR},
60 	{"is_flapping",			STATS_OFFSET(is_flapping),		VARTYPE_INT},
61 	{"last_check",			STATS_OFFSET(last_check),		VARTYPE_TIMET},
62 	{"last_event_id",		STATS_OFFSET(last_event_id),		VARTYPE_INT},
63 	{"last_hard_state",		STATS_OFFSET(last_hard_state),		VARTYPE_INT},
64 	{"last_hard_state_change",	STATS_OFFSET(last_hard_state_change),	VARTYPE_INT},
65 	{"last_notification",		STATS_OFFSET(last_notification),	VARTYPE_INT},
66 	{"last_problem_id",		STATS_OFFSET(last_problem_id),		VARTYPE_INT},
67 	{"last_state_change",		STATS_OFFSET(last_state_change),	VARTYPE_TIMET},
68 	{"last_time_critical",		STATS_OFFSET(last_time_critical),	VARTYPE_INT},
69 	{"last_time_down",		STATS_OFFSET(last_time_down),		VARTYPE_INT},
70 	{"last_time_ok",		STATS_OFFSET(last_time_ok),		VARTYPE_INT},
71 	{"last_time_unknown",		STATS_OFFSET(last_time_unknown),	VARTYPE_INT},
72 	{"last_time_unreachable",	STATS_OFFSET(last_time_unreachable),	VARTYPE_INT},
73 	{"last_time_up",		STATS_OFFSET(last_time_up),		VARTYPE_INT},
74 	{"last_time_warning",		STATS_OFFSET(last_time_warning),	VARTYPE_INT},
75 	{"last_update",			STATS_OFFSET(last_update),		VARTYPE_TIMET},
76 	{"long_plugin_output",		STATS_OFFSET(long_plugin_output),	VARTYPE_PCHAR},
77 	{"max_attempts",		STATS_OFFSET(max_attempts),		VARTYPE_INT},
78 	{"modified_attributes",		STATS_OFFSET(modified_attributes),	VARTYPE_INT},
79 	{"next_check",			STATS_OFFSET(next_check),		VARTYPE_TIMET},
80 	{"next_comment_id",		STATS_OFFSET(next_comment_id),		VARTYPE_INT},
81 	{"next_notification",		STATS_OFFSET(next_notification),	VARTYPE_INT},
82 	{"no_more_notifications",	STATS_OFFSET(no_more_notifications),	VARTYPE_INT},
83 	{"notification_period",		STATS_OFFSET(notification_period),	VARTYPE_PCHAR},
84 	{"notifications_enabled",	STATS_OFFSET(notifications_enabled),	VARTYPE_INT},
85 	{"obsess_over_host",		STATS_OFFSET(obsess_over_host),		VARTYPE_INT},
86 	{"obsess_over_service",		STATS_OFFSET(obsess_over_service),	VARTYPE_INT},
87 	{"passive_checks_enabled",	STATS_OFFSET(passive_checks_enabled),	VARTYPE_INT},
88 	{"percent_state_change",	STATS_OFFSET(percent_state_change),	VARTYPE_DOUBLE},
89 	{"performance_data",		STATS_OFFSET(performance_data),		VARTYPE_PCHAR},
90 	{"persistent",			STATS_OFFSET(persistent),		VARTYPE_INT},
91 	{"plugin_output",		STATS_OFFSET(plugin_output),		VARTYPE_PCHAR},
92 	{"problem_has_been_acknowledged",	STATS_OFFSET(problem_has_been_acknowledged),	VARTYPE_INT},
93 	{"process_performance_data",	STATS_OFFSET(process_performance_data),	VARTYPE_INT},
94 	{"retry_interval",		STATS_OFFSET(retry_interval),		VARTYPE_DOUBLE},
95 	{"scheduled_downtime_depth",	STATS_OFFSET(scheduled_downtime_depth),	VARTYPE_DOUBLE},
96 	{"service_description",		STATS_OFFSET(service_description),	VARTYPE_PCHAR},
97 	{"should_be_scheduled",		STATS_OFFSET(should_be_scheduled),	VARTYPE_INT},
98 	{"source",			STATS_OFFSET(source),			VARTYPE_INT},
99 	{"start_time",			STATS_OFFSET(start_time),		VARTYPE_TIMET},
100 	{"state_type",			STATS_OFFSET(state_type),		VARTYPE_INT},
101 	{"triggered_by",		STATS_OFFSET(triggered_by),		VARTYPE_INT},
102 	{"type",			STATS_OFFSET(type),			VARTYPE_INT}
103 };
104 
105 /*
106    service {
107    host_name=ap
108    service_description=HTTP
109    modified_attributes=0
110    check_command=check_tcp!80
111    event_handler=
112    has_been_checked=1
113    should_be_scheduled=1
114    check_execution_time=0.009
115    check_latency=0.712
116    current_state=0
117    last_hard_state=0
118    current_attempt=1
119    max_attempts=3
120    state_type=1
121    last_state_change=1128634047
122    last_hard_state_change=1128633828
123    last_time_ok=1129101510
124    last_time_warning=0
125    last_time_unknown=1128633828
126    last_time_critical=1126954624
127    plugin_output=TCP OK - 0.001 second response time on port 80
128    performance_data=time=0.001121s;0.000000;0.000000;0.000000;10.000000
129    last_check=1129101510
130    next_check=1129101630
131    check_type=0
132    current_notification_number=0
133    last_notification=0
134    next_notification=0
135    no_more_notifications=0
136    notifications_enabled=1
137    active_checks_enabled=1
138    passive_checks_enabled=1
139    event_handler_enabled=1
140    problem_has_been_acknowledged=0
141    acknowledgement_type=0
142    flap_detection_enabled=1
143    failure_prediction_enabled=1
144    process_performance_data=1
145    obsess_over_service=1
146    last_update=1129101556
147    is_flapping=0
148    percent_state_change=0.00
149    scheduled_downtime_depth=0
150    }
151 
152    host {
153    host_name=ap
154    modified_attributes=0
155    check_command=check-host-alive
156    event_handler=
157    has_been_checked=1
158    should_be_scheduled=0
159    check_execution_time=0.012
160    check_latency=0.000
161    current_state=0
162    last_hard_state=0
163    check_type=0
164    plugin_output=PING OK - Packet loss = 0%, RTA = 1.54 ms
165    performance_data=
166    last_check=1128863442
167    next_check=0
168    current_attempt=1
169    max_attempts=10
170    state_type=1
171    last_state_change=1128634057
172    last_hard_state_change=1128634057
173    last_time_up=1128863442
174    last_time_down=1128633868
175    last_time_unreachable=0
176    last_notification=1128634057
177 next_notification=0
178 no_more_notifications=0
179 current_notification_number=0
180 notifications_enabled=1
181 problem_has_been_acknowledged=0
182 acknowledgement_type=0
183 active_checks_enabled=1
184 passive_checks_enabled=1
185 event_handler_enabled=1
186 flap_detection_enabled=1
187 failure_prediction_enabled=1
188 process_performance_data=1
189 obsess_over_host=1
190 last_update=1129101556
191 is_flapping=0
192 percent_state_change=0.00
193 scheduled_downtime_depth=0
194 }
195 */
196 
v2_0_find_entry_type(char * field_name)197 int v2_0_find_entry_type(char *field_name)
198 {
199 	int left = 0;
200 	int right = (sizeof(v2_0_config_elements) / sizeof(struct v2_0_config)) - 1;
201 
202 	while(left <= right)
203 	{
204 		int mid = (left + right) / 2;
205 		int compare = strcmp(field_name, v2_0_config_elements[mid].str);
206 
207 		if (compare > 0)
208 			left = mid + 1;
209 		else if (compare < 0)
210 			right = mid - 1;
211 		else
212 			return mid;
213 	}
214 
215 	return -1;
216 }
217 
parse_2_0_statuslog(int fd,struct stats ** pstats,int * n_stats)218 void parse_2_0_statuslog(int fd, struct stats **pstats, int *n_stats)
219 {
220 	int n_alloc = 0;
221 	int type = TYPE_IGNORE;
222 
223 	/* start up buffered reader */
224 	buffered_reader bf(fd);
225 
226 	*pstats = NULL;
227 	*n_stats = 0;
228 
229 	for(;;)
230 	{
231 		char *line = bf.read_line();
232 		if (!line)
233 			break;
234 
235 		if (strchr(line, '{'))
236 		{
237 			/* init */
238 			type = TYPE_IGNORE;
239 
240 			if (*n_stats == n_alloc)
241 			{
242 				if (n_alloc)
243 					n_alloc *= 2;
244 				else
245 					n_alloc = 128;
246 
247 				*pstats = (struct stats *)myrealloc(*pstats, n_alloc * sizeof(struct stats), "stats array");
248 				if (!*pstats)
249 					error_exit("Error allocating memory");
250 
251 				memset(&(*pstats)[*n_stats], 0x00, sizeof(struct stats) * (n_alloc - *n_stats));
252 			}
253 			else
254 			{
255 				memset(&(*pstats)[*n_stats], 0x00, sizeof(struct stats));
256 			}
257 
258 
259 			if (strncmp(line, "host", 4) == 0)
260 			{
261 				type = TYPE_HOST;
262 			}
263 			else if (strncmp(line, "service", 7) == 0)
264 			{
265 				type = TYPE_SERVICE;
266 			}
267 			else
268 			{
269 				type = TYPE_IGNORE;
270 			}
271 		}
272 		else if (type != TYPE_IGNORE)
273 		{
274 			char *cmd = line, *is;
275 			while(*cmd == ' ' || *cmd == '\t') cmd++;
276 
277 			is = strchr(cmd, '=');
278 			if (is == NULL)
279 			{
280 				if (strchr(cmd, '}') != NULL)	/* end of definition, store in array */
281 				{
282 					if (type == TYPE_HOST && (*pstats)[*n_stats].current_state == 1) /* HOSTS: 0=ok, 1=down, 2=unreachable */
283 						(*pstats)[*n_stats].current_state = 2;
284 					(*pstats)[*n_stats].type = type;
285 					(*n_stats)++;
286 				}
287 			}
288 			else
289 			{
290 				int index;
291 				char *record = (char *)(&(*pstats)[*n_stats]);
292 				char *par = is + 1;
293 				*is = 0x00;
294 
295 				if ((index = v2_0_find_entry_type(cmd)) != -1)
296 				{
297 					switch(v2_0_config_elements[index].type)
298 					{
299 						case VARTYPE_PCHAR:
300 							*((char **)(&record[v2_0_config_elements[index].offset])) = mystrdup(par);
301 							break;
302 						case VARTYPE_INT:
303 							*((int *)(&record[v2_0_config_elements[index].offset])) = atoi(par);
304 							break;
305 						case VARTYPE_TIMET:
306 							*((time_t *)(&record[v2_0_config_elements[index].offset])) = atol(par);
307 							break;
308 						case VARTYPE_DOUBLE:
309 							*((double *)(&record[v2_0_config_elements[index].offset])) = atof(par);
310 							break;
311 					}
312 				}
313 				else
314 				{
315 					printf("{%s} ???\n", cmd);
316 				}
317 			}
318 		}
319 
320 		/* this one does not use myfree() as the buffered reader does not
321 		 * use mymalloc() and friends
322 		 */
323 		free(line);
324 	}
325 }
326 
split_1_0_line(char * line,char ** out)327 int split_1_0_line(char *line, char **out)
328 {
329 	int out_index = 0;
330 
331 	memset(out, 0x00, sizeof(char *) * V1_0_MAX_ELEMENTS);
332 
333 	for(;out_index < V1_0_MAX_ELEMENTS;)
334 	{
335 		out[out_index++] = line;
336 
337 		line = strchr(line, ';');
338 
339 		if (!line)
340 			break;
341 
342 		*line = 0x00; /* replace ';' with 0x00 */
343 		line++;
344 	}
345 
346 	return out_index;
347 }
348 
parse_1_0_statuslog(int fd,struct stats ** pstats,int * n_stats)349 void parse_1_0_statuslog(int fd, struct stats **pstats, int *n_stats)
350 {
351 	/* start up buffered reader */
352 	buffered_reader bf(fd);
353 
354 	*pstats = NULL;
355 	*n_stats = 0;
356 
357 	for(;;)
358 	{
359 		int type = TYPE_IGNORE;
360 		char *host_name = NULL;
361 		int current_state = -1;
362 		char *service_description = NULL;
363 		char *plugin_output = NULL;
364 		time_t last_state_change = 0;
365 		char active_checks_enabled = 0;
366 		char passive_checks_enabled = 0;
367 		char notifications_enabled = 0;
368 		char problem_has_been_acknowledged = 0;
369 		int scheduled_downtime_depth = 0;
370 		char state_type = 0;
371 		char last_hard_state = 0;
372 		int modified_attributes = 0;
373 		int event_handler = 0;
374 		int has_been_checked = 0;
375 		int should_be_scheduled = 0;
376 		int current_attempt = 0;
377 		int max_attempts = 0;
378 		int last_hard_state_change = 0;
379 		int last_time_ok = 0;
380 		int last_time_warning = 0;
381 		int last_time_unknown = 0;
382 		int last_time_critical = 0;
383 		time_t last_check = 0;
384 		time_t next_check = 0;
385 		int check_type = 0;
386 		int current_notification_number = 0;
387 		int last_notification = 0;
388 		int next_notification = 0;
389 		int no_more_notifications = 0;
390 		int event_handler_enabled = 0;
391 		int acknowledgement_type = 0;
392 		int flap_detection_enabled = 0;
393 		int failure_prediction_enabled = 0;
394 		int process_performance_data = 0;
395 		int obsess_over_service = 0;
396 		time_t last_update = 0;
397 		int is_flapping = 0;
398 		double percent_state_change = 0;
399 		double check_execution_time = 0;
400 		double check_latency = 0;
401 		char * performance_data = NULL;
402 		char * check_command = NULL;
403 		int last_time_up = 0;
404 		int last_time_down = 0;
405 		int last_time_unreachable = 0;
406 
407 		char *dummy;
408 		char *elements[V1_0_MAX_ELEMENTS];
409 		int n_elem;
410 		char *line = bf.read_line();
411 		if (!line)
412 			break;
413 
414 		if (line[0] == '#')
415 			goto skip_line;
416 
417 		n_elem = split_1_0_line(line, elements);
418 
419 		*pstats = (struct stats *)myrealloc(*pstats, ((*n_stats) + 1) * sizeof(struct stats), "stats array");
420 		if (!*pstats)
421 			error_exit("Error allocating memory");
422 
423 		memset(&(*pstats)[*n_stats], 0x00, sizeof(struct stats));
424 
425 		/*
426 		   [Time of last update] HOST;
427 		   Host Name (string);
428 		   Status (OK/DOWN/UNREACHABLE);
429 		   Last Check Time (long time);
430 		   Last State Change (long time);
431 		   Acknowledged (0/1);
432 		   Time Up (long time);
433 		   Time Down (long time);
434 		   Time Unreachable (long time);
435 		   Last Notification Time (long time);
436 		   Current Notification Number (#);
437 		   Notifications Enabled (0/1);
438 		   Event Handlers Enabled (0/1);
439 		   Checks Enabled (0/1);
440 		   Flap Detection Enabled (0/1);
441 		   Host is Flapping (0/1);
442 		   Percent State Change (###.##);
443 		   Scheduled downtime depth (#);
444 		   Failure Prediction Enabled (0/1);
445 		   Process Performance Data(0/1);
446 		   Plugin Output (string)
447 		   */
448 
449 		/*
450 		   [Time of last update] SERVICE;
451 		   Host Name (string);
452 		   Service Description (string);
453 		   Status (OK/WARNING/CRITICAL/UNKNOWN);
454 		   Retry number (#/#);
455 		   State Type (SOFT/HARD);
456 		   Last check time (long time);
457 		   Next check time (long time);
458 		   Check type (ACTIVE/PASSIVE);
459 		   Checks enabled (0/1);
460 		   Accept Passive Checks (0/1);
461 		   Event Handlers Enabled (0/1);
462 		   Last state change (long time);
463 		   Problem acknowledged (0/1);
464 		   Last Hard State (OK/WARNING/CRITICAL/UNKNOWN);
465 		   Time OK (long time);
466 		   Time Unknown (long time);
467 		   Time Warning (long time);
468 		   Time Critical (long time);
469 		   Last Notification Time (long time);
470 		   Current Notification Number (#);
471 		   Notifications Enabled (0/1);
472 		   Latency (#);
473 		   Execution Time (#);
474 		   Flap Detection Enabled (0/1);
475 		   Service is Flapping (0/1);
476 		   Percent State Change (###.##);
477 		   Scheduled Downtime Depth (#);
478 		   Failure Prediction Enabled (0/1);
479 		   Process Performance Date (0/1);
480 		   Obsess Over Service (0/1);
481 		   Plugin Output (string)
482 		   */
483 
484 		dummy = strchr(elements[0], ' ');
485 		if (!dummy)
486 			goto skip_line;
487 		dummy++;
488 		if (strcmp(dummy, "HOST") == 0)
489 			type = TYPE_HOST;
490 		else if (strcmp(dummy, "SERVICE") == 0)
491 			type = TYPE_SERVICE;
492 		else if (strcmp(dummy, "PROGRAM") == 0)
493 			goto skip_line;
494 		else
495 			goto skip_line;
496 
497 		last_update = atol(elements[0] + 1);
498 
499 		if (type == TYPE_HOST)
500 		{
501 			if (n_elem != 21)
502 				goto skip_line;
503 
504 			host_name = mystrdup(elements[1]);
505 			if (strcmp(elements[2], "UP") == 0)
506 				current_state = 0;
507 			else
508 				current_state = 2;
509 			last_check = atol(elements[3]);
510 			last_state_change = atol(elements[4]);
511 			problem_has_been_acknowledged = atoi(elements[5]);
512 			last_time_up = atol(elements[6]);
513 			last_time_down = atol(elements[7]);
514 			last_time_unreachable = atol(elements[8]);
515 			last_notification = atol(elements[9]);
516 			current_notification_number = atoi(elements[10]);
517 			notifications_enabled = atoi(elements[11]);
518 			event_handler_enabled = atoi(elements[12]);
519 			active_checks_enabled = atoi(elements[13]); /* in 2.0 it has been split up in passive and active */
520 			flap_detection_enabled = atoi(elements[14]);
521 			is_flapping = atoi(elements[15]);
522 			percent_state_change = atof(elements[16]);
523 			scheduled_downtime_depth = atoi(elements[17]);
524 			failure_prediction_enabled = atoi(elements[18]);
525 			/*			process_performance_data = atoi(elements[19]); */
526 			plugin_output = mystrdup(elements[20]);
527 		}
528 		else if (type == TYPE_SERVICE)
529 		{
530 			if (n_elem != 32)
531 				goto skip_line;
532 			host_name = mystrdup(elements[1]);
533 			service_description = mystrdup(elements[2]);
534 			if (strcmp(elements[3], "OK") == 0)
535 				current_state = 0;
536 			else if (strcmp(elements[3], "WARNING") == 0)
537 				current_state = 1;
538 			else if (strcmp(elements[3], "CRITICAL") == 0)
539 				current_state = 2;
540 			else if (strcmp(elements[3], "UNKNOWN") == 0 || strcmp(elements[3], "PENDING") == 0)
541 				current_state = 3;
542 			/*			retry_number = atoi(elements[4]); */
543 			if (strcmp(elements[5], "SOFT") == 0)
544 				state_type = 0;
545 			else
546 				state_type = 1;
547 			last_check = atol(elements[6]);
548 			next_check = atol(elements[7]);
549 			if (strcmp(elements[8], "ACTIVE") == 0)
550 				check_type = 1;
551 			else
552 				check_type = 0;
553 			active_checks_enabled = atoi(elements[9]);
554 			/*			accept_passive_checks = atoi(elements[10]); */
555 			event_handler_enabled = atoi(elements[11]);
556 			last_state_change = atol(elements[12]);
557 			problem_has_been_acknowledged = atoi(elements[13]);
558 			if (strcmp(elements[14], "OK") == 0)
559 				last_hard_state = 0;
560 			else if (strcmp(elements[14], "WARNING") == 0)
561 				last_hard_state = 1;
562 			else if (strcmp(elements[14], "CRITICAL") == 0)
563 				last_hard_state = 2;
564 			else if (strcmp(elements[14], "UNKNOWN") == 0)
565 				last_hard_state = 3;
566 			last_time_ok = atol(elements[15]);
567 			last_time_unknown = atol(elements[16]);
568 			last_time_warning = atol(elements[17]);
569 			last_time_critical = atol(elements[18]);
570 			last_notification = atol(elements[19]);
571 			current_notification_number = atoi(elements[20]);
572 			notifications_enabled = atoi(elements[21]);
573 			check_latency = atof(elements[22]);
574 			check_execution_time = atof(elements[23]);
575 			flap_detection_enabled = atoi(elements[24]);
576 			is_flapping = atoi(elements[25]);
577 			percent_state_change = atof(elements[26]);
578 			scheduled_downtime_depth = atoi(elements[27]);
579 			failure_prediction_enabled = atoi(elements[28]);
580 			/*			process_performance_date = atoi(elements[29]); */
581 			obsess_over_service = atoi(elements[30]);
582 			plugin_output = mystrdup(elements[31]);
583 		}
584 		else
585 			error_exit("internal error: type %d unexpected\n", type);
586 
587 		(*pstats)[*n_stats].type = type;
588 		(*pstats)[*n_stats].host_name = host_name?host_name:mystrdup("");
589 		if (type == TYPE_HOST && current_state == 1) /* HOSTS: 0=ok, 1=down, 2=unreachable */
590 			current_state = 2;
591 		(*pstats)[*n_stats].current_state = current_state;
592 		(*pstats)[*n_stats].service_description = service_description?service_description:mystrdup("");
593 		(*pstats)[*n_stats].plugin_output = plugin_output?plugin_output:mystrdup("");
594 		(*pstats)[*n_stats].last_state_change = last_state_change;
595 		(*pstats)[*n_stats].active_checks_enabled = active_checks_enabled;
596 		(*pstats)[*n_stats].passive_checks_enabled = passive_checks_enabled;
597 		(*pstats)[*n_stats].notifications_enabled = notifications_enabled;
598 		(*pstats)[*n_stats].problem_has_been_acknowledged = problem_has_been_acknowledged;
599 		(*pstats)[*n_stats].scheduled_downtime_depth = scheduled_downtime_depth;
600 		(*pstats)[*n_stats].state_type = state_type;
601 		(*pstats)[*n_stats].last_hard_state = last_hard_state;
602 		(*pstats)[*n_stats].modified_attributes = modified_attributes;
603 		(*pstats)[*n_stats].event_handler = event_handler;
604 		(*pstats)[*n_stats].has_been_checked = has_been_checked;
605 		(*pstats)[*n_stats].should_be_scheduled = should_be_scheduled;
606 		(*pstats)[*n_stats].current_attempt = current_attempt;
607 		(*pstats)[*n_stats].max_attempts = max_attempts;
608 		(*pstats)[*n_stats].last_hard_state_change = last_hard_state_change;
609 		(*pstats)[*n_stats].last_time_ok = last_time_ok;
610 		(*pstats)[*n_stats].last_time_warning = last_time_warning;
611 		(*pstats)[*n_stats].last_time_unknown = last_time_unknown;
612 		(*pstats)[*n_stats].last_time_critical = last_time_critical;
613 		(*pstats)[*n_stats].last_check = last_check;
614 		(*pstats)[*n_stats].next_check = next_check;
615 		(*pstats)[*n_stats].check_type = check_type;
616 		(*pstats)[*n_stats].current_notification_number = current_notification_number;
617 		(*pstats)[*n_stats].last_notification = last_notification;
618 		(*pstats)[*n_stats].next_notification = next_notification;
619 		(*pstats)[*n_stats].no_more_notifications = no_more_notifications;
620 		(*pstats)[*n_stats].event_handler_enabled = event_handler_enabled;
621 		(*pstats)[*n_stats].acknowledgement_type = acknowledgement_type;
622 		(*pstats)[*n_stats].flap_detection_enabled = flap_detection_enabled;
623 		(*pstats)[*n_stats].failure_prediction_enabled = failure_prediction_enabled;
624 		(*pstats)[*n_stats].process_performance_data = process_performance_data;
625 		(*pstats)[*n_stats].obsess_over_service = obsess_over_service;
626 		(*pstats)[*n_stats].last_update = last_update;
627 		(*pstats)[*n_stats].is_flapping = is_flapping;
628 		(*pstats)[*n_stats].percent_state_change = percent_state_change;
629 		(*pstats)[*n_stats].check_execution_time = check_execution_time;
630 		(*pstats)[*n_stats].check_latency = check_latency;
631 		(*pstats)[*n_stats].performance_data = performance_data;
632 		(*pstats)[*n_stats].check_command = check_command;
633 		(*pstats)[*n_stats].last_time_up = last_time_up;
634 		(*pstats)[*n_stats].last_time_down = last_time_down;
635 		(*pstats)[*n_stats].last_time_unreachable = last_time_unreachable;
636 		(*n_stats)++;
637 
638 skip_line:
639 		free(line);
640 	}
641 
642 	close(fd);
643 }
644 
free_stats_array(struct stats * pstats,int n_stats)645 void free_stats_array(struct stats *pstats, int n_stats)
646 {
647 	if (pstats)
648 	{
649 		for(int loop=0; loop<n_stats; loop++)
650 		{
651 			myfree(pstats[loop].host_name, "entry hostname");
652 			myfree(pstats[loop].service_description, "entry servicedescription");
653 			myfree(pstats[loop].plugin_output, "entry plugin output");
654 			myfree(pstats[loop].performance_data, "entry performance data");
655 			myfree(pstats[loop].check_command, "entry check command");
656 			myfree(pstats[loop].author, "entry author");
657 			myfree(pstats[loop].check_period, "entry check_period");
658 			myfree(pstats[loop].comment_data, "entry comment data");
659 			myfree(pstats[loop].host_notification_period, "entry host notification period");
660 			myfree(pstats[loop].long_plugin_output, "entry long plugin output");
661 			myfree(pstats[loop].notification_period, "entry notification period");
662 			myfree(pstats[loop].service_notification_period, "entry service notification period");
663 		}
664 
665 		myfree(pstats, "stats array");
666 	}
667 }
668 
sort_compare_func(const void * a,const void * b)669 int sort_compare_func(const void *a, const void *b)
670 {
671 	struct stats *p1 = (struct stats *)a;
672 	struct stats *p2 = (struct stats *)b;
673 
674 	if (p1 -> current_state < p2 -> current_state)
675 		return 1;
676 	else if (p1 -> current_state == p2 -> current_state)
677 	{
678 		if (p1 -> last_state_change < p2 -> last_state_change)
679 			return 1;
680 
681 		return p2 -> last_state_change - p1 -> last_state_change;
682 	}
683 
684 	return -1;
685 }
686 
sort_stats_array(struct stats * pstats,int n_stats)687 void sort_stats_array(struct stats *pstats, int n_stats)
688 {
689 	if (n_stats > 1)
690 		qsort(pstats, n_stats, sizeof(struct stats), sort_compare_func);
691 }
692 
host_is_down(struct stats * pstats,int n_stats,char * host_name)693 int host_is_down(struct stats *pstats, int n_stats, char *host_name)
694 {
695 	for(int loop=0; loop<n_stats; loop++)
696 	{
697 		if (pstats[loop].type == TYPE_SERVICE)
698 			continue;
699 
700 		if (pstats[loop].current_state == 1 || // down
701 				pstats[loop].current_state == 2) // unreachable
702 		{
703 			if (pstats[loop].host_name != NULL && strcmp(pstats[loop].host_name, host_name) == 0)
704 				return loop;
705 		}
706 	}
707 
708 	return -1;
709 }
710 
should_i_show_entry(struct stats * pstats,int n_stats,int cur_index,char list_all_problems,char always_notify,char also_acknowledged,char hide_ok)711 int should_i_show_entry(struct stats *pstats, int n_stats, int cur_index, char list_all_problems, char always_notify, char also_acknowledged, char hide_ok)
712 {
713 	if (pstats[cur_index].state_type != 1)
714 		return 0;
715 
716 	if (!list_all_problems)
717 	{
718 		if (pstats[cur_index].type != TYPE_HOST && host_is_down(pstats, n_stats, pstats[cur_index].host_name) != -1)
719 			return 0;
720 
721 		if (pstats[cur_index].active_checks_enabled == 0 &&
722 				pstats[cur_index].passive_checks_enabled == 0)
723 			return 0;
724 
725 		if (pstats[cur_index].scheduled_downtime_depth != 0)
726 			return 0;
727 	}
728 
729 	if (!always_notify && pstats[cur_index].notifications_enabled == 0)
730 		return 0;
731 
732 	if (!also_acknowledged && pstats[cur_index].problem_has_been_acknowledged == 1)
733 		return 0;
734 
735 	if (pstats[cur_index].current_state == 0 && hide_ok)
736 		return 0;
737 
738 	if (pstats[cur_index].current_state < 0 || pstats[cur_index].current_state > 3)
739 		error_exit("internal error: state %d not known", pstats[cur_index].current_state);
740 
741 	return 1;
742 }
743 
find_index_by_host_and_service(struct stats * pstats,int n_stats,char * host_name,char * service_description)744 int find_index_by_host_and_service(struct stats *pstats, int n_stats, char *host_name, char *service_description)
745 {
746 	int loop;
747 	static int last = 0;
748 
749 	if (service_description)
750 	{
751 		for(loop=0; loop<n_stats; loop++)
752 		{
753 			int index = (last + loop) % n_stats;
754 			if (pstats[index].host_name != NULL && strcmp(pstats[index].host_name, host_name) == 0 &&
755 					pstats[index].service_description != NULL && strcmp(pstats[index].service_description, service_description) == 0)
756 			{
757 				last = index;
758 				return index;
759 			}
760 		}
761 	}
762 	else
763 	{
764 		for(loop=0; loop<n_stats; loop++)
765 		{
766 			int index = (last + loop) % n_stats;
767 			if (pstats[index].service_description == NULL && pstats[index].host_name != NULL && strcmp(pstats[index].host_name, host_name) == 0)
768 			{
769 				last = index;
770 				return index;
771 			}
772 		}
773 	}
774 
775 	return -1;
776 }
777 
check_an_age(char ** message,char * descr,time_t now,time_t check_time,int max_diff,char * what)778 int check_an_age(char **message, char *descr, time_t now, time_t check_time, int max_diff, char *what)
779 {
780 	char buffer[4096] = { 0 };
781 	int cur_diff = (now - check_time);
782 
783 	*message = 0x00;
784 
785 	if (cur_diff > max_diff)
786 	{
787 		char *time_str = ctime(&check_time);
788 		char *dummy = strchr(time_str, '\n');
789 		*dummy = 0x00;
790 
791 		snprintf(buffer, sizeof(buffer), "limit reached of \"%s\" for %s: %d seconds (last check: %s (%d), max diff: %d)", descr, what?what:"?", cur_diff, time_str, (int)check_time, max_diff);
792 
793 		*message = strdup(buffer);
794 
795 		return -1;
796 	}
797 
798 	return 0;
799 }
800 
check_max_age_last_check(struct stats * pstats,int n_stats,int max_time_last_host_update,int max_time_oldest_host_update,int max_time_last_host_check,int max_time_oldest_host_check,int max_time_last_service_check,int max_time_oldest_service_check,int max_time_oldest_next_service_check,char ** message)801 int check_max_age_last_check(struct stats *pstats, int n_stats, int max_time_last_host_update, int max_time_oldest_host_update, int max_time_last_host_check, int max_time_oldest_host_check, int max_time_last_service_check, int max_time_oldest_service_check, int max_time_oldest_next_service_check, char **message)
802 {
803 	time_t now = time(NULL);
804 	int index;
805 	time_t most_recent_host_update = 0;
806 	time_t most_recent_host_check  = 0;
807 	time_t most_recent_last_service_check = 0;
808 	time_t oldest_next_service_check = now;
809 
810 	for(index=0; index<n_stats; index++)
811 	{
812 		if (pstats[index].type == TYPE_HOST)
813 		{
814 			if (pstats[index].last_update != 0 && pstats[index].active_checks_enabled != 0)
815 			{
816 				most_recent_host_update = max(most_recent_host_update, pstats[index].last_update);
817 
818 				if (check_an_age(message, "oldest host update", now, pstats[index].last_update, max_time_oldest_host_update, pstats[index].host_name) == -1)
819 					return -1;
820 			}
821 
822 			if (pstats[index].last_check != 0 && pstats[index].active_checks_enabled != 0)
823 			{
824 				most_recent_host_check = max(most_recent_host_check, pstats[index].last_check);
825 
826 				// if (check_an_age(message, "oldest host check", now, pstats[index].last_check, max_time_oldest_host_check, pstats[index].host_name) == -1)
827 				//	return -1;
828 			}
829 		}
830 		else if (pstats[index].type == TYPE_SERVICE)
831 		{
832 			if (pstats[index].last_check != 0)
833 			{
834 				char buffer[4096];
835 
836 				snprintf(buffer, sizeof(buffer), "%s@%s", pstats[index].service_description, pstats[index].host_name);
837 
838 				most_recent_last_service_check = max(most_recent_last_service_check, pstats[index].last_check);
839 
840 				if (check_an_age(message, "oldest service check", now, pstats[index].last_check, max_time_oldest_service_check, buffer) == -1)
841 					return -1;
842 			}
843 
844 			if (pstats[index].next_check != 0)
845 			{
846 				oldest_next_service_check = min(oldest_next_service_check, pstats[index].next_check);
847 			}
848 		}
849 	}
850 
851 	if (check_an_age(message, "most recent host update", now, most_recent_host_update, max_time_last_host_update, NULL) == -1)
852 		return -1;
853 
854 	// if (check_an_age(message, "most recent host check", now, most_recent_host_check, max_time_last_host_check, NULL) == -1)
855 	//	return -1;
856 
857 	if (check_an_age(message, "most recent last service check", now, most_recent_last_service_check, max_time_last_service_check, NULL) == -1)
858 		return -1;
859 
860 	if (check_an_age(message, "oldest next sevice check", now, oldest_next_service_check, max_time_oldest_next_service_check, NULL) == -1)
861 		return -1;
862 
863 	return 0;
864 }
865 
calc_stats_stats(struct stats * pstats,int n_stats,char list_all_problems,char always_notify,char also_acknowledged,char hide_ok,int * n_critical,int * n_warning,int * n_ok,int * n_up,int * n_down,int * n_unreachable,int * n_pending)866 void calc_stats_stats(struct stats *pstats, int n_stats, char list_all_problems, char always_notify, char also_acknowledged, char hide_ok, int *n_critical, int *n_warning, int *n_ok, int *n_up, int *n_down, int *n_unreachable, int *n_pending)
867 {
868 	*n_critical = *n_warning = *n_ok = 0;
869 	*n_up = *n_down = *n_unreachable = *n_pending = 0;
870 
871 	for(int loop=0; loop<n_stats; loop++)
872 	{
873 		if (pstats[loop].type == TYPE_HOST)
874 		{
875 			if (pstats[loop].current_state == 0)
876 				(*n_up)++;
877 			else if (pstats[loop].current_state == 1)
878 				(*n_down)++;
879 			else if (pstats[loop].current_state == 2)
880 				(*n_unreachable)++;
881 			else if (pstats[loop].current_state == 3)
882 				(*n_pending)++;
883 		}
884 		else if (pstats[loop].type == TYPE_SERVICE)
885 		{
886 			if (pstats[loop].current_state == 0)
887 				(*n_ok)++;
888 			else if (pstats[loop].current_state == 1)
889 				(*n_warning)++;
890 			else if (pstats[loop].current_state == 2)
891 				(*n_critical)++;
892 		}
893 		else
894 			error_exit("calc_stats_stats: internal error (%d)", pstats[loop].type);
895 	}
896 }
897