1 /*----------------------------------------------------------------------------*/
2 /* Xymon message daemon.                                                      */
3 /*                                                                            */
4 /* Copyright (C) 2004-2011 Henrik Storner <henrik@hswn.dk>                    */
5 /*                                                                            */
6 /* This program is released under the GNU General Public License (GPL),       */
7 /* version 2. See the file "COPYING" for details.                             */
8 /*                                                                            */
9 /*----------------------------------------------------------------------------*/
10 
11 static char rcsid[] = "$Id: do_rrd.c 7608 2015-03-21 15:00:40Z jccleaver $";
12 
13 #include <sys/types.h>
14 #include <sys/time.h>
15 #include <sys/stat.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <limits.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <utime.h>
24 
25 #include <rrd.h>
26 #include <pcre.h>
27 
28 #include "libxymon.h"
29 
30 #include "xymond_rrd.h"
31 #include "do_rrd.h"
32 #include "client_config.h"
33 
34 #ifndef NAME_MAX
35 #define NAME_MAX 255	/* Solaris doesn't define NAME_MAX, but ufs limit is 255 */
36 #endif
37 
38 extern int seq;	/* from xymond_rrd.c */
39 
40 char *rrddir = NULL;
41 int use_rrd_cache = 1;         /* Use the cache by default */
42 int no_rrd = 0;                /* Write to rrd by default */
43 
44 static int  processorfd = 0;
45 static FILE *processorstream = NULL;
46 
47 static char *exthandler = NULL;
48 static char **extids = NULL;
49 
50 static char rrdvalues[MAX_LINE_LEN];
51 
52 static char *senderip = NULL;
53 static char rrdfn[PATH_MAX];   /* Base filename without directories, from setupfn() */
54 static char filedir[PATH_MAX]; /* Full path filename */
55 static char *fnparams[4] = { NULL, };  /* Saved parameters passed to setupfn() */
56 
57 /* How often do we feed data into the RRD file */
58 #define DEFAULT_RRD_INTERVAL 300
59 static int  rrdinterval = DEFAULT_RRD_INTERVAL;
60 
61 #define CACHESZ 12             /* # of updates that can be cached - updates are usually 5 minutes apart */
62 static int updcache_keyofs = -1;
63 static void * updcache;
64 typedef struct updcacheitem_t {
65 	char *key;
66 	rrdtpldata_t *tpl;
67 	int valcount;
68 	char *vals[CACHESZ];
69 	int updseq[CACHESZ];
70 	time_t updtime[CACHESZ];
71 } updcacheitem_t;
72 
73 static void * flushtree;
74 static int have_flushtree = 0;
75 typedef struct flushtree_t {
76 	char *hostname;
77 	time_t flushtime;
78 } flushtree_t;
79 
80 
setup_exthandler(char * handlerpath,char * ids)81 void setup_exthandler(char *handlerpath, char *ids)
82 {
83 	char *p;
84 	int idcount = 0;
85 
86 	MEMDEFINE(rrdvalues);
87 
88 	exthandler = strdup(handlerpath);
89 	idcount=1; p = ids; while ((p = strchr(p, ',')) != NULL) { p++; idcount++; }
90 	extids = (char **)malloc((idcount+1)*(sizeof(char *)));
91 	idcount = 0;
92 	p = strtok(ids, ",");
93 	while (p) {
94 		extids[idcount++] = strdup(p);
95 		p = strtok(NULL, ",");
96 	}
97 	extids[idcount] = NULL;
98 
99 	MEMUNDEFINE(rrdvalues);
100 }
101 
setup_extprocessor(char * cmd)102 void setup_extprocessor(char *cmd)
103 {
104 
105 	int n;
106 	int pfd[2];
107 	pid_t childpid;
108 
109 	if (!cmd) return;
110 
111 	processorfd = 0;
112 
113 	n = pipe(pfd);
114 	if (n == -1) {
115 		errprintf("Could not get a pipe: %s\n", strerror(errno));
116 	}
117 	else {
118 		childpid = fork();
119 		if (childpid == -1) {
120 			errprintf("Could not fork channel handler: %s\n", strerror(errno));
121 		}
122 		else if (childpid == 0) {
123 			/* The channel handler child */
124 			char *argv[2];
125 
126 			argv[0] = strdup(cmd);
127 			argv[1] = NULL;
128 
129 			n = dup2(pfd[0], STDIN_FILENO);
130 			close(pfd[0]); close(pfd[1]);
131 			n = execvp(cmd, argv);
132 
133 			/* We should never go here */
134 			errprintf("exec() failed for child command %s: %s\n", cmd, strerror(errno));
135 			exit(1);
136 		}
137 		else {
138 			/* Parent process continues */
139 			close(pfd[0]);
140 			processorfd = pfd[1];
141 			processorstream = fdopen(processorfd, "w");
142 			errprintf("External processor '%s' started\n", cmd);
143 		}
144 	}
145 }
146 
shutdown_extprocessor(void)147 void shutdown_extprocessor(void)
148 {
149 	if (!processorfd) return;
150 
151 	close(processorfd);
152 	processorfd = 0;
153 	processorstream = NULL;
154 
155 	errprintf("External processor stopped\n");
156 }
157 
158 
setupfn(char * format,char * param)159 static void setupfn(char *format, char *param)
160 {
161 	char *p;
162 
163 	memset(fnparams, 0, sizeof(fnparams));
164 	fnparams[0] = param;
165 
166 	snprintf(rrdfn, sizeof(rrdfn)-1, format, param);
167 	rrdfn[sizeof(rrdfn)-1] = '\0';
168 	while ((p = strchr(rrdfn, ' ')) != NULL) *p = '_';
169 }
170 
setupfn2(char * format,char * param1,char * param2)171 static void setupfn2(char *format, char *param1, char *param2)
172 {
173 	char *p;
174 
175 	while ((p = strchr(param2, '/')) != NULL) *p = ',';
176 
177 	memset(fnparams, 0, sizeof(fnparams));
178 	fnparams[0] = param1;
179 	fnparams[1] = param2;
180 
181 	snprintf(rrdfn, sizeof(rrdfn)-1, format, param1, param2);
182 	rrdfn[sizeof(rrdfn)-1] = '\0';
183 	while ((p = strchr(rrdfn, ' ')) != NULL) *p = '_';
184 }
185 
setupfn3(char * format,char * param1,char * param2,char * param3)186 static void setupfn3(char *format, char *param1, char *param2, char *param3)
187 {
188 	char *p;
189 
190 	memset(fnparams, 0, sizeof(fnparams));
191 	fnparams[0] = param1;
192 	fnparams[1] = param2;
193 	fnparams[2] = param3;
194 
195 	snprintf(rrdfn, sizeof(rrdfn)-1, format, param1, param2, param3);
196 	rrdfn[sizeof(rrdfn)-1] = '\0';
197 	while ((p = strchr(rrdfn, ' ')) != NULL) *p = '_';
198 
199 	if (strlen(rrdfn) >= (NAME_MAX - 50)) {
200 		/*
201 		 * Filename is too long. Limit filename length
202 		 * by replacing the last part of the filename
203 		 * with an MD5 hash.
204 		 */
205 		char *hash = md5hash(rrdfn+(NAME_MAX-50));
206 
207 		sprintf(rrdfn+(NAME_MAX-50), "_%s.rrd", hash);
208 	}
209 }
210 
setupinterval(int intvl)211 static void setupinterval(int intvl)
212 {
213 	rrdinterval = (intvl ? intvl : DEFAULT_RRD_INTERVAL);
214 }
215 
flush_cached_updates(updcacheitem_t * cacheitem,char * newdata)216 static int flush_cached_updates(updcacheitem_t *cacheitem, char *newdata)
217 {
218 	/* Flush any updates we've cached */
219 	char *updparams[5+CACHESZ+1] = { "rrdupdate", filedir, "-t", NULL, NULL, NULL, };
220 	int i, pcount, result;
221 
222 	dbgprintf("Flushing '%s' with %d updates pending, template '%s'\n",
223 		  cacheitem->key, (newdata ? 1 : 0) + cacheitem->valcount, cacheitem->tpl->template);
224 
225 	/* ISO C90: parameters cannot be used as initializers */
226 	updparams[3] = cacheitem->tpl->template;
227 
228 	/* Setup the parameter list with all of the cached and new readings */
229 	for (i=0; (i < cacheitem->valcount); i++) updparams[4+i] = cacheitem->vals[i];
230 
231 	if (newdata) {
232 		updparams[4+cacheitem->valcount] = newdata;
233 		updparams[4+cacheitem->valcount+1] = NULL;
234 	}
235 	else {
236 		/* No new data - happens when flushing the cache */
237 		updparams[4+cacheitem->valcount] = NULL;
238 	}
239 
240 	for (pcount = 0; (updparams[pcount]); pcount++);
241 	optind = opterr = 0; rrd_clear_error();
242 	result = rrd_update(pcount, updparams);
243 
244 #if defined(LINUX) && defined(RRDTOOL12)
245 	/*
246 	 * RRDtool 1.2+ uses mmap'ed I/O, but the Linux kernel does not update timestamps when
247 	 * doing file I/O on mmap'ed files. This breaks our check for stale/nostale RRD's.
248 	 * So do an explicit timestamp update on the file here.
249 	 */
250 	utimes(filedir, NULL);
251 #endif
252 
253 	/* Clear the cached data */
254 	for (i=0; (i < cacheitem->valcount); i++) {
255 		cacheitem->updseq[i] = 0;
256 		cacheitem->updtime[i] = 0;
257 		if (cacheitem->vals[i]) xfree(cacheitem->vals[i]);
258 	}
259 	cacheitem->valcount = 0;
260 
261 	return result;
262 }
263 
create_and_update_rrd(char * hostname,char * testname,char * classname,char * pagepaths,char * creparams[],void * template)264 static int create_and_update_rrd(char *hostname, char *testname, char *classname, char *pagepaths, char *creparams[], void *template)
265 {
266 	static int callcounter = 0;
267 	struct stat st;
268 	int pcount, result;
269 	char *updcachekey;
270 	xtreePos_t handle;
271 	updcacheitem_t *cacheitem = NULL;
272 	int pollinterval;
273 	strbuffer_t *modifymsg;
274 	time_t updtime = 0;
275 
276 	/* Reset the RRD poll interval */
277 	pollinterval = rrdinterval;
278 	rrdinterval = DEFAULT_RRD_INTERVAL;
279 
280 	if ((rrdfn == NULL) || (strlen(rrdfn) == 0)) {
281 		errprintf("RRD update for no file\n");
282 		return -1;
283 	}
284 
285 	MEMDEFINE(rrdvalues);
286 	MEMDEFINE(filedir);
287 
288 	sprintf(filedir, "%s/%s", rrddir, hostname);
289 	if (stat(filedir, &st) == -1) {
290 		if (mkdir(filedir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) == -1) {
291 			errprintf("Cannot create rrd directory %s : %s\n", filedir, strerror(errno));
292 			MEMUNDEFINE(filedir);
293 			MEMUNDEFINE(rrdvalues);
294 			return -1;
295 		}
296 	}
297 	/* Watch out here - "rrdfn" may be very large. */
298 	snprintf(filedir, sizeof(filedir)-1, "%s/%s/%s", rrddir, hostname, rrdfn);
299 	filedir[sizeof(filedir)-1] = '\0'; /* Make sure it is null terminated */
300 
301 	/*
302 	 * Prepare to cache the update. Create the cache tree, and find/create a cache record.
303 	 * Note: Cache records are persistent, once created they remain in place forever.
304 	 * Only the update-data is flushed from time to time.
305 	 */
306 	if (updcache_keyofs == -1) {
307 		updcache = xtreeNew(strcasecmp);
308 		updcache_keyofs = strlen(rrddir);
309 	}
310 	updcachekey = filedir + updcache_keyofs;
311 	handle = xtreeFind(updcache, updcachekey);
312 	if (handle == xtreeEnd(updcache)) {
313 		if (!template) template = setup_template(creparams);
314 		if (!template) {
315 			errprintf("BUG: setup_template() returns NULL! host=%s,test=%s,cp[0]=%s, cp[1]=%s\n",
316 				  hostname, testname,
317 				  (creparams[0] ? creparams[0] : "NULL"),
318 				  (creparams[1] ? creparams[1] : "NULL"));
319 			return -1;
320 		}
321 		cacheitem = (updcacheitem_t *)calloc(1, sizeof(updcacheitem_t));
322 		cacheitem->key = strdup(updcachekey);
323 		cacheitem->tpl = template;
324 		xtreeAdd(updcache, cacheitem->key, cacheitem);
325 	}
326 	else {
327 		cacheitem = (updcacheitem_t *)xtreeData(updcache, handle);
328 		if (!template) template = cacheitem->tpl;
329 	}
330 
331 	/* If the RRD file doesn't exist, create it immediately */
332 	if (stat(filedir, &st) == -1) {
333 		char **rrdcreate_params, **rrddefinitions;
334 		int rrddefcount, i;
335 		char *rrakey = NULL;
336 		char stepsetting[10];
337 		int havestepsetting = 0, fixcount = 2;
338 
339 		dbgprintf("Creating rrd %s\n", filedir);
340 
341 		/* How many parameters did we get? */
342 		for (pcount = 0; (creparams[pcount]); pcount++);
343 
344 		/* Add the RRA definitions to the create parameter set */
345 		if (pollinterval != DEFAULT_RRD_INTERVAL) {
346 			rrakey = (char *)malloc(strlen(testname) + 10);
347 			sprintf(rrakey, "%s/%d", testname, pollinterval);
348 		}
349 		sprintf(stepsetting, "%d", pollinterval);
350 
351 		rrddefinitions = get_rrd_definition((rrakey ? rrakey : testname), &rrddefcount);
352 		rrdcreate_params = (char **)calloc(4 + pcount + rrddefcount + 1, sizeof(char *));
353 		rrdcreate_params[0] = "rrdcreate";
354 		rrdcreate_params[1] = filedir;
355 
356 		/* Is there already a step-setting in the rrddefinitions? */
357 		for (i=0; (!havestepsetting && (i < rrddefcount)); i++)
358 			havestepsetting = ((strcmp(rrddefinitions[i], "-s") == 0) || (strcmp(rrddefinitions[i], "--step") == 0));
359 		if (!havestepsetting) {
360 			rrdcreate_params[2] = "-s";
361 			rrdcreate_params[3] = stepsetting;
362 			fixcount = 4;
363 		}
364 
365 		for (i=0; (i < pcount); i++)
366 			rrdcreate_params[fixcount+i]      = creparams[i];
367 		for (i=0; (i < rrddefcount); i++, pcount++)
368 			rrdcreate_params[fixcount+pcount] = rrddefinitions[i];
369 
370 		if (debug) {
371 			for (i = 0; (rrdcreate_params[i]); i++) {
372 				dbgprintf("RRD create param %02d: '%s'\n", i, rrdcreate_params[i]);
373 			}
374 		}
375 
376 		/*
377 		 * Ugly! RRDtool uses getopt() for parameter parsing, so
378 		 * we MUST reset this before every call.
379 		 */
380 		optind = opterr = 0; rrd_clear_error();
381 		result = rrd_create(4+pcount, rrdcreate_params);
382 		xfree(rrdcreate_params);
383 		if (rrakey) xfree(rrakey);
384 
385 		if (result != 0) {
386 			errprintf("RRD error creating %s: %s\n", filedir, rrd_get_error());
387 			MEMUNDEFINE(filedir);
388 			MEMUNDEFINE(rrdvalues);
389 			return 1;
390 		}
391 	}
392 
393 	updtime = atoi(rrdvalues);
394 	if (cacheitem->valcount > 0) {
395 		/* Check for duplicate updates */
396 
397 		if (cacheitem->updseq[cacheitem->valcount-1] == seq) {
398 			/*
399 			 * This is usually caused by a configuration error,
400 			 * e.g. two PORT settings in analysis.cfg that
401 			 * use the same TRACK string.
402 			 * Can also be two web checks using the same URL, but
403 			 * with different POST data.
404 			 */
405 			dbgprintf("%s/%s: Error - ignored duplicate update for message sequence %d\n", hostname, rrdfn, seq);
406 			MEMUNDEFINE(filedir);
407 			MEMUNDEFINE(rrdvalues);
408 			return 0;
409 		}
410 		else if (cacheitem->updtime[cacheitem->valcount-1] > updtime) {
411 			dbgprintf("%s/%s: Error - RRD time goes backwards: Now=%d, previous=%d\n", hostname, rrdfn, (int) updtime, (int)cacheitem->updtime[cacheitem->valcount-1]);
412 			MEMUNDEFINE(filedir);
413 			MEMUNDEFINE(rrdvalues);
414 			return 0;
415 		}
416 		else if (cacheitem->updtime[cacheitem->valcount-1] == updtime) {
417 			int identical = (strcmp(rrdvalues, cacheitem->vals[cacheitem->valcount-1]) == 0);
418 
419 			if (!identical) {
420 				int i;
421 
422 				errprintf("%s/%s: Bug - duplicate RRD data with same timestamp %d, different data\n",
423 					  hostname, rrdfn, (int) updtime);
424 
425 				for (i=0; (i < cacheitem->valcount); i++)
426 					dbgprintf("Val %d: Seq %d: %s\n", i, cacheitem->updseq[i], cacheitem->vals[i]);
427 				dbgprintf("NewVal: Seq %d: %s\n", seq, rrdvalues);
428 			}
429 			else {
430 				dbgprintf("%s/%s: Ignored duplicate (and identical) update timestamped %d\n", hostname, rrdfn, (int) updtime);
431 			}
432 
433 			MEMUNDEFINE(filedir);
434 			MEMUNDEFINE(rrdvalues);
435 			return 0;
436 		}
437 	}
438 
439 
440 	/*
441 	 * Match the RRD data against any DS client-configuration modifiers.
442 	 */
443 	modifymsg = check_rrdds_thresholds(hostname, classname, pagepaths, rrdfn, ((rrdtpldata_t *)template)->dsnames, rrdvalues);
444 	if (modifymsg) combo_add(modifymsg);
445 
446 	/*
447 	 * See if we want the data to go to an external handler.
448 	 */
449 	if (processorstream) {
450 		int i, n;
451 
452 		n = fprintf(processorstream, "%s %s %s", ((rrdtpldata_t *)template)->template, rrdvalues, hostname);
453 		for (i=0; ((n >= 0) && fnparams[i]); i++) n = fprintf(processorstream, " %s", fnparams[i]);
454 		if (n >= 0) n = fprintf(processorstream, "\n");
455 		if (n >= 0) fflush(processorstream);
456 
457 		if (n == -1) {
458 			errprintf("Ext-processor write failed: %s\n", strerror(errno));
459 			shutdown_extprocessor();
460 		}
461 	}
462 
463 	/* Are we actually handling the writing of RRD files? */
464 	if (no_rrd) return 0;
465 
466 	/*
467 	 * We cannot just cache data every time because then after CACHESZ updates
468 	 * of each RRD, we will flush all of the data at once (all of the caches
469 	 * fill at the same speed); this would result in huge load-spikes every
470 	 * rrdinterval*CACHESZ seconds.
471 	 *
472 	 * So to smooth the load, we force the update through for every CACHESZ
473 	 * updates, regardless of how much is in the cache. This gives us a steady
474 	 * (although slightly higher) load.
475 	 */
476 	if (use_rrd_cache && (++callcounter < CACHESZ)) {
477 		if (cacheitem && (cacheitem->valcount < CACHESZ)) {
478 			cacheitem->updseq[cacheitem->valcount] = seq;
479 			cacheitem->updtime[cacheitem->valcount] = updtime;
480 			cacheitem->vals[cacheitem->valcount] = strdup(rrdvalues);
481 			cacheitem->valcount += 1;
482 			MEMUNDEFINE(filedir);
483 			MEMUNDEFINE(rrdvalues);
484 			return 0;
485 		}
486 	}
487 	else callcounter = 0;
488 
489 	/* At this point, we will commit the update to disk */
490 	result = flush_cached_updates(cacheitem, rrdvalues);
491 	if (result != 0) {
492 		char *msg = rrd_get_error();
493 
494 		if (strstr(msg, "(minimum one second step)") != NULL) {
495 			dbgprintf("RRD error updating %s from %s: %s\n",
496 				  filedir, (senderip ? senderip : "unknown"), msg);
497 		}
498 		else {
499 			errprintf("RRD error updating %s from %s: %s\n",
500 				  filedir, (senderip ? senderip : "unknown"), msg);
501 		}
502 
503 		MEMUNDEFINE(filedir);
504 		MEMUNDEFINE(rrdvalues);
505 		return 2;
506 	}
507 
508 	MEMUNDEFINE(filedir);
509 	MEMUNDEFINE(rrdvalues);
510 
511 	return 0;
512 }
513 
rrdcacheflushall(void)514 void rrdcacheflushall(void)
515 {
516 	xtreePos_t handle;
517 	updcacheitem_t *cacheitem;
518 
519 	if (updcache_keyofs == -1) return; /* No cache */
520 
521 	for (handle = xtreeFirst(updcache); (handle != xtreeEnd(updcache)); handle = xtreeNext(updcache, handle)) {
522 		cacheitem = (updcacheitem_t *) xtreeData(updcache, handle);
523 		if (cacheitem->valcount > 0) {
524 			sprintf(filedir, "%s%s", rrddir, cacheitem->key);
525 			flush_cached_updates(cacheitem, NULL);
526 		}
527 	}
528 }
529 
rrdcacheflushhost(char * hostname)530 void rrdcacheflushhost(char *hostname)
531 {
532 	xtreePos_t handle;
533 	updcacheitem_t *cacheitem;
534 	flushtree_t *flushitem;
535 	int keylen;
536 	time_t now = gettimer();
537 
538 	if (updcache_keyofs == -1) return;
539 
540 	/* If we get a full path for the key, skip the leading rrddir */
541 	if (strncmp(hostname, rrddir, updcache_keyofs) == 0) hostname += updcache_keyofs;
542 	keylen = strlen(hostname);
543 
544 	if (!have_flushtree) {
545 		flushtree = xtreeNew(strcasecmp);
546 		have_flushtree = 1;
547 	}
548 	handle = xtreeFind(flushtree, hostname);
549 	if (handle == xtreeEnd(flushtree)) {
550 		flushitem = (flushtree_t *)calloc(1, sizeof(flushtree_t));
551 		flushitem->hostname = strdup(hostname);
552 		flushitem->flushtime = 0;
553 		xtreeAdd(flushtree, flushitem->hostname, flushitem);
554 	}
555 	else {
556 		flushitem = (flushtree_t *) xtreeData(flushtree, handle);
557 	}
558 
559 	if ((flushitem->flushtime + 60) >= now) {
560 		dbgprintf("Flush of '%s' skipped, too soon\n", hostname);
561 		return;
562 	}
563 	flushitem->flushtime = now;
564 
565 	handle = xtreeFirst(updcache);
566 	while (handle != xtreeEnd(updcache)) {
567 		cacheitem = (updcacheitem_t *) xtreeData(updcache, handle);
568 
569 		switch (strncasecmp(cacheitem->key, hostname, keylen)) {
570 		  case 1 :
571 			handle = xtreeEnd(updcache); break;
572 
573 		  case 0:
574 			if (cacheitem->valcount > 0) {
575 				dbgprintf("Flushing cache '%s'\n", cacheitem->key);
576 				sprintf(filedir, "%s%s", rrddir, cacheitem->key);
577 				flush_cached_updates(cacheitem, NULL);
578 			}
579 			/* Fall through */
580 
581 		  default:
582 			handle = xtreeNext(updcache, handle);
583 			break;
584 		}
585 	}
586 }
587 
rrddatasets(char * hostname,char *** dsnames)588 static int rrddatasets(char *hostname, char ***dsnames)
589 {
590 	struct stat st;
591 
592 	int result;
593 	char *fetch_params[] = { "rrdfetch", filedir, "AVERAGE", "-s", "-30m", NULL };
594 	time_t starttime, endtime;
595 	unsigned long steptime, dscount;
596 	rrd_value_t *rrddata;
597 
598 	snprintf(filedir, sizeof(filedir)-1, "%s/%s/%s", rrddir, hostname, rrdfn);
599 	filedir[sizeof(filedir)-1] = '\0';
600 	if (stat(filedir, &st) == -1) return 0;
601 
602 	optind = opterr = 0; rrd_clear_error();
603 	result = rrd_fetch(5, fetch_params, &starttime, &endtime, &steptime, &dscount, dsnames, &rrddata);
604 	if (result == -1) {
605 		errprintf("Error while retrieving RRD dataset names from %s: %s\n",
606 			  filedir, rrd_get_error());
607 		return 0;
608 	}
609 
610 	free(rrddata);	/* No use for the actual data */
611 	return dscount;
612 }
613 
614 /* Include all of the sub-modules. */
615 #include "rrd/do_xymongen.c"
616 #include "rrd/do_xymonnet.c"
617 #include "rrd/do_xymonproxy.c"
618 #include "rrd/do_xymond.c"
619 #include "rrd/do_citrix.c"
620 #include "rrd/do_ntpstat.c"
621 
622 #include "rrd/do_memory.c"	/* Must go before do_la.c */
623 #include "rrd/do_la.c"
624 
625 /*
626  * From hobbit-perl-client http://sourceforge.net/projects/hobbit-perl-cl/
627  * version 1.15 Oct. 17 2006 (downloaded on 2008-12-01).
628  *
629  * Include file for netapp.pl dbcheck.pl and beastat.pl scripts
630  * do_fd_lib.c contains some function used by the other library
631  *
632  * Must go before "do_disk.c"
633  */
634 #include "rrd/do_fd_lib.c"
635 #include "rrd/do_netapp.c"
636 #include "rrd/do_beastat.c"
637 #include "rrd/do_dbcheck.c"
638 
639 
640 #include "rrd/do_disk.c"
641 #include "rrd/do_netstat.c"
642 #include "rrd/do_vmstat.c"
643 #include "rrd/do_iostat.c"
644 #include "rrd/do_ifstat.c"
645 
646 #include "rrd/do_apache.c"
647 #include "rrd/do_sendmail.c"
648 #include "rrd/do_mailq.c"
649 #include "rrd/do_iishealth.c"
650 #include "rrd/do_temperature.c"
651 
652 #include "rrd/do_net.c"
653 
654 #include "rrd/do_ncv.c"
655 #include "rrd/do_external.c"
656 #include "rrd/do_filesizes.c"
657 #include "rrd/do_counts.c"
658 #include "rrd/do_trends.c"
659 
660 #include "rrd/do_ifmib.c"
661 #include "rrd/do_snmpmib.c"
662 
663 /* z/OS, z/VM, z/VME stuff */
664 #include "rrd/do_paging.c"
665 #include "rrd/do_mdc.c"
666 #include "rrd/do_cics.c"
667 #include "rrd/do_getvis.c"
668 #include "rrd/do_asid.c"
669 
670 
671 /*
672  * From devmon http://sourceforge.net/projects/devmon/
673  * version 0.3.0 (downloaded on 2008-12-01).
674  */
675 #include "rrd/do_devmon.c"
676 
677 
update_rrd(char * hostname,char * testname,char * msg,time_t tstamp,char * sender,xymonrrd_t * ldef,char * classname,char * pagepaths)678 void update_rrd(char *hostname, char *testname, char *msg, time_t tstamp, char *sender, xymonrrd_t *ldef, char *classname, char *pagepaths)
679 {
680 	char *id;
681 
682 	MEMDEFINE(rrdvalues);
683 
684 	if (ldef) id = ldef->xymonrrdname; else id = testname;
685 	senderip = sender;
686 
687 	if      (strcmp(id, "bbgen") == 0)       do_xymongen_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
688 	else if (strcmp(id, "xymongen") == 0)    do_xymongen_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
689 	else if (strcmp(id, "bbtest") == 0)      do_xymonnet_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
690 	else if (strcmp(id, "xymonnet") == 0)    do_xymonnet_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
691 	else if (strcmp(id, "bbproxy") == 0)     do_xymonproxy_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
692 	else if (strcmp(id, "xymonproxy") == 0)  do_xymonproxy_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
693 	else if (strcmp(id, "hobbitd") == 0)     do_xymond_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
694 	else if (strcmp(id, "xymond") == 0)      do_xymond_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
695 	else if (strcmp(id, "citrix") == 0)      do_citrix_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
696 	else if (strcmp(id, "ntpstat") == 0)     do_ntpstat_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
697 
698 	else if (strcmp(id, "la") == 0)          do_la_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
699 	else if (strcmp(id, "disk") == 0)        do_disk_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
700 	else if (strcmp(id, "memory") == 0)      do_memory_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
701 	else if (strcmp(id, "netstat") == 0)     do_netstat_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
702 	else if (strcmp(id, "vmstat") == 0)      do_vmstat_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
703 	else if (strcmp(id, "iostat") == 0)      do_iostat_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
704 	else if (strcmp(id, "ifstat") == 0)      do_ifstat_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
705 
706 	/* These two come from the filerstats2bb.pl script. The reports are in disk-format */
707 	else if (strcmp(id, "inode") == 0)       do_disk_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
708 	else if (strcmp(id, "qtree") == 0)       do_disk_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
709 
710 	else if (strcmp(id, "apache") == 0)      do_apache_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
711 	else if (strcmp(id, "sendmail") == 0)    do_sendmail_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
712 	else if (strcmp(id, "mailq") == 0)       do_mailq_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
713 	else if (strcmp(id, "iishealth") == 0)   do_iishealth_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
714 	else if (strcmp(id, "temperature") == 0) do_temperature_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
715 
716 	else if (strcmp(id, "ncv") == 0)         do_ncv_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
717 	else if (strcmp(id, "tcp") == 0)         do_net_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
718 
719 	else if (strcmp(id, "filesizes") == 0)   do_filesizes_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
720 	else if (strcmp(id, "proccounts") == 0)  do_counts_rrd("processes", hostname, testname, classname, pagepaths, msg, tstamp);
721 	else if (strcmp(id, "portcounts") == 0)  do_counts_rrd("ports", hostname, testname, classname, pagepaths, msg, tstamp);
722 	else if (strcmp(id, "linecounts") == 0)  do_derives_rrd("lines", hostname, testname, classname, pagepaths, msg, tstamp);
723 	else if (strcmp(id, "deltacounts") == 0) do_counts_rrd("deltalines", hostname, testname, classname, pagepaths, msg, tstamp);
724 	else if (strcmp(id, "trends") == 0)      do_trends_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
725 
726 	else if (strcmp(id, "ifmib") == 0)       do_ifmib_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
727 	else if (is_snmpmib_rrd(id))             do_snmpmib_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
728 
729 	/* z/OS, z/VSE, z/VM from Rich Smrcina */
730 	else if (strcmp(id, "paging") == 0)      do_paging_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
731 	else if (strcmp(id, "mdc") == 0)         do_mdc_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
732 	else if (strcmp(id, "cics") == 0)        do_cics_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
733 	else if (strcmp(id, "getvis") == 0)      do_getvis_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
734 	else if (strcmp(id, "maxuser") == 0)     do_asid_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
735 	else if (strcmp(id, "nparts") == 0)      do_asid_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
736 
737 	/*
738 	 * These are from the hobbit-perl-client
739 	 * NetApp check for netapp.pl, dbcheck.pl and beastat.pl scripts
740 	 */
741 	else if (strcmp(id, "xtstats") == 0)     do_netapp_extrastats_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
742 	else if (strcmp(id, "quotas") == 0)      do_disk_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
743 	else if (strcmp(id, "snapshot") == 0)    do_disk_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
744 	else if (strcmp(id, "TblSpace") == 0)    do_disk_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
745 	else if (strcmp(id, "stats") == 0)       do_netapp_stats_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
746 	else if (strcmp(id, "ops") == 0)         do_netapp_ops_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
747 	else if (strcmp(id, "cifs") == 0)        do_netapp_cifs_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
748 	else if (strcmp(id, "snaplist") == 0)    do_netapp_snaplist_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
749 	else if (strcmp(id, "snapmirr") == 0)    do_netapp_snapmirror_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
750 	else if (strcmp(id, "HitCache") == 0)    do_dbcheck_hitcache_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
751 	else if (strcmp(id, "Session") == 0)     do_dbcheck_session_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
752 	else if (strcmp(id, "RollBack") == 0)    do_dbcheck_rb_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
753 	else if (strcmp(id, "InvObj") == 0)      do_dbcheck_invobj_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
754 	else if (strcmp(id, "MemReq") == 0)      do_dbcheck_memreq_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
755 	else if (strcmp(id, "JVM") == 0)         do_beastat_jvm_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
756 	else if (strcmp(id, "JMS") == 0)         do_beastat_jms_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
757 	else if (strcmp(id, "JTA") == 0)         do_beastat_jta_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
758 	else if (strcmp(id, "ExecQueue") == 0)   do_beastat_exec_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
759 	else if (strcmp(id, "JDBCConn") == 0)    do_beastat_jdbc_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
760 
761 	/*
762 	 * This is from the devmon SNMP collector
763 	 */
764 	else if (strcmp(id, "devmon") == 0)      do_devmon_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
765 
766 	else if (extids && exthandler) {
767 		int i;
768 
769 		for (i=0; (extids[i] && strcmp(extids[i], id)); i++) ;
770 
771 		if (extids[i]) do_external_rrd(hostname, testname, classname, pagepaths, msg, tstamp);
772 	}
773 
774 	senderip = NULL;
775 
776 	MEMUNDEFINE(rrdvalues);
777 }
778 
779