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