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