1 /*----------------------------------------------------------------------------*/
2 /* Xymon monitor library.                                                     */
3 /*                                                                            */
4 /* This is a library module for Xymon, responsible for loading the            */
5 /* critical.cfg file.                                                         */
6 /*                                                                            */
7 /* Copyright (C) 2005-2011 Henrik Storner <henrik@hswn.dk>                    */
8 /*                                                                            */
9 /* This program is released under the GNU General Public License (GPL),       */
10 /* version 2. See the file "COPYING" for details.                             */
11 /*                                                                            */
12 /*----------------------------------------------------------------------------*/
13 
14 static char rcsid[] = "$Id: loadcriticalconf.c 8069 2019-07-23 15:29:06Z jccleaver $";
15 
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <time.h>
22 #include <limits.h>
23 #include <ctype.h>
24 #include <utime.h>
25 
26 #include "libxymon.h"
27 
28 static void * rbconf;
29 STATIC_SBUF_DEFINE(defaultfn);
30 STATIC_SBUF_DEFINE(configfn);
31 
32 
flushrec(void * k1,void * k2)33 static void flushrec(void *k1, void *k2)
34 {
35 	char *key;
36 
37 	key = (char *)k1;
38 	if (*(key + strlen(key) - 1) == '=') {
39 		/* Clone record just holds a char string pointing to the origin record */
40 		char *pointsto = (char *)k2;
41 		xfree(pointsto);
42 	}
43 	else {
44 		/* Full record */
45 		critconf_t *rec = (critconf_t *)k2;
46 		if (rec->crittime)  xfree(rec->crittime);
47 		if (rec->ttgroup) xfree(rec->ttgroup);
48 		if (rec->ttextra) xfree(rec->ttextra);
49 	}
50 	xfree(key);
51 }
52 
load_critconfig(char * fn)53 int load_critconfig(char *fn)
54 {
55 	static void *configfiles = NULL;
56 	static int firsttime = 1;
57 	FILE *fd;
58 	strbuffer_t *inbuf;
59 
60 	/* Setup the default configuration filename */
61 	if (!fn) {
62 		if (!defaultfn) {
63 			char *xymonhome = xgetenv("XYMONHOME");
64 			SBUF_MALLOC(defaultfn, strlen(xymonhome) + strlen(DEFAULT_CRITCONFIGFN) + 2);
65 			snprintf(defaultfn, defaultfn_buflen, "%s/%s", xymonhome, DEFAULT_CRITCONFIGFN);
66 		}
67 		fn = defaultfn;
68 	}
69 
70 	if (configfn && (strcmp(fn, configfn) != 0)) {
71 		/* Force full reload - it's a different config file */
72 		if (configfiles) {
73 			stackfclist(&configfiles);
74 			configfiles = NULL;
75 		}
76 	}
77 
78 	if (configfn) xfree(configfn);
79 	configfn = strdup(fn);
80 
81 	/* First check if there were no modifications at all */
82 	if (configfiles) {
83 		if (!stackfmodified(configfiles)){
84 			dbgprintf("No files modified, skipping reload of %s\n", fn);
85 			return 0;
86 		}
87 		else {
88 			stackfclist(&configfiles);
89 			configfiles = NULL;
90 		}
91 	}
92 
93 	if (!firsttime) {
94 		/* Clean up existing datatree */
95 		xtreePos_t handle;
96 
97 		for (handle = xtreeFirst(rbconf); (handle != xtreeEnd(rbconf)); handle = xtreeNext(rbconf, handle)) {
98 			flushrec(xtreeKey(rbconf, handle), xtreeData(rbconf, handle));
99 		}
100 
101 		xtreeDestroy(rbconf);
102 	}
103 
104 	firsttime = 0;
105 	rbconf = xtreeNew(strcasecmp);
106 
107 	fd = stackfopen(fn, "r", &configfiles);
108 	if (fd == NULL) return 1;
109 
110 	inbuf = newstrbuffer(0);
111 	while (stackfgets(inbuf, NULL)) {
112 		/* Full record : Host  service  START  END  TIMESPEC  TTPrio TTGroup TTExtra */
113 		/* Clone record: Host  =HOST */
114 		char *ehost, *eservice, *estart, *eend, *etime, *ttgroup, *ttextra, *updinfo;
115 		int ttprio = 0;
116 		critconf_t *newitem;
117 		xtreeStatus_t status;
118 		int idx = 0;
119 
120 		ehost = gettok(STRBUF(inbuf), "|\n"); if (!ehost) continue;
121 		eservice = gettok(NULL, "|\n"); if (!eservice) continue;
122 
123 		if (*eservice == '=') {
124 			SBUF_DEFINE(key);
125 			char *pointsto = strdup(eservice+1);
126 
127 			SBUF_MALLOC(key, strlen(ehost) + 2);
128 
129 			snprintf(key, key_buflen, "%s=", ehost);
130 			status = xtreeAdd(rbconf, key, pointsto);
131 		}
132 		else {
133 			unsigned int key_buflen;
134 
135 			estart = gettok(NULL, "|\n"); if (!estart) continue;
136 			eend = gettok(NULL, "|\n"); if (!eend) continue;
137 			etime = gettok(NULL, "|\n"); if (!etime) continue;
138 			ttprio = atoi(gettok(NULL, "|\n")); if (ttprio == 0) continue;
139 			ttgroup = gettok(NULL, "|\n");
140 			ttextra = gettok(NULL, "|\n");
141 			updinfo = gettok(NULL, "|\n");
142 
143 			newitem = (critconf_t *)malloc(sizeof(critconf_t));
144 			key_buflen = strlen(ehost) + strlen(eservice) + 15;
145 			newitem->key = (char *)malloc(key_buflen);
146 			snprintf(newitem->key, key_buflen, "%s|%s", ehost, eservice);
147 			newitem->starttime= ((estart && *estart) ? atoi(estart) : 0);
148 			newitem->endtime  = ((eend && *eend) ? atoi(eend) : 0);
149 			newitem->crittime = ((etime && *etime) ? strdup(etime) : NULL);
150 			newitem->priority = ttprio;
151 			newitem->ttgroup  = strdup(ttgroup);
152 			newitem->ttextra  = strdup(ttextra);
153 			newitem->updinfo  = strdup(updinfo);
154 
155 			status = xtreeAdd(rbconf, newitem->key, newitem);
156 			while (status == XTREE_STATUS_DUPLICATE_KEY) {
157 				idx++;
158 				snprintf(newitem->key, key_buflen, "%s|%s|%d", ehost, eservice, idx);
159 				status = xtreeAdd(rbconf, newitem->key, newitem);
160 			}
161 		}
162 	}
163 
164 	stackfclose(fd);
165 	freestrbuffer(inbuf);
166 
167 	if (debug) {
168 		xtreePos_t handle;
169 
170 		handle = xtreeFirst(rbconf);
171 		while (handle != xtreeEnd(rbconf)) {
172 			printf("%s\n", (char *)xtreeKey(rbconf, handle));
173 			handle = xtreeNext(rbconf, handle);
174 		}
175 	}
176 
177 	return 0;
178 }
179 
findrec(char * key)180 static xtreePos_t findrec(char *key)
181 {
182 	xtreePos_t handle;
183 
184 	handle = xtreeFind(rbconf, key);
185 	if (handle == xtreeEnd(rbconf)) {
186 		/* Check if there's a clone pointer record */
187 		SBUF_DEFINE(clonekey);
188 		char *p;
189 
190 		clonekey = strdup(key);
191 		p = strchr(clonekey, '|');
192 		if (p && *(p+1)) { *p = '='; *(p+1) = '\0'; }
193 		handle = xtreeFind(rbconf, clonekey);
194 		xfree(clonekey);
195 
196 		if (handle != xtreeEnd(rbconf)) {
197 			char *pointsto;
198 			char *service;
199 
200 			/* Get the origin record for this cloned record, using the same service name */
201 			pointsto = (char *)xtreeData(rbconf, handle);
202 			service = strchr(key, '|');
203 			if (service) {
204 				service++;
205 				SBUF_MALLOC(clonekey, strlen(pointsto) + strlen(service) + 2);
206 				snprintf(clonekey, clonekey_buflen, "%s|%s", pointsto, service);
207 
208 				handle = xtreeFind(rbconf, clonekey);
209 				xfree(clonekey);
210 			}
211 			else
212 				handle = xtreeEnd(rbconf);
213 		}
214 	}
215 
216 	return handle;
217 }
218 
timecheck(time_t starttime,time_t endtime,char * crittime)219 static int timecheck(time_t starttime, time_t endtime, char *crittime)
220 {
221 	time_t now = getcurrenttime(NULL);
222 
223 	if (starttime && (now < starttime)) return 0;
224 	if (endtime && (now > endtime)) return 0;
225 	if ((crittime == NULL) || within_sla(NULL, crittime, 0)) return 1; /* FIXME */
226 
227 	return 0;
228 }
229 
get_critconfig(char * key,int flags,char ** resultkey)230 critconf_t *get_critconfig(char *key, int flags, char **resultkey)
231 {
232 	static xtreePos_t handle;
233 	static char *realkey = NULL;
234 	critconf_t *result = NULL;
235 	int isclone;
236 
237 	if (resultkey) *resultkey = NULL;
238 
239 	switch (flags) {
240 	  case CRITCONF_TIMEFILTER:
241 		handle = findrec(key);
242 		/* We may have hit a cloned record, so use the real key for further searches */
243 		if (handle != xtreeEnd(rbconf)) {
244 			realkey = (char *)xtreeKey(rbconf, handle);
245 		}
246 
247 		while (handle != xtreeEnd(rbconf)) {
248 			result = (critconf_t *)xtreeData(rbconf, handle);
249 			if (timecheck(result->starttime, result->endtime, result->crittime)) return result;
250 
251 			/* Go to the next */
252 			handle = xtreeNext(rbconf, handle);
253 			if (handle != xtreeEnd(rbconf)) {
254 				critconf_t *rec = (critconf_t *)xtreeData(rbconf, handle);
255 				if (strncmp(realkey, rec->key, strlen(realkey)) != 0) handle=xtreeEnd(rbconf);
256 			}
257 		}
258 		realkey = NULL;
259 		break;
260 
261 	  case CRITCONF_FIRSTMATCH:
262 		handle = findrec(key);
263 		realkey = NULL;
264 		if (handle != xtreeEnd(rbconf)) {
265 			realkey = (char *)xtreeKey(rbconf, handle);
266 		}
267 		break;
268 
269 	  case CRITCONF_FIRST:
270 		realkey = NULL;
271 		handle = xtreeFirst(rbconf);
272 		if (handle == xtreeEnd(rbconf)) return NULL;
273 		do {
274 			realkey = (char *)xtreeKey(rbconf, handle);
275 			isclone = (*(realkey + strlen(realkey) - 1) == '=');
276 			if (isclone) handle = xtreeNext(rbconf, handle);
277 		} while (isclone && (handle != xtreeEnd(rbconf)));
278 		break;
279 
280 
281 	  case CRITCONF_NEXT:
282 		if (!realkey || (handle == xtreeEnd(rbconf))) return NULL;
283 		isclone = 1;
284 		while (isclone && (handle != xtreeEnd(rbconf))) {
285 			handle = xtreeNext(rbconf, handle);
286 			if (handle) {
287 				realkey = (char *)xtreeKey(rbconf, handle);
288 				isclone = (*(realkey + strlen(realkey) - 1) == '=');
289 			}
290 		}
291 		break;
292 
293 	  case CRITCONF_RAW_FIRST:
294 		handle = xtreeFirst(rbconf);
295 		realkey = NULL;
296 		break;
297 
298 	  case CRITCONF_RAW_NEXT:
299 		handle = xtreeNext(rbconf, handle);
300 		realkey = NULL;
301 		break;
302 
303 	  case CRITCONF_FIRSTHOSTMATCH:
304 		do {
305 			int found = 0;
306 			char *delim;
307 
308 			realkey = NULL;
309 			handle = xtreeFirst(rbconf);
310 			while (!found && (handle != xtreeEnd(rbconf))) {
311 				realkey = (char *)xtreeKey(rbconf, handle);
312 				delim = realkey + strlen(key); /* OK even if past end of realkey */
313 				found = ((strncmp(realkey, key, strlen(key)) == 0) &&
314 					((*delim == '|') || (*delim == '=')));
315 				if (!found) { handle = xtreeNext(rbconf, handle); realkey = NULL; }
316 			}
317 
318 			if ((handle != xtreeEnd(rbconf)) && (*(realkey + strlen(realkey) - 1) == '=')) {
319 				key = (char *)xtreeData(rbconf, handle);
320 				isclone = 1;
321 			}
322 			else isclone = 0;
323 
324 		} while (isclone && (handle != xtreeEnd(rbconf)));
325 		break;
326 	}
327 
328 	if (handle == xtreeEnd(rbconf)) { realkey = NULL; return NULL; }
329 
330 	if (resultkey) *resultkey = (char *)xtreeKey(rbconf, handle);
331 	result = (critconf_t *)xtreeData(rbconf, handle);
332 
333 	return result;
334 }
335 
update_critconfig(critconf_t * rec)336 int update_critconfig(critconf_t *rec)
337 {
338 	SBUF_DEFINE(bakfn);
339 	FILE *bakfd;
340 	unsigned char buf[8192];
341 	int n;
342 	struct stat st;
343 	struct utimbuf ut;
344 
345 	xtreePos_t handle;
346 	FILE *fd;
347 	int result = 0;
348 
349 	/* First, copy the old file */
350 	SBUF_MALLOC(bakfn, strlen(configfn) + 5);
351 	snprintf(bakfn, bakfn_buflen, "%s.bak", configfn);
352 	if (stat(configfn, &st) == 0) {
353 		ut.actime = st.st_atime;
354 		ut.modtime = st.st_mtime;
355 	}
356 	else ut.actime = ut.modtime = getcurrenttime(NULL);
357 	fd = fopen(configfn, "r");
358 	if (fd) {
359 		bakfd = fopen(bakfn, "w");
360 		if (bakfd) {
361 			while ((n = fread(buf, 1, sizeof(buf), fd)) > 0) fwrite(buf, 1, n, bakfd);
362 			fclose(bakfd);
363 			utime(bakfn, &ut);
364 		}
365 		fclose(fd);
366 	}
367 	xfree(bakfn);
368 
369 	fd = fopen(configfn, "w");
370 	if (fd == NULL) {
371 		errprintf("Cannot open output file %s\n", configfn);
372 		return 1;
373 	}
374 
375 	if (rec) {
376 		handle = xtreeFind(rbconf, rec->key);
377 		if (handle == xtreeEnd(rbconf)) xtreeAdd(rbconf, rec->key, rec);
378 	}
379 
380 	handle = xtreeFirst(rbconf);
381 	while (handle != xtreeEnd(rbconf)) {
382 		char *onekey;
383 
384 		onekey = (char *)xtreeKey(rbconf, handle);
385 
386 		if (*(onekey + strlen(onekey) - 1) == '=') {
387 			char *pointsto = (char *)xtreeData(rbconf, handle);
388 			char *hostname;
389 
390 			hostname = strdup(onekey);
391 			*(hostname + strlen(hostname) - 1) = '\0';
392 			fprintf(fd, "%s|=%s\n", hostname, pointsto);
393 		}
394 		else {
395 			critconf_t *onerec = (critconf_t *)xtreeData(rbconf, handle);
396 			char startstr[20], endstr[20];
397 
398 			*startstr = *endstr = '\0';
399 			if (onerec->starttime > 0) snprintf(startstr, sizeof(startstr), "%d", (int)onerec->starttime);
400 			if (onerec->endtime > 0) snprintf(endstr, sizeof(endstr), "%d", (int)onerec->endtime);
401 
402 			fprintf(fd, "%s|%s|%s|%s|%d|%s|%s|%s\n",
403 				onekey,
404 				startstr, endstr,
405 				(onerec->crittime ? onerec->crittime : ""),
406 				onerec->priority,
407 				(onerec->ttgroup ? onerec->ttgroup : ""),
408 				(onerec->ttextra ? onerec->ttextra : ""),
409 				(onerec->updinfo ? onerec->updinfo : ""));
410 		}
411 
412 		handle = xtreeNext(rbconf, handle);
413 	}
414 
415 	fclose(fd);
416 
417 	return result;
418 }
419 
addclone_critconfig(char * origin,char * newclone)420 void addclone_critconfig(char *origin, char *newclone)
421 {
422 	SBUF_DEFINE(newkey);
423 	xtreePos_t handle;
424 
425 	SBUF_MALLOC(newkey, strlen(newclone) + 2);
426 	snprintf(newkey, newkey_buflen, "%s=", newclone);
427 	handle = xtreeFind(rbconf, newkey);
428 	if (handle != xtreeEnd(rbconf)) dropclone_critconfig(newclone);
429 	xtreeAdd(rbconf, newkey, strdup(origin));
430 }
431 
dropclone_critconfig(char * drop)432 void dropclone_critconfig(char *drop)
433 {
434 	xtreePos_t handle;
435 	SBUF_DEFINE(key);
436 	char *dropkey, *dropsrc;
437 
438 	SBUF_MALLOC(key, strlen(drop) + 2);
439 	snprintf(key, key_buflen, "%s=", drop);
440 	handle = xtreeFind(rbconf, key);
441 	if (handle == xtreeEnd(rbconf)) return;
442 
443 	dropkey = (char *)xtreeKey(rbconf, handle);
444 	dropsrc = (char *)xtreeDelete(rbconf, key);
445 	xfree(dropkey); xfree(dropsrc);
446 
447 	xfree(key);
448 }
449 
delete_critconfig(char * dropkey,int evenifcloned)450 int delete_critconfig(char *dropkey, int evenifcloned)
451 {
452 	xtreePos_t handle;
453 
454 	handle = xtreeFind(rbconf, dropkey);
455 	if (handle == xtreeEnd(rbconf)) return 0;
456 
457 	if (!evenifcloned) {
458 		/* Check if this record has any clones attached to it */
459 		char *hostname, *p;
460 
461 		hostname = strdup(dropkey);
462 		p = strchr(hostname, '|'); if (p) *p = '\0';
463 
464 		handle = xtreeFirst(rbconf);
465 
466 		while (handle != xtreeEnd(rbconf)) {
467 			char *key, *ptr;
468 
469 			key = (char *)xtreeKey(rbconf, handle);
470 			ptr = (char *)xtreeData(rbconf, handle);
471 			if ((*(key + strlen(key) - 1) == '=') && (strcmp(hostname, ptr) == 0)) {
472 				xfree(hostname);
473 				return 1;
474 			}
475 
476 			handle = xtreeNext(rbconf, handle);
477 		}
478 
479 		xfree(hostname);
480 	}
481 
482 	handle = xtreeFind(rbconf, dropkey);
483 	if (handle != xtreeEnd(rbconf)) {
484 		void *k1, *k2;
485 
486 		k1 = xtreeKey(rbconf, handle);
487 		k2 = xtreeDelete(rbconf, dropkey);
488 		flushrec(k1, k2);
489 	}
490 
491 	return 0;
492 }
493 
494