1 /*----------------------------------------------------------------------------*/
2 /* Xymon message daemon.                                                      */
3 /*                                                                            */
4 /* Client backend module                                                      */
5 /* This file has routines that load the xymond_client configuration and       */
6 /* finds the rules relevant for a particular test when applied.               */
7 /*                                                                            */
8 /* Copyright (C) 2005-2011 Henrik Storner <henrik@hswn.dk>                    */
9 /* "PORT" handling (C) Mirko Saam                                             */
10 /*                                                                            */
11 /* This program is released under the GNU General Public License (GPL),       */
12 /* version 2. See the file "COPYING" for details.                             */
13 /*                                                                            */
14 /*----------------------------------------------------------------------------*/
15 
16 static char rcsid[] = "$Id: client_config.c 8068 2019-07-23 14:46:23Z jccleaver $";
17 
18 #include <stdio.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <sys/time.h>
23 #include <signal.h>
24 #include <time.h>
25 #include <ctype.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <limits.h>
29 #include <errno.h>
30 
31 #include <pcre.h>
32 
33 #include "libxymon.h"
34 #include "client_config.h"
35 
36 typedef struct exprlist_t {
37 	char *pattern;
38 	pcre *exp;
39 	struct exprlist_t *next;
40 } exprlist_t;
41 
42 typedef struct c_load_t {
43 	float warnlevel, paniclevel;
44 } c_load_t;
45 
46 typedef struct c_uptime_t {
47 	int recentlimit, ancientlimit, color;
48 } c_uptime_t;
49 
50 typedef struct c_clock_t {
51 	int maxdiff, color;
52 } c_clock_t;
53 
54 typedef struct c_disk_t {
55 	exprlist_t *fsexp;
56 	long warnlevel, paniclevel;
57 	int abswarn, abspanic;
58 	int dmin, dmax, dcount;
59 	int color;
60 	int ignored;
61 } c_disk_t;
62 
63 typedef struct c_inode_t {
64 	exprlist_t *fsexp;
65 	long warnlevel, paniclevel;
66 	int abswarn, abspanic;
67 	int imin, imax, icount;
68 	int color;
69 	int ignored;
70 } c_inode_t;
71 
72 typedef struct c_mem_t {
73 	enum { C_MEM_PHYS, C_MEM_SWAP, C_MEM_ACT } memtype;
74 	int warnlevel, paniclevel;
75 } c_mem_t;
76 
77 typedef struct c_zos_mem_t {
78 	enum { C_MEM_CSA, C_MEM_ECSA, C_MEM_SQA, C_MEM_ESQA } zos_memtype;
79 	int warnlevel, paniclevel;
80 } c_zos_mem_t;
81 
82 typedef struct c_zvse_vsize_t {
83 	int warnlevel, paniclevel;
84 } c_zvse_vsize_t;
85 
86 typedef struct c_zvse_getvis_t {
87 	exprlist_t *partid;
88 	int warnlevel, paniclevel;
89 	int anywarnlevel, anypaniclevel;
90 } c_zvse_getvis_t;
91 
92 typedef struct c_cics_t {
93 	exprlist_t *applid;  /* CICS Application Identifier */
94 	int dsawarnlevel, dsapaniclevel;
95 	int edsawarnlevel, edsapaniclevel;
96 } c_cics_t;
97 
98 typedef struct c_asid_t {
99         enum { C_ASID_MAXUSER, C_ASID_NPARTS } asidtype;
100         int warnlevel, paniclevel;
101 } c_asid_t;
102 
103 typedef struct c_proc_t {
104 	exprlist_t *procexp;
105 	int pmin, pmax, pcount;
106 	int color;
107 } c_proc_t;
108 
109 typedef struct c_log_t {
110 	exprlist_t *logfile;
111 	exprlist_t *matchexp, *matchone, *ignoreexp;
112 	int color;
113 } c_log_t;
114 
115 typedef struct c_paging_t {
116 	int warnlevel, paniclevel;
117 } c_paging_t;
118 
119 #define FCHK_NOEXIST  (1 << 0)
120 #define FCHK_TYPE     (1 << 1)
121 #define FCHK_MODE     (1 << 2)
122 #define FCHK_MINLINKS (1 << 3)
123 #define FCHK_MAXLINKS (1 << 4)
124 #define FCHK_EQLLINKS (1 << 5)
125 #define FCHK_MINSIZE  (1 << 6)
126 #define FCHK_MAXSIZE  (1 << 7)
127 #define FCHK_EQLSIZE  (1 << 8)
128 #define FCHK_OWNERID  (1 << 10)
129 #define FCHK_OWNERSTR (1 << 11)
130 #define FCHK_GROUPID  (1 << 12)
131 #define FCHK_GROUPSTR (1 << 13)
132 #define FCHK_CTIMEMIN (1 << 16)
133 #define FCHK_CTIMEMAX (1 << 17)
134 #define FCHK_CTIMEEQL (1 << 18)
135 #define FCHK_MTIMEMIN (1 << 19)
136 #define FCHK_MTIMEMAX (1 << 20)
137 #define FCHK_MTIMEEQL (1 << 21)
138 #define FCHK_ATIMEMIN (1 << 22)
139 #define FCHK_ATIMEMAX (1 << 23)
140 #define FCHK_ATIMEEQL (1 << 24)
141 #define FCHK_MD5      (1 << 25)
142 #define FCHK_SHA1     (1 << 26)
143 #define FCHK_SHA256   (1 << 27)
144 #define FCHK_SHA512   (1 << 28)
145 #define FCHK_SHA224   (1 << 29)
146 #define FCHK_SHA384   (1 << 30)
147 #define FCHK_RMD160   (1 << 31)
148 
149 #define CHK_OPTIONAL  (1 << 0)
150 #define CHK_TRACKIT   (1 << 1)
151 
152 typedef struct c_file_t {
153 	exprlist_t *filename;
154 	int color;
155 	int ftype;
156 	off_t minsize, maxsize, eqlsize;
157 	unsigned int minlinks, maxlinks, eqllinks;
158 	unsigned int fmode;
159 	int ownerid, groupid;
160 	char *ownerstr, *groupstr;
161 	unsigned int minctimedif, maxctimedif, ctimeeql;
162 	unsigned int minmtimedif, maxmtimedif, mtimeeql;
163 	unsigned int minatimedif, maxatimedif, atimeeql;
164 	char *md5hash, *sha1hash, *sha256hash, *sha512hash, *sha224hash, *sha384hash, *rmd160hash;
165 } c_file_t;
166 
167 typedef struct c_dir_t {
168 	exprlist_t *filename;
169 	int color;
170 	unsigned long maxsize, minsize;
171 } c_dir_t;
172 
173 typedef struct c_port_t {
174 	exprlist_t *localexp;
175 	exprlist_t *exlocalexp;
176 	exprlist_t *remoteexp;
177 	exprlist_t *exremoteexp;
178 	exprlist_t *stateexp;
179 	exprlist_t *exstateexp;
180 	int pmin, pmax, pcount;
181 	int color;
182 } c_port_t;
183 
184 typedef struct c_svc_t {
185 	exprlist_t *svcexp;
186 	exprlist_t *stateexp;
187 	exprlist_t *startupexp;
188 	char *svcname, *startup, *state;
189 	int scount;
190 	int color;
191 } c_svc_t;
192 
193 #define MIBCHK_MINVALUE  (1 << 0)
194 #define MIBCHK_MAXVALUE  (1 << 1)
195 #define MIBCHK_MATCH     (1 << 2)
196 typedef struct c_mibval_t {
197 	exprlist_t *mibvalexp;  /* Key composed of the mib name and the value name */
198 	exprlist_t *keyexp;     /* Match pattern for the mib table key */
199 	int color;
200 	long minval, maxval;
201 	exprlist_t *matchexp;
202 
203 	/*
204 	 * For optimization, we build a tree of c_rule_t pointers, indexed by a key
205 	 * which is combined from the mib-, key- and value-names. This tree is updated
206 	 * and/or used whenever an actual lookup happens for the thresholds.
207 	 * So when doing a lookup, we first check to see if the combination is in the
208 	 * tree; if not, then we scan the list by matching against the keyexp pattern
209 	 * and update the tree with the result.
210 	 */
211 	int havetree;
212 	void * valdeftree;
213 } c_mibval_t;
214 
215 #define RRDDSCHK_GT     (1 << 0)
216 #define RRDDSCHK_GE     (1 << 1)
217 #define RRDDSCHK_LT     (1 << 2)
218 #define RRDDSCHK_LE     (1 << 3)
219 #define RRDDSCHK_EQ     (1 << 4)
220 #define RRDDSCHK_INTVL  (1 << 29)
221 typedef struct c_rrdds_t {
222 	exprlist_t *rrdkey;     /* Pattern match for filename of the RRD file */
223 	char *rrdds;            /* DS name */
224 	char *column;           /* Status column modified by this check */
225 	int color;
226 	/* For absolute min/max values of the data item */
227 	double limitval, limitval2;
228 } c_rrdds_t;
229 
230 
231 typedef struct c_mq_queue_t {
232 	exprlist_t *qmgrname, *qname;
233 	int warnlen, critlen;
234 	int warnage, critage;
235 } c_mq_queue_t;
236 
237 typedef struct c_mq_channel_t {
238 	exprlist_t *qmgrname, *chnname, *warnstates, *alertstates;
239 } c_mq_channel_t;
240 
241 typedef enum { C_LOAD, C_UPTIME, C_CLOCK, C_DISK, C_INODE, C_MEM, C_PROC, C_LOG, C_FILE, C_DIR, C_PORT, C_SVC, C_CICS, C_PAGING, C_MEM_GETVIS, C_MEM_VSIZE, C_ASID, C_RRDDS, C_MQ_QUEUE, C_MQ_CHANNEL, C_MIBVAL } ruletype_t;
242 
243 typedef struct c_rule_t {
244 	exprlist_t *hostexp;
245 	exprlist_t *exhostexp;
246 	exprlist_t *pageexp;
247 	exprlist_t *expageexp;
248 	exprlist_t *dgexp;
249 	exprlist_t *exdgexp;
250 	exprlist_t *classexp;
251 	exprlist_t *exclassexp;
252 	char *timespec, *extimespec, *statustext, *rrdidstr, *groups;
253 	ruletype_t ruletype;
254 	int cfid;
255 	uint32_t flags;
256 	uint32_t chkflags;
257 	struct c_rule_t *next;
258 	union {
259 		c_load_t load;
260 		c_uptime_t uptime;
261 		c_clock_t clock;
262 		c_disk_t disk;
263 		c_inode_t inode;
264 		c_mem_t mem;
265 		c_zos_mem_t zos_mem;
266 		c_zvse_vsize_t zvse_vsize;
267 		c_zvse_getvis_t zvse_getvis;
268 		c_cics_t cics;
269 		c_asid_t asid;
270 		c_proc_t proc;
271 		c_log_t log;
272 		c_file_t fcheck;
273 		c_dir_t dcheck;
274 		c_port_t port;
275 		c_svc_t	svc;
276 		c_paging_t paging;
277 		c_mibval_t mibval;
278 		c_rrdds_t rrdds;
279 		c_mq_queue_t mqqueue;
280 		c_mq_channel_t mqchannel;
281 	} rule;
282 } c_rule_t;
283 
284 static c_rule_t *rulehead = NULL;
285 static c_rule_t *ruletail = NULL;
286 static exprlist_t *exprhead = NULL;
287 
288 /* ruletree is a tree indexed by hostname of the rules. */
289 typedef struct ruleset_t {
290 	c_rule_t *rule;
291 	struct ruleset_t *next;
292 } ruleset_t;
293 static int havetree = 0;
294 static void * ruletree;
295 
296 
filesize_value(char * s)297 static off_t filesize_value(char *s)
298 {
299 	/* s is the size in BYTES */
300 	char *modifier;
301 	off_t result;
302 
303 	modifier = (s + strspn(s, " 0123456789"));
304 
305 #ifdef _LARGEFILE_SOURCE
306 	result = (off_t) str2ll(s, NULL);
307 #else
308 	result = (off_t) atol(s);
309 #endif
310 
311 	switch (*modifier) {
312 	  case 'K': case 'k':
313 		result = (result << 10);
314 		break;
315 
316 	  case 'M': case 'm':
317 		result = (result << 20);
318 		break;
319 
320 	  case 'G': case 'g':
321 		result = (result << 30);
322 		break;
323 
324 	  case 'T': case 't':
325 		result = (result << 40);
326 		break;
327 
328 	  default:
329 		break;
330 	}
331 
332 	return result;
333 }
334 
ruleset(char * hostname,char * pagename,char * classname)335 static ruleset_t *ruleset(char *hostname, char *pagename, char *classname)
336 {
337 	/*
338 	 * This routine manages a list of rules that apply to a particular host.
339 	 *
340 	 * We maintain a tree indexed by hostname. Each node in the tree contains
341 	 * a list of c_rule_t records, which point to individual rules in the full
342 	 * list of rules. So instead of walking the entire list of rules for all hosts,
343 	 * we can just go through those rules that are relevant for a given host.
344 	 * This should speed up client-rule matching tremendously, since all of
345 	 * the expensive pagename/hostname matches are only performed initially
346 	 * when the list of rules for the host is decided.
347 	 */
348 	xtreePos_t handle;
349 	c_rule_t *rwalk;
350 	ruleset_t *head, *tail, *itm;
351 	char *pagenamecopy, *pgtok;
352 	int pgmatchres, pgexclres;
353 
354 	handle = xtreeFind(ruletree, hostname);
355 	if (handle != xtreeEnd(ruletree)) {
356 		/* We have the tree for this host */
357 		return (ruleset_t *)xtreeData(ruletree, handle);
358 	}
359 
360 	pagenamecopy = strdup(pagename);
361 
362 	/* We must build the list of rules for this host */
363 	head = tail = NULL;
364 	for (rwalk = rulehead; (rwalk); rwalk = rwalk->next) {
365 		if (rwalk->exclassexp && namematch(classname, rwalk->exclassexp->pattern, rwalk->exclassexp->exp)) continue;
366 		if (rwalk->classexp && !namematch(classname, rwalk->classexp->pattern, rwalk->classexp->exp)) continue;
367 		if (rwalk->exhostexp && namematch(hostname, rwalk->exhostexp->pattern, rwalk->exhostexp->exp)) continue;
368 		if (rwalk->hostexp && !namematch(hostname, rwalk->hostexp->pattern, rwalk->hostexp->exp)) continue;
369 		if (rwalk->exdgexp && namematch(hostname, rwalk->exdgexp->pattern, rwalk->exdgexp->exp)) continue;
370 		if (rwalk->dgexp && !namematch(hostname, rwalk->dgexp->pattern, rwalk->dgexp->exp)) continue;
371 
372 		pgmatchres = pgexclres = -1;
373 		pgtok = strtok(pagenamecopy, ",");
374 		while (pgtok) {
375 			if (rwalk->pageexp && (pgmatchres != 1))
376 				pgmatchres = (namematch(pgtok, rwalk->pageexp->pattern, rwalk->pageexp->exp) ? 1 : 0);
377 
378 			if (rwalk->expageexp && (pgexclres != 1))
379 				pgexclres = (namematch(pgtok, rwalk->expageexp->pattern, rwalk->expageexp->exp) ? 1 : 0);
380 
381 			pgtok = strtok(NULL, ",");
382 		}
383 		if (pgexclres == 1) continue;
384 		if (pgmatchres == 0) continue;
385 
386 		/* All criteria match - add this rule to the list of rules for this host */
387 		itm = (ruleset_t *)calloc(1, sizeof(ruleset_t));
388 		itm->rule = rwalk;
389 		itm->next = NULL;
390 		if (head == NULL) {
391 			head = tail = itm;
392 		}
393 		else {
394 			tail->next = itm;
395 			tail = itm;
396 		}
397 	}
398 
399 	/* Add the list to the tree */
400 	xtreeAdd(ruletree, strdup(hostname), head);
401 
402 	xfree(pagenamecopy);
403 
404 	return head;
405 }
406 
setup_expr(char * ptn,int multiline)407 static exprlist_t *setup_expr(char *ptn, int multiline)
408 {
409 	exprlist_t *newitem = (exprlist_t *)calloc(1, sizeof(exprlist_t));
410 
411 	newitem->pattern = strdup(ptn);
412 	if (*ptn == '%') {
413 		if (multiline)
414 			newitem->exp = multilineregex(ptn+1);
415 		else
416 			newitem->exp = compileregex(ptn+1);
417 	}
418 	newitem->next = exprhead;
419 	exprhead = newitem;
420 
421 	return newitem;
422 }
423 
setup_rule(ruletype_t ruletype,exprlist_t * curhost,exprlist_t * curexhost,exprlist_t * curpage,exprlist_t * curexpage,exprlist_t * curdg,exprlist_t * curexdg,exprlist_t * curclass,exprlist_t * curexclass,char * curtime,char * curextime,char * curtext,char * curgroup,int cfid)424 static c_rule_t *setup_rule(ruletype_t ruletype,
425 			    exprlist_t *curhost, exprlist_t *curexhost,
426 			    exprlist_t *curpage, exprlist_t *curexpage,
427 			    exprlist_t *curdg, exprlist_t *curexdg,
428 			    exprlist_t *curclass, exprlist_t *curexclass,
429 			    char *curtime, char *curextime, char *curtext, char *curgroup,
430 			    int cfid)
431 {
432 	c_rule_t *newitem = (c_rule_t *)calloc(1, sizeof(c_rule_t));
433 	if (ruletail) { ruletail->next = newitem; ruletail = newitem; }
434 	else rulehead = ruletail = newitem;
435 
436 	newitem->ruletype = ruletype;
437 	newitem->hostexp = curhost;
438 	newitem->exhostexp = curexhost;
439 	newitem->pageexp = curpage;
440 	newitem->expageexp = curexpage;
441 	newitem->dgexp = curdg;
442 	newitem->exdgexp = curexdg;
443 	newitem->classexp = curclass;
444 	newitem->exclassexp = curexclass;
445 	if (curtime) newitem->timespec = strdup(curtime);
446 	if (curextime) newitem->extimespec = strdup(curextime);
447 	if (curtext) newitem->statustext = strdup(curtext);
448 	if (curgroup) newitem->groups = strdup(curgroup);
449 	newitem->cfid = cfid;
450 
451 	return newitem;
452 }
453 
454 
isqual(char * token)455 static int isqual(char *token)
456 {
457 	if (!token) return 1;
458 
459 	if ( (strncasecmp(token, "HOST=", 5) == 0)		||
460 	     (strncasecmp(token, "EXHOST=", 7) == 0)		||
461 	     (strncasecmp(token, "PAGE=", 5) == 0)		||
462 	     (strncasecmp(token, "EXPAGE=", 7) == 0)		||
463 	     (strncasecmp(token, "DISPLAYGROUP=", 13) == 0)	||
464 	     (strncasecmp(token, "EXDISPLAYGROUP=", 15) == 0)	||
465 	     (strncasecmp(token, "CLASS=", 6) == 0)		||
466 	     (strncasecmp(token, "EXCLASS=", 8) == 0)		||
467 	     (strncasecmp(token, "TEXT=", 5) == 0)		||
468 	     (strncasecmp(token, "GROUP=", 6) == 0)		||
469 	     (strncasecmp(token, "TIME=", 5) == 0)		||
470 	     (strncasecmp(token, "EXTIME=", 7) == 0)		) return 1;
471 
472 	return 0;
473 }
474 
ftypestr(unsigned int ftype)475 static char *ftypestr(unsigned int ftype)
476 {
477 	if      (ftype == S_IFSOCK) return "socket";
478 	else if (ftype == S_IFREG)  return "file";
479 	else if (ftype == S_IFBLK)  return "block";
480 	else if (ftype == S_IFCHR)  return "char";
481 	else if (ftype == S_IFDIR)  return "dir";
482 	else if (ftype == S_IFIFO)  return "fifo";
483 	else if (ftype == S_IFLNK)  return "symlink";
484 
485 	return "";
486 }
487 
488 static char *grouplist = NULL;
clearalertgroups(void)489 void clearalertgroups(void)
490 {
491 	if (grouplist) xfree(grouplist);
492 }
493 
getalertgroups(void)494 char *getalertgroups(void)
495 {
496 	if (grouplist) {
497 		*(grouplist + strlen(grouplist) - 1) = '\0';
498 		return grouplist+1;
499 	}
500 	else return NULL;
501 }
502 
addalertgroup(char * group)503 void addalertgroup(char *group)
504 {
505 	char *key;
506 	int curlen;
507 
508 	if (group == NULL) return;
509 
510 	key = (char *)malloc(strlen(group)+3);
511 	sprintf(key, ",%s,", group);
512 
513 	if (!grouplist) {
514 		grouplist = key;
515 		return;
516 	}
517 
518 	if (strstr(grouplist, key)) {
519 		xfree(key);
520 		return;
521 	}
522 
523 	curlen = strlen(grouplist);
524 	grouplist = (char *)realloc(grouplist, curlen + strlen(key) + 2);
525 	sprintf(grouplist + curlen, "%s,", key);
526 }
527 
load_client_config(char * configfn)528 int load_client_config(char *configfn)
529 {
530 	/* (Re)load the configuration file without leaking memory */
531 	static void *configfiles = NULL;
532 	char fn[PATH_MAX];
533 	FILE *fd;
534 	strbuffer_t *inbuf;
535 	char *tok;
536 	exprlist_t *curhost, *curpage, *curclass, *curexhost, *curexpage, *curexclass, *curdg, *curexdg;
537 	char *curtime, *curextime, *curtext, *curgroup;
538 	c_rule_t *currule = NULL;
539 	int cfid = 0;
540 
541 	MEMDEFINE(fn);
542 
543 	if (configfn) strcpy(fn, configfn); else sprintf(fn, "%s/etc/analysis.cfg", xgetenv("XYMONHOME"));
544 
545 	/* First check if there were no modifications at all */
546 	if (configfiles) {
547 		if (!stackfmodified(configfiles)){
548 			dbgprintf("No files modified, skipping reload of %s\n", fn);
549 			return 0;
550 		}
551 		else {
552 			stackfclist(&configfiles);
553 			configfiles = NULL;
554 		}
555 	}
556 
557 	fd = stackfopen(fn, "r", &configfiles);
558 	if (!fd) {
559 		errprintf("Cannot load config file %s: %s\n", fn, strerror(errno));
560 		MEMUNDEFINE(fn);
561 		return 0;
562 	}
563 
564 	/* First free the old list, if any */
565 	while (rulehead) {
566 		c_rule_t *tmp = rulehead;
567 		rulehead = rulehead->next;
568 		if (tmp->groups) xfree(tmp->groups);
569 		if (tmp->timespec) xfree(tmp->timespec);
570 		if (tmp->extimespec) xfree(tmp->extimespec);
571 		if (tmp->statustext) xfree(tmp->statustext);
572 		if (tmp->rrdidstr) xfree(tmp->rrdidstr);
573 
574 		switch (tmp->ruletype) {
575 		  case C_MIBVAL:
576 			if (tmp->rule.mibval.havetree) xtreeDestroy(tmp->rule.mibval.valdeftree);
577 			break;
578 
579 		  case C_RRDDS:
580 			if (tmp->rule.rrdds.rrdds) xfree(tmp->rule.rrdds.rrdds);
581 			if (tmp->rule.rrdds.column) xfree(tmp->rule.rrdds.column);
582 			break;
583 
584 		  default:
585 			break;
586 		}
587 		xfree(tmp);
588 	}
589 	rulehead = ruletail = NULL;
590 	while (exprhead) {
591 		exprlist_t *tmp = exprhead;
592 		exprhead = exprhead->next;
593 		if (tmp->pattern) xfree(tmp->pattern);
594 		if (tmp->exp) pcre_free(tmp->exp);
595 		xfree(tmp);
596 	}
597 	exprhead = NULL;
598 
599 	if (havetree) {
600 		xtreePos_t handle;
601 		char *key;
602 		ruleset_t *head, *itm;
603 
604 		handle = xtreeFirst(ruletree);
605 		while (handle != xtreeEnd(ruletree)) {
606 			key = (char *)xtreeKey(ruletree, handle);
607 			head = (ruleset_t *)xtreeData(ruletree, handle);
608 			xfree(key);
609 			while (head) {
610 				itm = head; head = head->next; xfree(itm);
611 			}
612 			handle = xtreeNext(ruletree, handle);
613 		}
614 		xtreeDestroy(ruletree);
615 		havetree = 0;
616 	}
617 
618 #define NEWRULE(X) (setup_rule(X, curhost, curexhost, curpage, curexpage, curdg, curexdg, curclass, curexclass, curtime, curextime, curtext, curgroup, cfid));
619 
620 	curhost = curpage = curclass = curexhost = curexpage = curexclass = curdg = curexdg = NULL;
621 	curtime = curextime = curtext = curgroup = NULL;
622 	inbuf = newstrbuffer(0);
623 	while (stackfgets(inbuf, NULL)) {
624 		exprlist_t *newhost, *newpage, *newexhost, *newexpage, *newclass, *newexclass, *newdg, *newexdg;
625 		char *newtime, *newextime, *newtext, *newgroup;
626 		int unknowntok = 0;
627 
628 		cfid++;
629 		sanitize_input(inbuf, 1, 0); if (STRBUFLEN(inbuf) == 0) continue;
630 
631 		newhost = newpage = newexhost = newexpage = newclass = newexclass = newdg = newexdg = NULL;
632 		newtime = newextime = newtext = newgroup = NULL;
633 		currule = NULL;
634 
635 		tok = wstok(STRBUF(inbuf));
636 		while (tok) {
637 			if (strncasecmp(tok, "HOST=", 5) == 0) {
638 				char *p = strchr(tok, '=');
639 				newhost = setup_expr(p+1, 0);
640 				if (currule) currule->hostexp = newhost;
641 				tok = wstok(NULL); continue;
642 			}
643 			else if (strncasecmp(tok, "EXHOST=", 7) == 0) {
644 				char *p = strchr(tok, '=');
645 				newexhost = setup_expr(p+1, 0);
646 				if (currule) currule->exhostexp = newexhost;
647 				tok = wstok(NULL); continue;
648 			}
649 			else if (strncasecmp(tok, "PAGE=", 5) == 0) {
650 				char *p = strchr(tok, '=');
651 				newpage = setup_expr(p+1, 0);
652 				if (currule) currule->pageexp = newpage;
653 				tok = wstok(NULL); continue;
654 			}
655 			else if (strncasecmp(tok, "EXPAGE=", 7) == 0) {
656 				char *p = strchr(tok, '=');
657 				newexpage = setup_expr(p+1, 0);
658 				if (currule) currule->expageexp = newexpage;
659 				tok = wstok(NULL); continue;
660 			}
661 			else if (strncasecmp(tok, "DISPLAYGROUP=", 13) == 0) {
662 				char *p = strchr(tok, '=');
663 				newdg = setup_expr(p+1, 0);
664 				if (currule) currule->dgexp = newdg;
665 				tok = wstok(NULL); continue;
666 			}
667 			else if (strncasecmp(tok, "EXDISPLAYGROUP=", 15) == 0) {
668 				char *p = strchr(tok, '=');
669 				newexdg = setup_expr(p+1, 0);
670 				if (currule) currule->exdgexp = newexdg;
671 				tok = wstok(NULL); continue;
672 			}
673 			else if (strncasecmp(tok, "CLASS=", 6) == 0) {
674 				char *p = strchr(tok, '=');
675 				newclass = setup_expr(p+1, 0);
676 				if (currule) currule->classexp = newclass;
677 				tok = wstok(NULL); continue;
678 			}
679 			else if (strncasecmp(tok, "EXCLASS=", 8) == 0) {
680 				char *p = strchr(tok, '=');
681 				newexclass = setup_expr(p+1, 0);
682 				if (currule) currule->exclassexp = newexclass;
683 				tok = wstok(NULL); continue;
684 			}
685 			else if (strncasecmp(tok, "TIME=", 5) == 0) {
686 				char *p = strchr(tok, '=');
687 				if (currule) currule->timespec = strdup(p+1);
688 				else newtime = strdup(p+1);
689 				tok = wstok(NULL); continue;
690 			}
691 			else if (strncasecmp(tok, "EXTIME=", 7) == 0) {
692 				char *p = strchr(tok, '=');
693 				if (currule) currule->extimespec = strdup(p+1);
694 				else newextime = strdup(p+1);
695 				tok = wstok(NULL); continue;
696 			}
697 			else if (strncasecmp(tok, "TEXT=", 5) == 0) {
698 				char *p = strchr(tok, '=');
699 				if (currule) currule->statustext = strdup(p+1);
700 				else newtext = strdup(p+1);
701 				tok = wstok(NULL); continue;
702 			}
703 			else if (strncasecmp(tok, "GROUP=", 6) == 0) {
704 				char *p = strchr(tok, '=');
705 				if (currule) currule->groups = strdup(p+1);
706 				else newgroup = strdup(p+1);
707 				tok = wstok(NULL); continue;
708 			}
709 			else if (strncasecmp(tok, "DEFAULT", 6) == 0) {
710 				currule = NULL;
711 			}
712 			else if (strcasecmp(tok, "UP") == 0) {
713 				currule = NEWRULE(C_UPTIME)
714 				currule->rule.uptime.recentlimit = 3600;
715 				currule->rule.uptime.ancientlimit = -1;
716 				currule->rule.uptime.color = COL_YELLOW;
717 
718 				tok = wstok(NULL); if (isqual(tok)) continue;
719 				currule->rule.uptime.recentlimit = 60*durationvalue(tok);
720 				tok = wstok(NULL); if (isqual(tok)) continue;
721 				currule->rule.uptime.ancientlimit = 60*durationvalue(tok);
722 				tok = wstok(NULL); if (isqual(tok)) continue;
723 				if (tok) currule->rule.uptime.color = parse_color(tok);
724 			}
725 			else if (strcasecmp(tok, "CLOCK") == 0) {
726 				currule = NEWRULE(C_CLOCK);
727 				currule->rule.clock.maxdiff = 60;
728 				currule->rule.clock.color = COL_YELLOW;
729 				tok = wstok(NULL); if (isqual(tok)) continue;
730 				currule->rule.clock.maxdiff = atoi(tok);
731 				tok = wstok(NULL); if (isqual(tok)) continue;
732 				if (tok) currule->rule.clock.color = parse_color(tok);
733 			}
734 			else if (strcasecmp(tok, "LOAD") == 0) {
735 				currule = NEWRULE(C_LOAD);
736 				currule->rule.load.warnlevel = 5.0;
737 				currule->rule.load.paniclevel = atof(tok);
738 
739 				tok = wstok(NULL); if (isqual(tok)) continue;
740 				currule->rule.load.warnlevel = atof(tok);
741 				tok = wstok(NULL); if (isqual(tok)) continue;
742 				currule->rule.load.paniclevel = atof(tok);
743 			}
744 			else if (strcasecmp(tok, "DISK") == 0) {
745 				currule = NEWRULE(C_DISK);
746 				currule->rule.disk.abswarn = 0;
747 				currule->rule.disk.warnlevel = 90;
748 				currule->rule.disk.abspanic = 0;
749 				currule->rule.disk.paniclevel = 95;
750 				currule->rule.disk.dmin = 0;
751 				currule->rule.disk.dmax = -1;
752 				currule->rule.disk.color = COL_RED;
753 				currule->rule.disk.ignored = 0;
754 
755 				tok = wstok(NULL); if (isqual(tok)) continue;
756 				currule->rule.disk.fsexp = setup_expr(tok, 0);
757 
758 				tok = wstok(NULL); if (isqual(tok)) continue;
759 				if (strcasecmp(tok, "ignore") == 0) {
760 					currule->rule.disk.ignored = 1;
761 					tok = wstok(NULL);
762 					continue;
763 				}
764 				currule->rule.disk.warnlevel = atol(tok);
765 				switch (*(tok + strspn(tok, "0123456789"))) {
766 				  case 'U':
767 				  case 'u': currule->rule.disk.abswarn = 1; break;
768 				  case '%': currule->rule.disk.abswarn = 0; break;
769 				  default : currule->rule.disk.abswarn = (currule->rule.disk.warnlevel > 200 ? 1 : 0); break;
770 				}
771 
772 				tok = wstok(NULL); if (isqual(tok)) continue;
773 				currule->rule.disk.paniclevel = atol(tok);
774 				switch (*(tok + strspn(tok, "0123456789"))) {
775 				  case 'U':
776 				  case 'u': currule->rule.disk.abspanic = 1; break;
777 				  case '%': currule->rule.disk.abspanic = 0; break;
778 				  default : currule->rule.disk.abspanic = (currule->rule.disk.paniclevel > 200 ? 1 : 0); break;
779 				}
780 
781 				tok = wstok(NULL); if (isqual(tok)) continue;
782 				currule->rule.disk.dmin = atoi(tok);
783 				tok = wstok(NULL); if (isqual(tok)) continue;
784 				currule->rule.disk.dmax = atoi(tok);
785 				tok = wstok(NULL); if (isqual(tok)) continue;
786 				currule->rule.disk.color = parse_color(tok);
787 			}
788 			else if (strcasecmp(tok, "INODE") == 0) {
789 				currule = NEWRULE(C_INODE);
790 				currule->rule.inode.abswarn = 0;
791 				currule->rule.inode.warnlevel = 70;
792 				currule->rule.inode.abspanic = 0;
793 				currule->rule.inode.paniclevel = 90;
794 				currule->rule.inode.imin = 0;
795 				currule->rule.inode.imax = -1;
796 				currule->rule.inode.color = COL_RED;
797 				currule->rule.inode.ignored = 0;
798 
799 				tok = wstok(NULL); if (isqual(tok)) continue;
800 				currule->rule.inode.fsexp = setup_expr(tok, 0);
801 
802 				tok = wstok(NULL); if (isqual(tok)) continue;
803 				if (strcasecmp(tok, "ignore") == 0) {
804 					currule->rule.inode.ignored = 1;
805 					tok = wstok(NULL);
806 					continue;
807 				}
808 				currule->rule.inode.warnlevel = atol(tok);
809 				switch (*(tok + strspn(tok, "0123456789"))) {
810 				  case 'U':
811 				  case 'u': currule->rule.inode.abswarn = 1; break;
812 				  case '%': currule->rule.inode.abswarn = 0; break;
813 				  default : currule->rule.inode.abswarn = (currule->rule.inode.warnlevel > 200 ? 1 : 0); break;
814 				}
815 
816 				tok = wstok(NULL); if (isqual(tok)) continue;
817 				currule->rule.inode.paniclevel = atol(tok);
818 				switch (*(tok + strspn(tok, "0123456789"))) {
819 				  case 'U':
820 				  case 'u': currule->rule.inode.abspanic = 1; break;
821 				  case '%': currule->rule.inode.abspanic = 0; break;
822 				  default : currule->rule.inode.abspanic = (currule->rule.inode.paniclevel > 200 ? 1 : 0); break;
823 				}
824 
825 				tok = wstok(NULL); if (isqual(tok)) continue;
826 				currule->rule.inode.imin = atoi(tok);
827 				tok = wstok(NULL); if (isqual(tok)) continue;
828 				currule->rule.inode.imax = atoi(tok);
829 				tok = wstok(NULL); if (isqual(tok)) continue;
830 				currule->rule.inode.color = parse_color(tok);
831 			}
832 
833 			else if ((strcasecmp(tok, "MEMREAL") == 0) || (strcasecmp(tok, "MEMPHYS") == 0) || (strcasecmp(tok, "PHYS") == 0)) {
834 				currule = NEWRULE(C_MEM);
835 				currule->rule.mem.memtype = C_MEM_PHYS;
836 				currule->rule.mem.warnlevel = 100;
837 				currule->rule.mem.paniclevel = 101;
838 
839 				tok = wstok(NULL); if (isqual(tok)) continue;
840 				currule->rule.mem.warnlevel = atoi(tok);
841 				tok = wstok(NULL); if (isqual(tok)) continue;
842 				currule->rule.mem.paniclevel = atoi(tok);
843 			}
844 			else if ((strcasecmp(tok, "MEMSWAP") == 0) || (strcasecmp(tok, "SWAP") == 0)) {
845 				currule = NEWRULE(C_MEM);
846 				currule->rule.mem.memtype = C_MEM_SWAP;
847 				currule->rule.mem.warnlevel = 50;
848 				currule->rule.mem.paniclevel = 80;
849 
850 				tok = wstok(NULL); if (isqual(tok)) continue;
851 				currule->rule.mem.warnlevel = atoi(tok);
852 				tok = wstok(NULL); if (isqual(tok)) continue;
853 				currule->rule.mem.paniclevel = atoi(tok);
854 			}
855 			else if ((strcasecmp(tok, "MEMACT") == 0) || (strcasecmp(tok, "ACTUAL") == 0) || (strcasecmp(tok, "ACT") == 0)) {
856 				currule = NEWRULE(C_MEM);
857 				currule->rule.mem.memtype = C_MEM_ACT;
858 				currule->rule.mem.warnlevel = 90;
859 				currule->rule.mem.paniclevel = 97;
860 
861 				tok = wstok(NULL); if (isqual(tok)) continue;
862 				currule->rule.mem.warnlevel = atoi(tok);
863 				tok = wstok(NULL); if (isqual(tok)) continue;
864 				currule->rule.mem.paniclevel = atoi(tok);
865 			}
866 			else if (strcasecmp(tok, "MEMCSA") == 0) {
867 				currule = NEWRULE(C_MEM);
868 				currule->rule.zos_mem.zos_memtype = C_MEM_CSA;
869 				currule->rule.zos_mem.warnlevel = 90;
870 				currule->rule.zos_mem.paniclevel = 95;
871 
872 				tok = wstok(NULL); if (isqual(tok)) continue;
873 				currule->rule.zos_mem.warnlevel = atoi(tok);
874 				tok = wstok(NULL); if (isqual(tok)) continue;
875 				currule->rule.zos_mem.paniclevel = atoi(tok);
876 			}
877 			else if (strcasecmp(tok, "MEMECSA") == 0) {
878 				currule = NEWRULE(C_MEM);
879 				currule->rule.zos_mem.zos_memtype = C_MEM_ECSA;
880 				currule->rule.zos_mem.warnlevel = 90;
881 				currule->rule.zos_mem.paniclevel = 95;
882 
883 				tok = wstok(NULL); if (isqual(tok)) continue;
884 				currule->rule.zos_mem.warnlevel = atoi(tok);
885 				tok = wstok(NULL); if (isqual(tok)) continue;
886 				currule->rule.zos_mem.paniclevel = atoi(tok);
887 			}
888 			else if (strcasecmp(tok, "MEMSQA") == 0) {
889 				currule = NEWRULE(C_MEM);
890 				currule->rule.zos_mem.zos_memtype = C_MEM_SQA;
891 				currule->rule.zos_mem.warnlevel = 90;
892 				currule->rule.zos_mem.paniclevel = 95;
893 
894 				tok = wstok(NULL); if (isqual(tok)) continue;
895 				currule->rule.zos_mem.warnlevel = atoi(tok);
896 				tok = wstok(NULL); if (isqual(tok)) continue;
897 				currule->rule.zos_mem.paniclevel = atoi(tok);
898 			}
899 			else if (strcasecmp(tok, "MEMESQA") == 0) {
900 				currule = NEWRULE(C_MEM);
901 				currule->rule.zos_mem.zos_memtype = C_MEM_ESQA;
902 				currule->rule.zos_mem.warnlevel = 90;
903 				currule->rule.zos_mem.paniclevel = 95;
904 
905 				tok = wstok(NULL); if (isqual(tok)) continue;
906 				currule->rule.zos_mem.warnlevel = atoi(tok);
907 				tok = wstok(NULL); if (isqual(tok)) continue;
908 				currule->rule.zos_mem.paniclevel = atoi(tok);
909 			}
910                         else if (strcasecmp(tok, "CICS") == 0) {
911                                 currule = NEWRULE(C_CICS);
912                                 currule->rule.cics.dsawarnlevel = 90;
913                                 currule->rule.cics.dsapaniclevel = 95;
914                                 currule->rule.cics.edsawarnlevel = 90;
915                                 currule->rule.cics.edsapaniclevel = 95;
916 
917 				tok = wstok(NULL); if (isqual(tok)) continue;
918 				currule->rule.cics.applid = setup_expr(tok, 0);
919 
920                                 tok = wstok(NULL); if (isqual(tok)) continue;
921 				if (strcasecmp(tok, "DSA") == 0) {
922                                 	tok = wstok(NULL); if (isqual(tok)) continue;
923                                 	currule->rule.cics.dsawarnlevel = atoi(tok);
924                                 	tok = wstok(NULL); if (isqual(tok)) continue;
925                                 	currule->rule.cics.dsapaniclevel = atoi(tok);
926 					}
927 				else if (strcasecmp(tok, "EDSA") == 0) {
928                                 	tok = wstok(NULL); if (isqual(tok)) continue;
929                                 	currule->rule.cics.edsawarnlevel = atoi(tok);
930                                 	tok = wstok(NULL); if (isqual(tok)) continue;
931                                 	currule->rule.cics.edsapaniclevel = atoi(tok);
932 					}
933 
934                                 tok = wstok(NULL); if (isqual(tok)) continue;
935 				if (strcasecmp(tok, "DSA") == 0) {
936                                 	tok = wstok(NULL); if (isqual(tok)) continue;
937                                 	currule->rule.cics.dsawarnlevel = atoi(tok);
938                                 	tok = wstok(NULL); if (isqual(tok)) continue;
939                                 	currule->rule.cics.dsapaniclevel = atoi(tok);
940 					}
941 				else if (strcasecmp(tok, "EDSA") == 0) {
942                                 	tok = wstok(NULL); if (isqual(tok)) continue;
943                                 	currule->rule.cics.edsawarnlevel = atoi(tok);
944                                 	tok = wstok(NULL); if (isqual(tok)) continue;
945                                 	currule->rule.cics.edsapaniclevel = atoi(tok);
946 					}
947                         }
948 			else if (strcasecmp(tok, "PROC") == 0) {
949 				int idx = 0;
950 
951 				tok = wstok(NULL);
952 				if (tok == NULL) {
953 					errprintf("Syntax error line %d: PROC with no definition\n", cfid);
954 					unknowntok = 1;
955 					break;
956 				}
957 
958 				currule = NEWRULE(C_PROC);
959 				currule->rule.proc.pmin = 1;
960 				currule->rule.proc.pmax = -1;
961 				currule->rule.proc.color = COL_RED;
962 
963 				currule->rule.proc.procexp = setup_expr(tok, 0);
964 
965 				do {
966 					tok = wstok(NULL); if (!tok || isqual(tok)) { idx = -1; continue; }
967 
968 					if (strncasecmp(tok, "min=", 4) == 0) {
969 						currule->rule.proc.pmin = atoi(tok+4);
970 					}
971 					else if (strncasecmp(tok, "max=", 4) == 0) {
972 						currule->rule.proc.pmax = atoi(tok+4);
973 						/* When we have an explicit max, minimum should not be higher */
974 						if (currule->rule.proc.pmax < currule->rule.proc.pmin) {
975 							currule->rule.proc.pmin = currule->rule.proc.pmax;
976 						}
977 					}
978 					else if (strncasecmp(tok, "color=", 6) == 0) {
979 						currule->rule.proc.color = parse_color(tok+6);
980 					}
981 					else if (strncasecmp(tok, "track", 5) == 0) {
982 						currule->chkflags |= CHK_TRACKIT;
983 						if (*(tok+5) == '=') currule->rrdidstr = strdup(tok+6);
984 					}
985 					else if (idx == 0) {
986 						currule->rule.proc.pmin = atoi(tok);
987 						idx++;
988 					}
989 					else if (idx == 1) {
990 						currule->rule.proc.pmax = atoi(tok);
991 						idx++;
992 					}
993 					else if (idx == 2) {
994 						currule->rule.proc.color = parse_color(tok);
995 						idx++;
996 					}
997 				} while (tok && (!isqual(tok)));
998 
999 				/* It's easy to set max=0 when you only want to define a minimum */
1000 				if (currule->rule.proc.pmin && (currule->rule.proc.pmax == 0)) {
1001 					currule->rule.proc.pmax = -1;
1002 				}
1003 			}
1004 			else if (strcasecmp(tok, "LOG") == 0) {
1005 				int idx = 0;
1006 
1007 				currule = NEWRULE(C_LOG);
1008 				currule->rule.log.logfile   = NULL;
1009 				currule->rule.log.matchexp  = NULL;
1010 				currule->rule.log.matchone  = NULL;
1011 				currule->rule.log.ignoreexp = NULL;
1012 				currule->rule.log.color     = COL_RED;
1013 
1014 				do {
1015 					tok = wstok(NULL); if (!tok || isqual(tok)) { idx = -1; continue; }
1016 
1017 					if (strncasecmp(tok, "file=", 5) == 0) {
1018 						currule->rule.log.logfile   = setup_expr(tok+5, 0);
1019 					}
1020 					else if (strncasecmp(tok, "match=", 6) == 0) {
1021 						currule->rule.log.matchexp = setup_expr(tok+6, 1);
1022 						currule->rule.log.matchone = setup_expr(tok+6, 0);
1023 					}
1024 					else if (strncasecmp(tok, "ignore=", 7) == 0) {
1025 						currule->rule.log.ignoreexp = setup_expr(tok+7, 1);
1026 					}
1027 					else if (strncasecmp(tok, "color=", 6) == 0) {
1028 						currule->rule.log.color = parse_color(tok+6);
1029 					}
1030 					else if (strcasecmp(tok, "optional") == 0) {
1031 						currule->chkflags |= CHK_OPTIONAL;
1032 					}
1033 					else if (idx == 0) {
1034 						currule->rule.log.logfile   = setup_expr(tok, 0);
1035 						idx++;
1036 					}
1037 					else if (idx == 1) {
1038 						currule->rule.log.matchexp = setup_expr(tok, 1);
1039 						currule->rule.log.matchone = setup_expr(tok, 0);
1040 						idx++;
1041 					}
1042 					else if (idx == 2) {
1043 						currule->rule.log.color = parse_color(tok);
1044 						idx++;
1045 					}
1046 					else if (idx == 3) {
1047 						currule->rule.log.ignoreexp = setup_expr(tok, 1);
1048 						idx++;
1049 					}
1050 				} while (tok && (!isqual(tok)));
1051 			}
1052 			else if (strcasecmp(tok, "FILE") == 0) {
1053 				currule = NEWRULE(C_FILE);
1054 				currule->rule.fcheck.filename = NULL;
1055 				currule->rule.fcheck.color = COL_RED;
1056 
1057 				tok = wstok(NULL);
1058 				currule->rule.fcheck.filename = setup_expr(tok, 0);
1059 				do {
1060 					tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1061 
1062 					if (strcasecmp(tok, "noexist") == 0) {
1063 						currule->flags |= FCHK_NOEXIST;
1064 					}
1065 					else if (strncasecmp(tok, "type=", 5) == 0) {
1066 						currule->flags |= FCHK_TYPE;
1067 						if (strcasecmp(tok+5, "socket") == 0) currule->rule.fcheck.ftype = S_IFSOCK;
1068 						else if (strcasecmp(tok+5, "file") == 0) currule->rule.fcheck.ftype = S_IFREG;
1069 						else if (strcasecmp(tok+5, "block") == 0) currule->rule.fcheck.ftype = S_IFBLK;
1070 						else if (strcasecmp(tok+5, "char") == 0) currule->rule.fcheck.ftype = S_IFCHR;
1071 						else if (strcasecmp(tok+5, "dir") == 0) currule->rule.fcheck.ftype = S_IFDIR;
1072 						else if (strcasecmp(tok+5, "fifo") == 0) currule->rule.fcheck.ftype = S_IFIFO;
1073 						else if (strcasecmp(tok+5, "symlink") == 0) currule->rule.fcheck.ftype = S_IFLNK;
1074 					}
1075 					else if (strncasecmp(tok, "size>", 5) == 0) {
1076 						currule->flags |= FCHK_MINSIZE;
1077 						currule->rule.fcheck.minsize = filesize_value(tok+5);
1078 					}
1079 					else if (strncasecmp(tok, "size<", 5) == 0) {
1080 						currule->flags |= FCHK_MAXSIZE;
1081 						currule->rule.fcheck.maxsize = filesize_value(tok+5);
1082 					}
1083 					else if (strncasecmp(tok, "size=", 5) == 0) {
1084 						currule->flags |= FCHK_EQLSIZE;
1085 						currule->rule.fcheck.eqlsize = filesize_value(tok+5);
1086 					}
1087 					else if (strncasecmp(tok, "links>", 6) == 0) {
1088 						currule->flags |= FCHK_MINLINKS;
1089 						currule->rule.fcheck.minlinks = atol(tok+6);
1090 					}
1091 					else if (strncasecmp(tok, "links<", 6) == 0) {
1092 						currule->flags |= FCHK_MAXLINKS;
1093 						currule->rule.fcheck.maxlinks = atol(tok+6);
1094 					}
1095 					else if (strncasecmp(tok, "links=", 6) == 0) {
1096 						currule->flags |= FCHK_EQLLINKS;
1097 						currule->rule.fcheck.eqllinks = atol(tok+6);
1098 					}
1099 					else if (strncasecmp(tok, "mode=", 5) == 0) {
1100 						currule->flags |= FCHK_MODE;
1101 						currule->rule.fcheck.fmode = strtol(tok+5, NULL, 8);
1102 					}
1103 					else if ((strncasecmp(tok, "owner=", 6) == 0) ||
1104 						 (strncasecmp(tok, "ownerid=", 8) == 0)) {
1105 						char *p, *eptr;
1106 						int uid;
1107 
1108 						p = strchr(tok, '=');
1109 						uid = strtol(p+1, &eptr, 10);
1110 						if (*eptr == '\0') {
1111 							/* All numeric */
1112 							currule->flags |= FCHK_OWNERID;
1113 							currule->rule.fcheck.ownerid = uid;
1114 						}
1115 						else {
1116 							currule->flags |= FCHK_OWNERSTR;
1117 							currule->rule.fcheck.ownerstr = strdup(p+1);
1118 						}
1119 					}
1120 					else if (strncasecmp(tok, "groupid=", 8) == 0) {
1121 						/* Cannot use "group" because that is reserved */
1122 						char *p, *eptr;
1123 						int uid;
1124 
1125 						p = strchr(tok, '=');
1126 						uid = strtol(p+1, &eptr, 10);
1127 						if (*eptr == '\0') {
1128 							/* All numeric */
1129 							currule->flags |= FCHK_GROUPID;
1130 							currule->rule.fcheck.groupid = uid;
1131 						}
1132 						else {
1133 							currule->flags |= FCHK_GROUPSTR;
1134 							currule->rule.fcheck.groupstr = strdup(p+1);
1135 						}
1136 					}
1137 					else if (strncasecmp(tok, "mtime>", 6) == 0) {
1138 						currule->flags |= FCHK_MTIMEMIN;
1139 						currule->rule.fcheck.minmtimedif = atol(tok+6);
1140 					}
1141 					else if (strncasecmp(tok, "mtime<", 6) == 0) {
1142 						currule->flags |= FCHK_MTIMEMAX;
1143 						currule->rule.fcheck.maxmtimedif = atol(tok+6);
1144 					}
1145 					else if (strncasecmp(tok, "mtime=", 6) == 0) {
1146 						currule->flags |= FCHK_MTIMEEQL;
1147 						currule->rule.fcheck.mtimeeql = atol(tok+6);
1148 					}
1149 					else if (strncasecmp(tok, "ctime>", 6) == 0) {
1150 						currule->flags |= FCHK_CTIMEMIN;
1151 						currule->rule.fcheck.minctimedif = atol(tok+6);
1152 					}
1153 					else if (strncasecmp(tok, "ctime<", 6) == 0) {
1154 						currule->flags |= FCHK_CTIMEMAX;
1155 						currule->rule.fcheck.maxctimedif = atol(tok+6);
1156 					}
1157 					else if (strncasecmp(tok, "ctime=", 6) == 0) {
1158 						currule->flags |= FCHK_CTIMEEQL;
1159 						currule->rule.fcheck.ctimeeql = atol(tok+6);
1160 					}
1161 					else if (strncasecmp(tok, "atime>", 6) == 0) {
1162 						currule->flags |= FCHK_ATIMEMIN;
1163 						currule->rule.fcheck.minatimedif = atol(tok+6);
1164 					}
1165 					else if (strncasecmp(tok, "atime<", 6) == 0) {
1166 						currule->flags |= FCHK_ATIMEMAX;
1167 						currule->rule.fcheck.maxatimedif = atol(tok+6);
1168 					}
1169 					else if (strncasecmp(tok, "atime=", 6) == 0) {
1170 						currule->flags |= FCHK_ATIMEEQL;
1171 						currule->rule.fcheck.atimeeql = atol(tok+6);
1172 					}
1173 					else if (strncasecmp(tok, "md5=", 4) == 0) {
1174 						currule->flags |= FCHK_MD5;
1175 						currule->rule.fcheck.md5hash = strdup(tok+4);
1176 					}
1177 					else if (strncasecmp(tok, "sha1=", 5) == 0) {
1178 						currule->flags |= FCHK_SHA1;
1179 						currule->rule.fcheck.sha1hash = strdup(tok+5);
1180 					}
1181 					else if (strncasecmp(tok, "sha256=", 7) == 0) {
1182 						currule->flags |= FCHK_SHA256;
1183 						currule->rule.fcheck.sha256hash = strdup(tok+7);
1184 					}
1185 					else if (strncasecmp(tok, "sha512=", 7) == 0) {
1186 						currule->flags |= FCHK_SHA512;
1187 						currule->rule.fcheck.sha512hash = strdup(tok+7);
1188 					}
1189 					else if (strncasecmp(tok, "sha224=", 7) == 0) {
1190 						currule->flags |= FCHK_SHA224;
1191 						currule->rule.fcheck.sha224hash = strdup(tok+7);
1192 					}
1193 					else if (strncasecmp(tok, "sha384=", 7) == 0) {
1194 						currule->flags |= FCHK_SHA384;
1195 						currule->rule.fcheck.sha384hash = strdup(tok+7);
1196 					}
1197 					else if (strncasecmp(tok, "rmd160=", 7) == 0) {
1198 						currule->flags |= FCHK_RMD160;
1199 						currule->rule.fcheck.rmd160hash = strdup(tok+7);
1200 					}
1201 					else if (strncasecmp(tok, "track", 5) == 0) {
1202 						currule->chkflags |= CHK_TRACKIT;
1203 						if (*(tok+5) == '=') currule->rrdidstr = strdup(tok+6);
1204 					}
1205 					else if (strcasecmp(tok, "optional") == 0) {
1206 						currule->chkflags |= CHK_OPTIONAL;
1207 					}
1208 					else {
1209 						int col = parse_color(tok);
1210 						if (col != -1) currule->rule.fcheck.color = col;
1211 					}
1212 				} while (tok && (!isqual(tok)));
1213 			}
1214 			else if (strcasecmp(tok, "DIR") == 0) {
1215 				currule = NEWRULE(C_DIR);
1216 				currule->rule.dcheck.filename = NULL;
1217 				currule->rule.dcheck.color = COL_RED;
1218 
1219 				tok = wstok(NULL);
1220 				currule->rule.dcheck.filename = setup_expr(tok, 0);
1221 				do {
1222 					tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1223 
1224 					if (strncasecmp(tok, "size<", 5) == 0) {
1225 						currule->flags |= FCHK_MAXSIZE;
1226 						currule->rule.dcheck.maxsize = atol(tok+5);
1227 					}
1228 					else if (strncasecmp(tok, "size>", 5) == 0) {
1229 						currule->flags |= FCHK_MINSIZE;
1230 						currule->rule.dcheck.minsize = atol(tok+5);
1231 					}
1232 					else if (strncasecmp(tok, "track", 5) == 0) {
1233 						currule->chkflags |= CHK_TRACKIT;
1234 						if (*(tok+5) == '=') currule->rrdidstr = strdup(tok+6);
1235 					}
1236 					else {
1237 						int col = parse_color(tok);
1238 						if (col != -1) currule->rule.dcheck.color = col;
1239 					}
1240 				} while (tok && (!isqual(tok)));
1241 			}
1242 			else if (strcasecmp(tok, "PORT") == 0) {
1243 				currule = NEWRULE(C_PORT);
1244 
1245 				currule->rule.port.localexp = NULL;
1246 				currule->rule.port.exlocalexp = NULL;
1247 				currule->rule.port.remoteexp = NULL;
1248 				currule->rule.port.exremoteexp = NULL;
1249 				currule->rule.port.stateexp = NULL;
1250 				currule->rule.port.exstateexp = NULL;
1251 				currule->rule.port.pmin = 1;
1252 				currule->rule.port.pmax = -1;
1253 				currule->rule.port.color = COL_RED;
1254 
1255 				/* parse syntax [local=ADDR] [remote=ADDR] [state=STATE] [min=mincount] [max=maxcount] [col=color] */
1256 				do {
1257  					tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1258 
1259 					if (strncasecmp(tok, "local=", 6) == 0) {
1260 						currule->rule.port.localexp = setup_expr(tok+6, 0);
1261 					}
1262 					else if (strncasecmp(tok, "exlocal=", 8) == 0) {
1263 						currule->rule.port.exlocalexp = setup_expr(tok+8, 0);
1264 					}
1265 					else if (strncasecmp(tok, "remote=", 7) == 0) {
1266 						currule->rule.port.remoteexp = setup_expr(tok+7, 0);
1267 					}
1268 					else if (strncasecmp(tok, "exremote=", 9) == 0) {
1269 						currule->rule.port.exremoteexp = setup_expr(tok+9, 0);
1270 					}
1271 					else if (strncasecmp(tok, "state=", 6) == 0) {
1272 						currule->rule.port.stateexp = setup_expr(tok+6, 0);
1273 					}
1274 					else if (strncasecmp(tok, "exstate=", 8) == 0) {
1275 						currule->rule.port.exstateexp = setup_expr(tok+8, 0);
1276 					}
1277 					else if (strncasecmp(tok, "min=", 4) == 0) {
1278 						currule->rule.port.pmin = atoi(tok+4);
1279 					}
1280 					else if (strncasecmp(tok, "max=", 4) == 0) {
1281 						currule->rule.port.pmax = atoi(tok+4);
1282 
1283 						/* When we have an explicit max, minimum should not be higher */
1284 						if (currule->rule.port.pmax < currule->rule.port.pmin) {
1285 							currule->rule.port.pmin = currule->rule.port.pmax;
1286 						}
1287 					}
1288 					else if (strncasecmp(tok, "col=", 4) == 0) {
1289 						currule->rule.port.color = parse_color(tok+4);
1290 					}
1291 					else if (strncasecmp(tok, "color=", 6) == 0) {
1292 						currule->rule.port.color = parse_color(tok+6);
1293 					}
1294 					else if (strncasecmp(tok, "track", 5) == 0) {
1295 						currule->chkflags |= CHK_TRACKIT;
1296 						if (*(tok+5) == '=') currule->rrdidstr = strdup(tok+6);
1297 					}
1298 				} while (tok && (!isqual(tok)));
1299 			}
1300 			else if (strcasecmp(tok, "PAGING") == 0) {
1301 				currule = NEWRULE(C_PAGING);
1302 
1303 				currule->rule.paging.warnlevel = 5;
1304 				currule->rule.paging.paniclevel = 10;
1305 
1306 				tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1307 				currule->rule.paging.warnlevel = atoi(tok);
1308 
1309 				tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1310 				currule->rule.paging.paniclevel = atoi(tok);
1311 			}
1312 			else if (strcasecmp(tok, "GETVIS") == 0) {
1313                                 currule = NEWRULE(C_MEM_GETVIS);
1314 				currule->rule.zvse_getvis.warnlevel =  90;
1315 				currule->rule.zvse_getvis.paniclevel = 95;
1316 				currule->rule.zvse_getvis.anywarnlevel =  90;
1317 				currule->rule.zvse_getvis.anypaniclevel = 95;
1318 
1319 				tok = wstok(NULL); if (isqual(tok)) continue;
1320 				currule->rule.zvse_getvis.partid = setup_expr(tok, 0);
1321 
1322                                	tok = wstok(NULL); if (isqual(tok)) continue;
1323                                	currule->rule.zvse_getvis.warnlevel = atoi(tok);
1324                                	tok = wstok(NULL); if (isqual(tok)) continue;
1325                                	currule->rule.zvse_getvis.paniclevel = atoi(tok);
1326 
1327                                	tok = wstok(NULL); if (isqual(tok)) continue;
1328                                	currule->rule.zvse_getvis.anywarnlevel = atoi(tok);
1329                                	tok = wstok(NULL); if (isqual(tok)) continue;
1330                                	currule->rule.zvse_getvis.anypaniclevel = atoi(tok);
1331 			}
1332                         else if (strcasecmp(tok, "VSIZE") == 0) {
1333                                 currule = NEWRULE(C_MEM_VSIZE);
1334                                 currule->rule.zvse_vsize.warnlevel = 90;
1335                                 currule->rule.zvse_vsize.paniclevel = 95;
1336 
1337                                 tok = wstok(NULL); if (isqual(tok)) continue;
1338                                 currule->rule.zvse_vsize.warnlevel = atoi(tok);
1339                                 tok = wstok(NULL); if (isqual(tok)) continue;
1340                                 currule->rule.zvse_vsize.paniclevel = atoi(tok);
1341                         }
1342                         else if (strcasecmp(tok, "MAXUSER") == 0) {
1343                                 currule = NEWRULE(C_ASID);
1344 				currule->rule.asid.asidtype = C_ASID_MAXUSER;
1345 
1346                                 currule->rule.asid.warnlevel = 101;
1347                                 currule->rule.asid.paniclevel = 101;
1348 
1349                                 tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1350                                 currule->rule.asid.warnlevel = atoi(tok);
1351 
1352                                 tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1353                                 currule->rule.asid.paniclevel = atoi(tok);
1354                         }
1355                         else if (strcasecmp(tok, "NPARTS") == 0) {
1356                                 currule = NEWRULE(C_ASID);
1357                                 currule->rule.asid.asidtype = C_ASID_NPARTS;
1358 
1359                                 currule->rule.asid.warnlevel = 101;
1360                                 currule->rule.asid.paniclevel = 101;
1361 
1362                                 tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1363                                 currule->rule.asid.warnlevel = atoi(tok);
1364 
1365                                 tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1366                                 currule->rule.asid.paniclevel = atoi(tok);
1367                         }
1368 			else if (strcasecmp(tok, "SVC") == 0) {
1369 				tok = wstok(NULL);	/* See if there is any service definition at all */
1370 				if (tok) {
1371 					currule = NEWRULE(C_SVC);
1372 
1373 					currule->rule.svc.svcexp = setup_expr(tok, 0);
1374 					currule->rule.svc.startupexp = NULL;
1375 					currule->rule.svc.stateexp = NULL;
1376 					currule->rule.svc.state = NULL;
1377 					currule->rule.svc.startup = NULL;
1378 					currule->rule.svc.color = COL_RED;
1379 
1380 					do {
1381 						tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1382 
1383 						if (strncasecmp(tok, "startup=", 8) == 0) {
1384 							currule->rule.svc.startupexp = setup_expr(tok+8, 0);
1385 						}
1386 						else if (strncasecmp(tok, "status=", 7) == 0) {
1387 							currule->rule.svc.stateexp = setup_expr(tok+7, 0);
1388 						}
1389 						else if (strncasecmp(tok, "col=", 4) == 0) {
1390 							currule->rule.svc.color = parse_color(tok+4);
1391 						}
1392 						else if (strncasecmp(tok, "color=", 6) == 0) {
1393 							currule->rule.svc.color = parse_color(tok+6);
1394 						}
1395 					} while (tok && (!isqual(tok)));
1396 
1397 					if (!currule->rule.svc.stateexp && !currule->rule.svc.startupexp) {
1398 						/* No criteria defined, so we'll assume they just want to check that the service is running */
1399 						currule->rule.svc.stateexp = setup_expr("started", 0);
1400 					}
1401 				}
1402 			}
1403 			else if (strcasecmp(tok, "MIB") == 0) {
1404 				currule = NEWRULE(C_MIBVAL);
1405 				currule->rule.mibval.mibvalexp = NULL;
1406 				currule->rule.mibval.keyexp = NULL;
1407 				currule->rule.mibval.color = COL_RED;
1408 				currule->rule.mibval.minval = -1;
1409 				currule->rule.mibval.maxval = -1;
1410 				currule->rule.mibval.matchexp = NULL;
1411 
1412 				tok = wstok(NULL);
1413 				currule->rule.mibval.mibvalexp = setup_expr(tok, 0);
1414 				do {
1415 					tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1416 
1417 					if (strncasecmp(tok, "key=", 4) == 0) {
1418 						currule->rule.mibval.keyexp = setup_expr(tok+4, 0);
1419 					}
1420 					else if (strncasecmp(tok, "max=", 4) == 0) {
1421 						currule->flags |= MIBCHK_MAXVALUE;
1422 						currule->rule.mibval.maxval = atol(tok+4);
1423 					}
1424 					else if (strncasecmp(tok, "min=", 4) == 0) {
1425 						currule->flags |= MIBCHK_MINVALUE;
1426 						currule->rule.mibval.minval = atol(tok+4);
1427 					}
1428 					else if (strncasecmp(tok, "match=", 6) == 0) {
1429 						currule->flags |= MIBCHK_MATCH;
1430 						currule->rule.mibval.matchexp = setup_expr(tok+6, 0);
1431 					}
1432 					else if (strncasecmp(tok, "color=", 6) == 0) {
1433 						int col = parse_color(tok+6);
1434 						if (col != -1) currule->rule.mibval.color = col;
1435 					}
1436 				} while (tok && (!isqual(tok)));
1437 			}
1438 			else if (strcasecmp(tok, "DS") == 0) {
1439 				char *key, *ds, *column;
1440 
1441 				currule = NEWRULE(C_RRDDS);
1442 				currule->rule.rrdds.color = COL_RED;
1443 
1444 				tok = wstok(NULL);
1445 				column = tok;
1446 
1447 				tok = wstok(NULL);
1448 				key = tok;
1449 				ds = (tok ? strrchr(tok, ':') : NULL);
1450 				if (ds) { *ds = '\0'; ds++; }
1451 
1452 				if (!column || !key || !ds) {
1453 					errprintf("Invalid DS definition at line %d (missing column, key and/or dataset)\n", cfid);
1454 					continue;
1455 				}
1456 
1457 				currule->rule.rrdds.rrdkey = setup_expr(key, 0);
1458 				currule->rule.rrdds.rrdds = strdup(ds);
1459 				currule->rule.rrdds.column = strdup(column);
1460 
1461 				do {
1462 					int getnumber = 0;
1463 
1464 					tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1465 
1466 					if (strncasecmp(tok, ">=", 2) == 0) {
1467 						if (currule->flags) currule->flags |= RRDDSCHK_INTVL;
1468 						currule->flags |= RRDDSCHK_GE;
1469 						getnumber = 2;
1470 					}
1471 					else if (strncasecmp(tok, "<=", 2) == 0) {
1472 						if (currule->flags) currule->flags |= RRDDSCHK_INTVL;
1473 						currule->flags |= RRDDSCHK_LE;
1474 						getnumber = 2;
1475 					}
1476 					else if (strncasecmp(tok, ">", 1) == 0) {
1477 						if (currule->flags) currule->flags |= RRDDSCHK_INTVL;
1478 						currule->flags |= RRDDSCHK_GT;
1479 						getnumber = 1;
1480 					}
1481 					else if (strncasecmp(tok, "<", 1) == 0) {
1482 						if (currule->flags) currule->flags |= RRDDSCHK_INTVL;
1483 						currule->flags |= RRDDSCHK_LT;
1484 						getnumber = 1;
1485 					}
1486 					else if (strncasecmp(tok, "color=", 6) == 0) {
1487 						int col = parse_color(tok+6);
1488 						if (col != -1) currule->rule.rrdds.color = col;
1489 					}
1490 
1491 					if (getnumber) {
1492 						if (currule->flags & RRDDSCHK_INTVL)
1493 							currule->rule.rrdds.limitval2 = atof(tok+getnumber);
1494 						else
1495 							currule->rule.rrdds.limitval = atof(tok+getnumber);
1496 
1497 						if ((currule->flags & RRDDSCHK_INTVL) && (currule->rule.rrdds.limitval > currule->rule.rrdds.limitval2)) {
1498 							/* Swap the two values, so we always have limitval as the lower bound, and limitval2 as the upper */
1499 							double tmp;
1500 
1501 							tmp=currule->rule.rrdds.limitval;
1502 							currule->rule.rrdds.limitval = currule->rule.rrdds.limitval2;
1503 							currule->rule.rrdds.limitval2 = tmp;
1504 						}
1505 					}
1506 				} while (tok && (!isqual(tok)));
1507 			}
1508 			else if (strcasecmp(tok, "MQ_QUEUE") == 0) {
1509 				char *p;
1510 				currule = NEWRULE(C_MQ_QUEUE);
1511 				currule->rule.mqqueue.qmgrname = NULL;
1512 				currule->rule.mqqueue.qname = NULL;
1513 				currule->rule.mqqueue.warnlen = -1;
1514 				currule->rule.mqqueue.critlen = -1;
1515 				currule->rule.mqqueue.warnage = -1;
1516 				currule->rule.mqqueue.critage = -1;
1517 
1518 				tok = wstok(NULL);
1519 				p = strchr(tok, ':');
1520 				if (p) {
1521 					*p = '\0'; p++;
1522 					currule->rule.mqqueue.qmgrname = setup_expr(tok, 0);
1523 					currule->rule.mqqueue.qname = setup_expr(p, 0);
1524 				}
1525 				else {
1526 					currule->rule.mqqueue.qmgrname = setup_expr("*", 0);
1527 					currule->rule.mqqueue.qname = setup_expr(tok, 0);
1528 				};
1529 
1530 				do {
1531 					tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1532 
1533 					if (strncasecmp(tok, "depth-warning=", 14) == 0) {
1534 						currule->rule.mqqueue.warnlen = atol(tok+14);
1535 					}
1536 					else if (strncasecmp(tok, "depth-critical=", 15) == 0) {
1537 						currule->rule.mqqueue.critlen = atol(tok+15);
1538 					}
1539 					else if (strncasecmp(tok, "age-warning=", 12) == 0) {
1540 						currule->rule.mqqueue.warnage = atol(tok+12);
1541 					}
1542 					else if (strncasecmp(tok, "age-critical=", 13) == 0) {
1543 						currule->rule.mqqueue.critage = atol(tok+13);
1544 					}
1545 					else if (strncasecmp(tok, "track", 5) == 0) {
1546 						currule->chkflags |= CHK_TRACKIT;
1547 						if (*(tok+5) == '=') currule->rrdidstr = strdup(tok+6);
1548 					}
1549 				} while (tok && (!isqual(tok)));
1550 			}
1551 			else if (strcasecmp(tok, "MQ_CHANNEL") == 0) {
1552 				char *p;
1553 
1554 				currule = NEWRULE(C_MQ_CHANNEL);
1555 				currule->rule.mqchannel.qmgrname = NULL;
1556 				currule->rule.mqchannel.chnname = NULL;
1557 				currule->rule.mqchannel.warnstates = NULL;
1558 				currule->rule.mqchannel.alertstates = NULL;
1559 
1560 				tok = wstok(NULL);
1561 				p = strchr(tok, ':');
1562 				if (p) {
1563 					*p = '\0'; p++;
1564 					currule->rule.mqchannel.qmgrname = setup_expr(tok, 0);
1565 					currule->rule.mqchannel.chnname = setup_expr(p, 0);
1566 				}
1567 				else {
1568 					currule->rule.mqchannel.qmgrname = setup_expr("*", 0);
1569 					currule->rule.mqchannel.chnname = setup_expr(tok, 0);
1570 				};
1571 
1572 				do {
1573 					tok = wstok(NULL); if (!tok || isqual(tok)) continue;
1574 
1575 					if (strncasecmp(tok, "warning=", 8) == 0) {
1576 						currule->rule.mqchannel.warnstates = setup_expr(tok+8, 0);
1577 					}
1578 					else if (strncasecmp(tok, "alert=", 6) == 0) {
1579 						currule->rule.mqchannel.alertstates = setup_expr(tok+6, 0);
1580 					}
1581 				} while (tok && (!isqual(tok)));
1582 
1583 				if ((currule->rule.mqchannel.warnstates == NULL) && (currule->rule.mqchannel.alertstates == NULL)) {
1584 					/* Default: Alert on channel in BIND or RETRYING state */
1585 					currule->rule.mqchannel.alertstates = setup_expr("%BIND|RETRYING", 0);
1586 				}
1587 			}
1588 			else {
1589 				errprintf("Unknown token '%s' ignored at line %d\n", tok, cfid);
1590 				unknowntok = 1; tok = NULL; continue;
1591 			}
1592 
1593 			if (tok && !isqual(tok)) tok = wstok(NULL);
1594 		}
1595 
1596 		if (!currule && !unknowntok) {
1597 			/* No rules on this line - its the new set of criteria */
1598 			curhost = newhost;
1599 			curpage = newpage;
1600 			curclass = newclass;
1601 			curexhost = newexhost;
1602 			curexpage = newexpage;
1603 			curexclass = newexclass;
1604 			if (curtime) xfree(curtime); curtime = newtime;
1605 			if (curextime) xfree(curextime); curextime = newextime;
1606 			if (curtext) xfree(curtext); curtext = newtext;
1607 			if (curgroup) xfree(curgroup); curgroup = newgroup;
1608 		}
1609 	}
1610 
1611 	stackfclose(fd);
1612 	freestrbuffer(inbuf);
1613 	if (curtime) xfree(curtime);
1614 	if (curextime) xfree(curextime);
1615 	if (curtext) xfree(curtext);
1616 
1617 	/* Create the ruletree, but leave it empty - it will be filled as clients report */
1618 	ruletree = xtreeNew(strcasecmp);
1619 	havetree = 1;
1620 
1621 	MEMUNDEFINE(fn);
1622 	return 1;
1623 }
1624 
dump_client_config(void)1625 void dump_client_config(void)
1626 {
1627 	c_rule_t *rwalk;
1628 
1629 	for (rwalk = rulehead; (rwalk); rwalk = rwalk->next) {
1630 		switch (rwalk->ruletype) {
1631 		  case C_UPTIME:
1632 			printf("UP %d %d", rwalk->rule.uptime.recentlimit, rwalk->rule.uptime.ancientlimit);
1633 			break;
1634 
1635 		  case C_CLOCK:
1636 			printf("CLOCK %d", rwalk->rule.clock.maxdiff);
1637 			break;
1638 
1639 		  case C_LOAD:
1640 			printf("LOAD %.2f %.2f", rwalk->rule.load.warnlevel, rwalk->rule.load.paniclevel);
1641 			break;
1642 
1643 		  case C_DISK:
1644 			if (!rwalk->rule.disk.fsexp) break;
1645 
1646 			printf("DISK %s", rwalk->rule.disk.fsexp->pattern);
1647 			if (rwalk->rule.disk.ignored)
1648 				printf(" IGNORE");
1649 			else {
1650 				printf(" %lu%c", rwalk->rule.disk.warnlevel, (rwalk->rule.disk.abswarn ? 'U' : '%'));
1651 				printf(" %lu%c", rwalk->rule.disk.paniclevel, (rwalk->rule.disk.abspanic  ? 'U' : '%'));
1652 				printf(" %d %d %s", rwalk->rule.disk.dmin, rwalk->rule.disk.dmax, colorname(rwalk->rule.disk.color));
1653 			}
1654 			break;
1655 
1656 		  case C_INODE:
1657 			if (!rwalk->rule.inode.fsexp) break;
1658 
1659 			printf("INODE %s", rwalk->rule.inode.fsexp->pattern);
1660 			if (rwalk->rule.inode.ignored)
1661 				printf(" IGNORE");
1662 			else {
1663 				printf(" %lu%c", rwalk->rule.inode.warnlevel, (rwalk->rule.inode.abswarn ? 'U' : '%'));
1664 				printf(" %lu%c", rwalk->rule.inode.paniclevel, (rwalk->rule.inode.abspanic  ? 'U' : '%'));
1665 				printf(" %d %d %s", rwalk->rule.inode.imin, rwalk->rule.inode.imax, colorname(rwalk->rule.inode.color));
1666 			}
1667 			break;
1668 
1669 		  case C_MEM:
1670 			switch (rwalk->rule.mem.memtype) {
1671 			  case C_MEM_PHYS: printf("MEMREAL"); break;
1672 			  case C_MEM_SWAP: printf("MEMSWAP"); break;
1673 			  case C_MEM_ACT: printf("MEMACT"); break;
1674 			}
1675 			printf(" %d %d", rwalk->rule.mem.warnlevel, rwalk->rule.mem.paniclevel);
1676 			break;
1677 
1678                   case C_ASID:
1679                         switch (rwalk->rule.asid.asidtype) {
1680                           case C_ASID_MAXUSER: printf("MAXUSER: "); break;
1681                           case C_ASID_NPARTS:  printf(" NPARTS: "); break;
1682                         }
1683                         printf(" %d %d", rwalk->rule.asid.warnlevel, rwalk->rule.asid.paniclevel);
1684                         break;
1685 
1686 		  case C_PROC:
1687 			if (!rwalk->rule.proc.procexp) break;
1688 
1689 			if (strchr(rwalk->rule.proc.procexp->pattern, ' ') ||
1690 			    strchr(rwalk->rule.proc.procexp->pattern, '\t')) {
1691 				printf("PROC \"%s\" %d %d %s", rwalk->rule.proc.procexp->pattern,
1692 				       rwalk->rule.proc.pmin, rwalk->rule.proc.pmax, colorname(rwalk->rule.proc.color));
1693 			}
1694 			else {
1695 				printf("PROC %s %d %d %s", rwalk->rule.proc.procexp->pattern,
1696 				       rwalk->rule.proc.pmin, rwalk->rule.proc.pmax, colorname(rwalk->rule.proc.color));
1697 			}
1698 			break;
1699 
1700 		  case C_LOG:
1701 			if (!rwalk->rule.log.logfile || !rwalk->rule.log.matchexp) break;
1702 
1703 			printf("LOG %s MATCH=%s COLOR=%s",
1704 				rwalk->rule.log.logfile->pattern,
1705 				rwalk->rule.log.matchexp->pattern,
1706 				colorname(rwalk->rule.log.color));
1707 			if (rwalk->rule.log.ignoreexp) printf(" IGNORE=%s", rwalk->rule.log.ignoreexp->pattern);
1708 			break;
1709 
1710 		  case C_FILE:
1711 			if (!rwalk->rule.fcheck.filename) break;
1712 
1713 			printf("FILE %s %s", rwalk->rule.fcheck.filename->pattern,
1714 				colorname(rwalk->rule.fcheck.color));
1715 
1716 			if (rwalk->flags & FCHK_NOEXIST)
1717 				printf(" noexist");
1718 			if (rwalk->flags & FCHK_TYPE)
1719 				printf(" type=%s", ftypestr(rwalk->rule.fcheck.ftype));
1720 			if (rwalk->flags & FCHK_MODE)
1721 				printf(" mode=%o", rwalk->rule.fcheck.fmode);
1722 #ifdef _LARGEFILE_SOURCE
1723 			if (rwalk->flags & FCHK_MINSIZE)
1724 				printf(" size>%lld", (long long int)rwalk->rule.fcheck.minsize);
1725 			if (rwalk->flags & FCHK_MAXSIZE)
1726 				printf(" size<%lld", (long long int)rwalk->rule.fcheck.maxsize);
1727 			if (rwalk->flags & FCHK_EQLSIZE)
1728 				printf(" size=%lld", (long long int)rwalk->rule.fcheck.eqlsize);
1729 #else
1730 			if (rwalk->flags & FCHK_MINSIZE)
1731 				printf(" size>%ld", rwalk->rule.fcheck.minsize);
1732 			if (rwalk->flags & FCHK_MAXSIZE)
1733 				printf(" size<%ld", rwalk->rule.fcheck.maxsize);
1734 			if (rwalk->flags & FCHK_EQLSIZE)
1735 				printf(" size=%ld", rwalk->rule.fcheck.eqlsize);
1736 #endif
1737 			if (rwalk->flags & FCHK_MINLINKS)
1738 				printf(" links>%u", rwalk->rule.fcheck.minlinks);
1739 			if (rwalk->flags & FCHK_MAXLINKS)
1740 				printf(" links<%u", rwalk->rule.fcheck.maxlinks);
1741 			if (rwalk->flags & FCHK_EQLLINKS)
1742 				printf(" links=%u", rwalk->rule.fcheck.eqllinks);
1743 			if (rwalk->flags & FCHK_OWNERID)
1744 				printf(" owner=%u", rwalk->rule.fcheck.ownerid);
1745 			if (rwalk->flags & FCHK_OWNERSTR)
1746 				printf(" owner=%s", rwalk->rule.fcheck.ownerstr);
1747 			if (rwalk->flags & FCHK_GROUPID)
1748 				printf(" group=%u", rwalk->rule.fcheck.groupid);
1749 			if (rwalk->flags & FCHK_GROUPSTR)
1750 				printf(" group=%s", rwalk->rule.fcheck.groupstr);
1751 			if (rwalk->flags & FCHK_CTIMEMIN)
1752 				printf(" ctime>%u", rwalk->rule.fcheck.minctimedif);
1753 			if (rwalk->flags & FCHK_CTIMEMAX)
1754 				printf(" ctime<%u", rwalk->rule.fcheck.maxctimedif);
1755 			if (rwalk->flags & FCHK_CTIMEEQL)
1756 				printf(" ctime=%u", rwalk->rule.fcheck.ctimeeql);
1757 			if (rwalk->flags & FCHK_MTIMEMIN)
1758 				printf(" mtime>%u", rwalk->rule.fcheck.minmtimedif);
1759 			if (rwalk->flags & FCHK_MTIMEMAX)
1760 				printf(" mtime<%u", rwalk->rule.fcheck.maxmtimedif);
1761 			if (rwalk->flags & FCHK_MTIMEEQL)
1762 				printf(" mtime=%u", rwalk->rule.fcheck.mtimeeql);
1763 			if (rwalk->flags & FCHK_ATIMEMIN)
1764 				printf(" atime>%u", rwalk->rule.fcheck.minatimedif);
1765 			if (rwalk->flags & FCHK_ATIMEMAX)
1766 				printf(" atime<%u", rwalk->rule.fcheck.maxatimedif);
1767 			if (rwalk->flags & FCHK_ATIMEEQL)
1768 				printf(" atime=%u", rwalk->rule.fcheck.atimeeql);
1769 			if (rwalk->flags & FCHK_MD5)
1770 				printf(" md5=%s", rwalk->rule.fcheck.md5hash);
1771 			if (rwalk->flags & FCHK_SHA1)
1772 				printf(" sha1=%s", rwalk->rule.fcheck.sha1hash);
1773 			if (rwalk->flags & FCHK_SHA256)
1774 				printf(" sha256=%s", rwalk->rule.fcheck.sha256hash);
1775 			if (rwalk->flags & FCHK_SHA512)
1776 				printf(" sha512=%s", rwalk->rule.fcheck.sha512hash);
1777 			if (rwalk->flags & FCHK_SHA224)
1778 				printf(" sha224=%s", rwalk->rule.fcheck.sha224hash);
1779 			if (rwalk->flags & FCHK_SHA384)
1780 				printf(" sha384=%s", rwalk->rule.fcheck.sha384hash);
1781 			if (rwalk->flags & FCHK_RMD160)
1782 				printf(" rmd160=%s", rwalk->rule.fcheck.rmd160hash);
1783 			break;
1784 
1785 		  case C_DIR:
1786 			if (!rwalk->rule.dcheck.filename) break;
1787 
1788 			printf("DIR %s %s", rwalk->rule.dcheck.filename->pattern,
1789 				colorname(rwalk->rule.dcheck.color));
1790 
1791 			if (rwalk->flags & FCHK_MINSIZE)
1792 				printf(" size>%lu", rwalk->rule.dcheck.minsize);
1793 			if (rwalk->flags & FCHK_MAXSIZE)
1794 				printf(" size<%lu", rwalk->rule.dcheck.maxsize);
1795 			break;
1796 
1797 		  case C_PORT:
1798 			printf("PORT");
1799 			if (rwalk->rule.port.localexp)
1800 				printf(" local=%s", rwalk->rule.port.localexp->pattern);
1801 			if (rwalk->rule.port.exlocalexp)
1802 				printf(" exlocal=%s", rwalk->rule.port.exlocalexp->pattern);
1803 			if (rwalk->rule.port.remoteexp)
1804 				printf(" remote=%s", rwalk->rule.port.remoteexp->pattern);
1805 			if (rwalk->rule.port.exremoteexp)
1806 				printf(" exremote=%s", rwalk->rule.port.exremoteexp->pattern);
1807 			if (rwalk->rule.port.stateexp)
1808 				printf(" state=%s", rwalk->rule.port.stateexp->pattern);
1809 			if (rwalk->rule.port.exstateexp)
1810 				printf(" exstate=%s", rwalk->rule.port.exstateexp->pattern);
1811 			if (rwalk->rule.port.pmin != -1)
1812 				printf(" min=%d", rwalk->rule.port.pmin);
1813 			if (rwalk->rule.port.pmax != -1)
1814 				printf(" max=%d", rwalk->rule.port.pmax);
1815 			printf(" color=%s", colorname(rwalk->rule.port.color));
1816 			break;
1817 
1818 		  case C_PAGING:
1819 			printf("PAGING %d %d", rwalk->rule.paging.warnlevel, rwalk->rule.paging.paniclevel);
1820 			break;
1821 
1822 		  case C_MEM_VSIZE:
1823 			printf("z/VSE VSIZE %d %d", rwalk->rule.zvse_vsize.warnlevel, rwalk->rule.zvse_vsize.paniclevel);
1824 			break;
1825 
1826 		  case C_MEM_GETVIS:
1827 			break;
1828 
1829 		  case C_CICS:
1830 			if (!rwalk->rule.cics.applid) break;
1831 
1832 			printf("CICS: Appid:%s, DSA warning:%d, DSA panic:%d, EDSA warning%d, EDSA panic:%d", rwalk->rule.cics.applid->pattern, rwalk->rule.cics.dsawarnlevel, rwalk->rule.cics.dsapaniclevel, rwalk->rule.cics.edsawarnlevel, rwalk->rule.cics.edsapaniclevel);
1833 			break;
1834 
1835 		  case C_SVC:
1836 			if (!rwalk->rule.svc.svcexp) break;
1837 
1838 			printf("SVC %s", rwalk->rule.svc.svcexp->pattern);
1839 			if (rwalk->rule.svc.stateexp)
1840 				printf(" status=%s", rwalk->rule.svc.stateexp->pattern);
1841 			if (rwalk->rule.svc.startupexp)
1842 				printf(" startup=%s", rwalk->rule.svc.startupexp->pattern);
1843 			printf(" color=%s", colorname(rwalk->rule.svc.color));
1844 			break;
1845 
1846 		  case C_MIBVAL:
1847 			printf("MIB");
1848 			if (rwalk->rule.mibval.mibvalexp)
1849 				printf(" %s", rwalk->rule.mibval.mibvalexp->pattern);
1850 			if (rwalk->rule.mibval.keyexp)
1851 				printf(" key=%s", rwalk->rule.mibval.keyexp->pattern);
1852 			if (rwalk->flags & MIBCHK_MINVALUE)
1853 				printf(" min=%ld", rwalk->rule.mibval.minval);
1854 			if (rwalk->flags & MIBCHK_MAXVALUE)
1855 				printf(" max=%ld", rwalk->rule.mibval.maxval);
1856 			if (rwalk->flags & MIBCHK_MATCH)
1857 				printf(" match=%s", rwalk->rule.mibval.matchexp->pattern);
1858 			printf(" color=%s", colorname(rwalk->rule.mibval.color));
1859 			break;
1860 
1861 		  case C_RRDDS:
1862 			if (!rwalk->rule.rrdds.rrdkey) break;
1863 
1864 			printf("DS %s %s:%s", rwalk->rule.rrdds.column,
1865 				rwalk->rule.rrdds.rrdkey->pattern, rwalk->rule.rrdds.rrdds);
1866 			if (rwalk->flags & RRDDSCHK_GT)
1867 				printf(" >%.2f", rwalk->rule.rrdds.limitval);
1868 			if (rwalk->flags & RRDDSCHK_GE)
1869 				printf(" >=%.2f", rwalk->rule.rrdds.limitval);
1870 
1871 			if (rwalk->flags & RRDDSCHK_INTVL) {
1872 				if (rwalk->flags & RRDDSCHK_LT)
1873 					printf(" <%.2f", rwalk->rule.rrdds.limitval2);
1874 				if (rwalk->flags & RRDDSCHK_LE)
1875 					printf(" <=%.2f", rwalk->rule.rrdds.limitval2);
1876 			}
1877 			else {
1878 				if (rwalk->flags & RRDDSCHK_LT)
1879 					printf(" <%.2f", rwalk->rule.rrdds.limitval);
1880 				if (rwalk->flags & RRDDSCHK_LE)
1881 					printf(" <=%.2f", rwalk->rule.rrdds.limitval);
1882 			}
1883 			printf(" color=%s", colorname(rwalk->rule.rrdds.color));
1884 			break;
1885 
1886 		  case C_MQ_QUEUE:
1887 			if (!rwalk->rule.mqqueue.qmgrname || !rwalk->rule.mqqueue.qname) break;
1888 
1889 			printf("MQ_QUEUE %s:%s", rwalk->rule.mqqueue.qmgrname->pattern, rwalk->rule.mqqueue.qname->pattern);
1890 			if (rwalk->rule.mqqueue.warnlen != -1)
1891 				printf(" depth-warn=%d", rwalk->rule.mqqueue.warnlen);
1892 			if (rwalk->rule.mqqueue.critlen != -1)
1893 				printf(" depth-critical=%d", rwalk->rule.mqqueue.critlen);
1894 			if (rwalk->rule.mqqueue.warnage != -1)
1895 				printf(" age-warn=%d", rwalk->rule.mqqueue.warnage);
1896 			if (rwalk->rule.mqqueue.critage != -1)
1897 				printf(" age-critical=%d", rwalk->rule.mqqueue.critage);
1898 			break;
1899 
1900 		  case C_MQ_CHANNEL:
1901 			if (!rwalk->rule.mqchannel.qmgrname || !rwalk->rule.mqchannel.chnname) break;
1902 
1903 			printf("MQ_CHANNEL %s:%s",rwalk->rule.mqchannel.qmgrname->pattern , rwalk->rule.mqchannel.chnname->pattern);
1904 			if (rwalk->rule.mqchannel.warnstates) printf(" warning=%s", rwalk->rule.mqchannel.warnstates->pattern);
1905 			if (rwalk->rule.mqchannel.alertstates) printf(" alert=%s", rwalk->rule.mqchannel.alertstates->pattern);
1906 			break;
1907 		}
1908 
1909 		if (rwalk->chkflags & CHK_TRACKIT) {
1910 			printf(" TRACK");
1911 			if (rwalk->rrdidstr) printf("=%s", rwalk->rrdidstr);
1912 		}
1913 
1914 		if (rwalk->chkflags & CHK_OPTIONAL) printf(" OPTIONAL");
1915 
1916 		if (rwalk->timespec) printf(" TIME=%s", rwalk->timespec);
1917 		if (rwalk->extimespec) printf(" EXTIME=%s", rwalk->extimespec);
1918 		if (rwalk->hostexp) printf(" HOST=%s", rwalk->hostexp->pattern);
1919 		if (rwalk->exhostexp) printf(" EXHOST=%s", rwalk->exhostexp->pattern);
1920 		if (rwalk->dgexp) printf(" DISPLAYGROUP=%s", rwalk->dgexp->pattern);
1921 		if (rwalk->exdgexp) printf(" EXDISPLAYGROUP=%s", rwalk->exdgexp->pattern);
1922 		if (rwalk->pageexp) printf(" PAGE=%s", rwalk->pageexp->pattern);
1923 		if (rwalk->expageexp) printf(" EXPAGE=%s", rwalk->expageexp->pattern);
1924 		if (rwalk->classexp) printf(" CLASS=%s", rwalk->classexp->pattern);
1925 		if (rwalk->exclassexp) printf(" EXCLASS=%s", rwalk->exclassexp->pattern);
1926 		if (rwalk->statustext) printf(" TEXT=%s", rwalk->statustext);
1927 		printf(" (line: %d)\n", rwalk->cfid);
1928 	}
1929 }
1930 
getrule(char * hostname,char * pagename,char * classname,void * hinfo,ruletype_t ruletype)1931 static c_rule_t *getrule(char *hostname, char *pagename, char *classname, void *hinfo, ruletype_t ruletype)
1932 {
1933 	static ruleset_t *rwalk = NULL;
1934 	char *holidayset;
1935 
1936 	if (hostname || pagename) {
1937 		rwalk = ruleset(hostname, pagename, classname);
1938 	}
1939 	else {
1940 		if (rwalk) rwalk = rwalk->next;
1941 	}
1942 
1943 	holidayset = (hinfo ? xmh_item(hinfo, XMH_HOLIDAYS) : NULL);
1944 
1945 	for (; (rwalk); rwalk = rwalk->next) {
1946 		if (rwalk->rule->ruletype != ruletype) continue;
1947 		if (rwalk->rule->timespec && !timematch(holidayset, rwalk->rule->timespec)) continue;
1948 		if (rwalk->rule->extimespec && timematch(holidayset, rwalk->rule->extimespec)) continue;
1949 
1950 		/* If we get here, then we have something that matches */
1951 		return rwalk->rule;
1952 	}
1953 
1954 	return NULL;
1955 }
1956 
get_cpu_thresholds(void * hinfo,char * classname,float * loadyellow,float * loadred,int * recentlimit,int * ancientlimit,int * uptimecolor,int * maxclockdiff,int * clockdiffcolor)1957 int get_cpu_thresholds(void *hinfo, char *classname,
1958 		       float *loadyellow, float *loadred,
1959 		       int *recentlimit, int *ancientlimit, int *uptimecolor,
1960 		       int *maxclockdiff, int *clockdiffcolor)
1961 {
1962 	int result = 0;
1963 	char *hostname, *pagename;
1964 	c_rule_t *rule;
1965 
1966 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
1967 	pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
1968 
1969 	*loadyellow = 5.0;
1970 	*loadred = 10.0;
1971 	*uptimecolor = *clockdiffcolor = COL_YELLOW;
1972 
1973 	rule = getrule(hostname, pagename, classname, hinfo, C_LOAD);
1974 	if (rule) {
1975 		*loadyellow = rule->rule.load.warnlevel;
1976 		*loadred    = rule->rule.load.paniclevel;
1977 		result = rule->cfid;
1978 	}
1979 
1980 	*recentlimit = 3600;
1981 	*ancientlimit = -1;
1982 
1983 	rule = getrule(hostname, pagename, classname, hinfo, C_UPTIME);
1984 	if (rule) {
1985 		*recentlimit  = rule->rule.uptime.recentlimit;
1986 		*ancientlimit = rule->rule.uptime.ancientlimit;
1987 		*uptimecolor = rule->rule.uptime.color;
1988 		result = rule->cfid;
1989 	}
1990 
1991 	*maxclockdiff = -1;
1992 	rule = getrule(hostname, pagename, classname, hinfo, C_CLOCK);
1993 	if (rule) {
1994 		*maxclockdiff = rule->rule.clock.maxdiff;
1995 		*clockdiffcolor = rule->rule.clock.color;
1996 	}
1997 
1998 	return result;
1999 }
2000 
get_disk_thresholds(void * hinfo,char * classname,char * fsname,long * warnlevel,long * paniclevel,int * abswarn,int * abspanic,int * ignored,char ** group)2001 int get_disk_thresholds(void *hinfo, char *classname,
2002 			char *fsname,
2003 			long *warnlevel, long *paniclevel,
2004 			int *abswarn, int *abspanic,
2005 			int *ignored, char **group)
2006 {
2007 	char *hostname, *pagename;
2008 	c_rule_t *rule;
2009 
2010 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
2011 	pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
2012 
2013 	*warnlevel = 90;
2014 	*paniclevel = 95;
2015 	*abswarn = 0;
2016 	*abspanic = 0;
2017 	*ignored = 0;
2018 	*group = NULL;
2019 
2020 	rule = getrule(hostname, pagename, classname, hinfo, C_DISK);
2021 	while (rule && (!rule->rule.disk.fsexp || !namematch(fsname, rule->rule.disk.fsexp->pattern, rule->rule.disk.fsexp->exp))) {
2022 		rule = getrule(NULL, NULL, NULL, hinfo, C_DISK);
2023 	}
2024 
2025 	if (rule) {
2026 		*warnlevel = rule->rule.disk.warnlevel;
2027 		*abswarn = rule->rule.disk.abswarn;
2028 		*paniclevel = rule->rule.disk.paniclevel;
2029 		*abspanic = rule->rule.disk.abspanic;
2030 		*ignored = rule->rule.disk.ignored;
2031 		*group = rule->groups;
2032 		return rule->cfid;
2033 	}
2034 
2035 	return 0;
2036 }
2037 
get_inode_thresholds(void * hinfo,char * classname,char * fsname,long * warnlevel,long * paniclevel,int * abswarn,int * abspanic,int * ignored,char ** group)2038 int get_inode_thresholds(void *hinfo, char *classname,
2039 		char *fsname,
2040 		long *warnlevel, long *paniclevel,
2041 		int *abswarn, int *abspanic,
2042 		int *ignored, char **group)
2043 {
2044 	char *hostname, *pagename;
2045 	c_rule_t *rule;
2046 
2047 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
2048 	pagename = xmh_item(hinfo, XMH_PAGEPATH);
2049 
2050 	*warnlevel = 70;
2051 	*paniclevel = 90;
2052 	*abswarn = 0;
2053 	*abspanic = 0;
2054 	*ignored = 0;
2055 	*group = NULL;
2056 
2057 	rule = getrule(hostname, pagename, classname, hinfo, C_INODE);
2058 	while (rule && (!rule->rule.inode.fsexp || !namematch(fsname, rule->rule.inode.fsexp->pattern, rule->rule.inode.fsexp->exp))) {
2059 		rule = getrule(NULL, NULL, NULL, hinfo, C_INODE);
2060 	}
2061 
2062 	if (rule) {
2063 		*warnlevel = rule->rule.inode.warnlevel;
2064 		*abswarn = rule->rule.inode.abswarn;
2065 		*paniclevel = rule->rule.inode.paniclevel;
2066 		*abspanic = rule->rule.inode.abspanic;
2067 		*ignored = rule->rule.inode.ignored;
2068 		*group = rule->groups;
2069 		return rule->cfid;
2070 	}
2071 
2072 	return 0;
2073 }
2074 
get_cics_thresholds(void * hinfo,char * classname,char * appid,int * dsayel,int * dsared,int * edsayel,int * edsared)2075 void get_cics_thresholds(void *hinfo, char *classname, char *appid,
2076                         int *dsayel, int *dsared, int *edsayel, int *edsared)
2077 {
2078         char *hostname, *pagename;
2079         c_rule_t *rule;
2080 
2081         hostname = xmh_item(hinfo, XMH_HOSTNAME);
2082         pagename = xmh_item(hinfo, XMH_PAGEPATH);
2083 
2084         *dsayel = 90;
2085         *dsared = 95;
2086         *edsayel = 90;
2087         *edsared = 95;
2088 
2089 /* Get thresholds for CICS DSA */
2090         rule = getrule(hostname, pagename, classname, hinfo, C_CICS);
2091 
2092 /* This is sort of cheating, because the while statement that follows should catch it
2093    but it doesn't.  So if there is a way to solve the problem I welcome some tips...   */
2094 	if (!rule) {
2095 		return;
2096 		}
2097 
2098         while (rule && (!rule->rule.cics.applid || !namematch(appid, rule->rule.cics.applid->pattern, rule->rule.cics.applid->exp))) {
2099                 rule = getrule(NULL, NULL, NULL, hinfo, C_CICS);
2100         }
2101 
2102         if (rule) {
2103                 *dsayel = rule->rule.cics.dsawarnlevel;
2104                 *dsared = rule->rule.cics.dsapaniclevel;
2105                 *edsayel = rule->rule.cics.edsawarnlevel;
2106                 *edsared = rule->rule.cics.edsapaniclevel;
2107         }
2108 
2109 }
2110 
get_zvsevsize_thresholds(void * hinfo,char * classname,int * usedyel,int * usedred)2111 void get_zvsevsize_thresholds(void *hinfo, char *classname,
2112                         int *usedyel, int *usedred)
2113 {
2114         char *hostname, *pagename;
2115         c_rule_t *rule;
2116 
2117         hostname = xmh_item(hinfo, XMH_HOSTNAME);
2118         pagename = xmh_item(hinfo, XMH_PAGEPATH);
2119 
2120         *usedyel = 90;
2121         *usedred = 95;
2122 
2123 /* Get thresholds for z/VSE System Memory */
2124         rule = getrule(hostname, pagename, classname, hinfo, C_MEM_VSIZE);
2125 
2126         if (rule) {
2127                 *usedyel = rule->rule.zvse_vsize.warnlevel;
2128                 *usedred = rule->rule.zvse_vsize.paniclevel;
2129         }
2130 }
2131 
get_zvsegetvis_thresholds(void * hinfo,char * classname,char * pid,int * gv24yel,int * gv24red,int * gvanyyel,int * gvanyred)2132 void get_zvsegetvis_thresholds(void *hinfo, char *classname, char *pid,
2133                         int *gv24yel, int *gv24red, int *gvanyyel, int *gvanyred)
2134 {
2135         char *hostname, *pagename;
2136         c_rule_t *rule;
2137 
2138         hostname = xmh_item(hinfo, XMH_HOSTNAME);
2139         pagename = xmh_item(hinfo, XMH_PAGEPATH);
2140 
2141         *gv24yel = 90;
2142         *gv24red = 95;
2143         *gvanyyel = 90;
2144         *gvanyred = 95;
2145 
2146 /* Get thresholds for z/VSE Partition Getvis */
2147         rule = getrule(hostname, pagename, classname, hinfo, C_MEM_GETVIS);
2148 
2149 /* This is sort of cheating, because the while statement that follows should catch it
2150    but it doesn't.  So if there is a way to solve the problem I welcome some tips...   */
2151 	if (!rule) {
2152 		return;
2153 		}
2154 
2155         while (rule && (!rule->rule.zvse_getvis.partid || !namematch(pid, rule->rule.zvse_getvis.partid->pattern, rule->rule.zvse_getvis.partid->exp))) {
2156                 rule = getrule(NULL, NULL, NULL, hinfo, C_MEM_GETVIS);
2157         	}
2158 
2159         if (rule) {
2160                 *gv24yel  = rule->rule.zvse_getvis.warnlevel;
2161                 *gv24red  = rule->rule.zvse_getvis.paniclevel;
2162                 *gvanyyel = rule->rule.zvse_getvis.anywarnlevel;
2163                 *gvanyred = rule->rule.zvse_getvis.anypaniclevel;
2164         	}
2165 }
2166 
get_memory_thresholds(void * hinfo,char * classname,int * physyellow,int * physred,int * swapyellow,int * swapred,int * actyellow,int * actred)2167 void get_memory_thresholds(void *hinfo, char *classname,
2168 			   int *physyellow, int *physred, int *swapyellow, int *swapred, int *actyellow, int *actred)
2169 {
2170 	char *hostname, *pagename;
2171 	c_rule_t *rule;
2172 	int gotphys = 0, gotswap = 0, gotact = 0;
2173 
2174 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
2175 	pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
2176 
2177 	*physyellow = 100;
2178 	*physred = 101;
2179 	*swapyellow = 50;
2180 	*swapred = 80;
2181 	*actyellow = 90;
2182 	*actred = 97;
2183 
2184 	rule = getrule(hostname, pagename, classname, hinfo, C_MEM);
2185 	while (rule) {
2186 		switch (rule->rule.mem.memtype) {
2187 		  case C_MEM_PHYS:
2188 			if (!gotphys) {
2189 				*physyellow = rule->rule.mem.warnlevel;
2190 				*physred    = rule->rule.mem.paniclevel;
2191 				gotphys     = 1;
2192 			}
2193 			break;
2194 		  case C_MEM_ACT:
2195 			if (!gotact) {
2196 				*actyellow  = rule->rule.mem.warnlevel;
2197 				*actred     = rule->rule.mem.paniclevel;
2198 				gotact      = 1;
2199 			}
2200 			break;
2201 		  case C_MEM_SWAP:
2202 			if (!gotswap) {
2203 				*swapyellow = rule->rule.mem.warnlevel;
2204 				*swapred    = rule->rule.mem.paniclevel;
2205 				gotswap     = 1;
2206 			}
2207 			break;
2208 		}
2209 		rule = getrule(NULL, NULL, NULL, hinfo, C_MEM);
2210 	}
2211 }
2212 
get_zos_memory_thresholds(void * hinfo,char * classname,int * csayellow,int * csared,int * ecsayellow,int * ecsared,int * sqayellow,int * sqared,int * esqayellow,int * esqared)2213 void get_zos_memory_thresholds(void *hinfo, char *classname,
2214                                int *csayellow, int *csared, int *ecsayellow, int *ecsared,
2215 			       int *sqayellow, int *sqared, int *esqayellow, int *esqared)
2216 {
2217         char *hostname, *pagename;
2218         c_rule_t *rule;
2219         int gotcsa = 0, gotecsa = 0, gotsqa = 0, gotesqa = 0;
2220 
2221         hostname = xmh_item(hinfo, XMH_HOSTNAME);
2222         pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
2223 
2224         *csayellow = 90;
2225         *csared = 95;
2226         *ecsayellow = 90;
2227         *ecsared = 95;
2228         *sqayellow = 90;
2229         *sqared = 95;
2230         *esqayellow = 90;
2231         *esqared = 95;
2232 
2233         rule = getrule(hostname, pagename, classname, hinfo, C_MEM);
2234         while (rule) {
2235                 switch (rule->rule.zos_mem.zos_memtype) {
2236                   case C_MEM_CSA:
2237                         if (!gotcsa) {
2238                                 *csayellow = rule->rule.zos_mem.warnlevel;
2239                                 *csared    = rule->rule.zos_mem.paniclevel;
2240                                 gotcsa     = 1;
2241                         }
2242                         break;
2243                   case C_MEM_ECSA:
2244                         if (!gotecsa) {
2245                                 *ecsayellow = rule->rule.zos_mem.warnlevel;
2246                                 *ecsared    = rule->rule.zos_mem.paniclevel;
2247                                 gotecsa     = 1;
2248                         }
2249                         break;
2250                   case C_MEM_SQA:
2251                         if (!gotsqa) {
2252                                 *sqayellow = rule->rule.zos_mem.warnlevel;
2253                                 *sqared    = rule->rule.zos_mem.paniclevel;
2254                                 gotsqa     = 1;
2255                         }
2256                         break;
2257                   case C_MEM_ESQA:
2258                         if (!gotesqa) {
2259                                 *esqayellow = rule->rule.zos_mem.warnlevel;
2260                                 *esqared    = rule->rule.zos_mem.paniclevel;
2261                                 gotesqa     = 1;
2262                         }
2263                         break;
2264                 }
2265                 rule = getrule(NULL, NULL, NULL, hinfo, C_MEM);
2266         }
2267 
2268 }
2269 
2270 /* This routine doubles to get threshold values for z/OS Maxuser and z/VSE Nparts.  */
get_asid_thresholds(void * hinfo,char * classname,int * maxyellow,int * maxred)2271 void get_asid_thresholds(void *hinfo, char *classname,
2272                                int *maxyellow, int *maxred)
2273 {
2274         int gotmaxuser = 0, gotnparts = 0;
2275         char *hostname, *pagename;
2276         c_rule_t *rule;
2277 
2278         hostname = xmh_item(hinfo, XMH_HOSTNAME);
2279         pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
2280 
2281         *maxyellow = 101;
2282         *maxred = 101;
2283 
2284         rule = getrule(hostname, pagename, classname, hinfo, C_ASID);
2285         while (rule) {
2286                 switch (rule->rule.asid.asidtype) {
2287 			case C_ASID_MAXUSER:
2288 				if (!gotmaxuser) {
2289         				*maxyellow = rule->rule.asid.warnlevel;
2290 			        	*maxred    = rule->rule.asid.paniclevel;
2291 					gotmaxuser = 1;
2292 				}
2293 				break;
2294                         case C_ASID_NPARTS:
2295                                 if (!gotnparts) {
2296                                         *maxyellow = rule->rule.asid.warnlevel;
2297                                         *maxred    = rule->rule.asid.paniclevel;
2298 					gotnparts  = 1;
2299                                 }
2300                                 break;
2301 		}
2302                 rule = getrule(NULL, NULL, NULL, hinfo, C_ASID);
2303         }
2304 
2305 }
2306 
get_paging_thresholds(void * hinfo,char * classname,int * pagingyellow,int * pagingred)2307 int get_paging_thresholds(void *hinfo, char *classname, int *pagingyellow, int *pagingred)
2308 {
2309 	int result = 0;
2310 	char *hostname, *pagename;
2311 	c_rule_t *rule;
2312 
2313 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
2314 	pagename = xmh_item(hinfo, XMH_PAGEPATH);
2315 
2316 	*pagingyellow = 5;
2317 	*pagingred = 10;
2318 
2319 	rule = getrule(hostname, pagename, classname, hinfo, C_PAGING);
2320 	if (rule) {
2321 		*pagingyellow = rule->rule.paging.warnlevel;
2322 		*pagingred    = rule->rule.paging.paniclevel;
2323 		result = rule->cfid;
2324 	}
2325 
2326 	return result;
2327 }
2328 
get_mibval_thresholds(void * hinfo,char * classname,char * mibname,char * keyname,char * valname,long * minval,long * maxval,void ** matchexp,int * color,char ** group)2329 int get_mibval_thresholds(void *hinfo, char *classname,
2330 			  char *mibname, char *keyname, char *valname,
2331 			  long *minval, long *maxval, void **matchexp, int *color, char **group)
2332 {
2333 	static void * mibnametree;
2334 	static int have_mibnametree = 0;
2335 	char *hostname, *pagename, *mibkeyval_id;
2336 	c_rule_t *rule;
2337 	xtreePos_t namhandle, valdefhandle;
2338 	void * valdeftree;
2339 
2340 	if (!have_mibnametree) {
2341 		mibnametree = xtreeNew(strcasecmp);
2342 		have_mibnametree = 1;
2343 	}
2344 
2345 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
2346 	pagename = xmh_item(hinfo, XMH_PAGEPATH);
2347 
2348 	/* Any potential rules at all ? */
2349 	rule = getrule(hostname, pagename, classname, hinfo, C_MIBVAL);
2350 	if (!rule) return -1;
2351 
2352 	*minval = LONG_MIN;
2353 	*maxval = LONG_MAX;
2354 	*matchexp = NULL;
2355 	*color = COL_GREEN;
2356 	*group = NULL;
2357 
2358 	/*
2359 	 * Configuration rules are indexed by three items:
2360 	 * - the MIB Name
2361 	 * - the MIB Key
2362 	 * - the Value Name
2363 	 *
2364 	 * The MIB- and Value-names are static, so we combine these into
2365 	 * a single key which is referenced directly in the configuration.
2366 	 * This is the pattern listed as the first MIB criteria in the config,
2367 	 * stored in the "mibvalexp" field.
2368 	 * For the MIB Keys we want to use a regex (so the config can refer to
2369 	 * all "eth.*" interfaces), so when searching for a rule we must walk
2370 	 * the list of potential rules for this MIB+Value name, and match the
2371 	 * actual key value against the pattern.
2372 	 *
2373 	 * So all in all rules are keyed with the MIB+Key+Name strings as
2374 	 * a unique key. Hence, to speed things up we gradually build a tree
2375 	 * with this key, which points directly to the rule for this item.
2376 	 * This is the "valdeftree" tree.
2377 	 *
2378 	 * TODO: A further optimization would be to somehow keep
2379 	 * track of how many single MIB variables have a configuration rule,
2380 	 * to avoid scanning for a configuration for variables when all config
2381 	 * items have been used in a message. I cannot tell right away if this
2382 	 * is possible - perhaps by counting the number of configuration cache
2383 	 * hits while processing a message, and for the next message from the
2384 	 * same source then only process data until this count has been done?
2385 	 *
2386 	 * Finally, for optimising memory usage, the MIB+Key+Name strings
2387 	 * are not duplicated for each key; instead we have a separate token-
2388 	 * tree (mibnametree) which holds these.
2389 	 */
2390 
2391 	/* Setup the key and find/insert it into the mibnametree */
2392 	mibkeyval_id = (char *)malloc(strlen(mibname) + (keyname ? strlen(keyname) : 0) + strlen(valname) + 3);
2393 	sprintf(mibkeyval_id, "%s!%s!%s", mibname, (keyname ? keyname : ""), valname);
2394 	namhandle = xtreeFind(mibnametree, mibkeyval_id);
2395 	if (namhandle == xtreeEnd(mibnametree)) {
2396 		xtreeAdd(mibnametree, mibkeyval_id, mibkeyval_id);
2397 	}
2398 	else {
2399 		xfree(mibkeyval_id); /* Discard our copy - we now use the tree value */
2400 		mibkeyval_id = (char *)xtreeData(mibnametree, namhandle);
2401 	}
2402 
2403 	/* Create the rule tree (if it does not exist); look up the ruleset */
2404 	if (!rule->rule.mibval.havetree) {
2405 		rule->rule.mibval.havetree = 1;
2406 		valdeftree = rule->rule.mibval.valdeftree = xtreeNew(strcasecmp);
2407 		valdefhandle = xtreeEnd(rule->rule.mibval.valdeftree);
2408 	}
2409 	else {
2410 		valdeftree = rule->rule.mibval.valdeftree;
2411 		valdefhandle = xtreeFind(valdeftree, mibkeyval_id);
2412 	}
2413 
2414 	if (valdefhandle == xtreeEnd(valdeftree)) {
2415 		/*
2416 		 * Ruleset not in the tree.
2417 		 * Scan the configuration set for a rule matching this
2418 		 * MIB+Value name, and where the keyname matches.
2419 		 * Then insert the result into the tree (even if there is no
2420 		 * rule matching at all - we also cache the negative lookups!
2421 		 */
2422 		int found = 0;
2423 		char *mibval_id = (char *)malloc(strlen(mibname) + strlen(valname) + 2);
2424 		sprintf(mibval_id, "%s:%s", mibname, valname);
2425 
2426 		while (rule && !found) {
2427 			found = (rule->rule.mibval.mibvalexp && namematch(mibval_id, rule->rule.mibval.mibvalexp->pattern, rule->rule.mibval.mibvalexp->exp));
2428 			if (found && keyname && rule->rule.mibval.keyexp)
2429 				found = namematch(keyname, rule->rule.mibval.keyexp->pattern, rule->rule.mibval.keyexp->exp);
2430 			if (!found) rule = getrule(NULL, NULL, NULL, hinfo, C_MIBVAL);
2431 		}
2432 
2433 		xtreeAdd(valdeftree, mibkeyval_id, rule);
2434 
2435 		xfree(mibval_id);
2436 	}
2437 	else {
2438 		/* Found the rule */
2439 		rule = (c_rule_t *)xtreeData(valdeftree, valdefhandle);
2440 	}
2441 
2442 	if (rule) {
2443 		*color = rule->rule.mibval.color;
2444 		*group = rule->groups;
2445 		if (rule->flags & MIBCHK_MINVALUE) *minval = rule->rule.mibval.minval;
2446 		if (rule->flags & MIBCHK_MAXVALUE) *maxval = rule->rule.mibval.maxval;
2447 		if (rule->flags & MIBCHK_MATCH) *matchexp = rule->rule.mibval.matchexp;
2448 	}
2449 
2450 	return (rule ? rule->cfid : 0);
2451 }
2452 
2453 
check_mibvals(void * hinfo,char * classname,char * mibname,char * keyname,char * mibdata,strbuffer_t * summarybuf,int * anyrules)2454 int check_mibvals(void *hinfo, char *classname,
2455 		  char *mibname, char *keyname, char *mibdata,
2456 		  strbuffer_t *summarybuf, int *anyrules)
2457 {
2458 	char *bol, *eoln, *dnam, *dval, *delimp, delim;
2459 	long minval, maxval, actval;
2460 	void *matchexp;
2461 	int rulecolor, color = COL_GREEN;
2462 	char msgline[MAX_LINE_LEN];
2463 	char *group;
2464 
2465 	/*
2466 	 * Scan a single section of MIB data - without the [key] line -
2467 	 * and check all values against the configured limits.
2468 	 */
2469 	*anyrules = 1;
2470 	bol = mibdata;
2471 	while (bol && *anyrules) {
2472 		eoln = strchr(bol, '\n'); if (eoln) *eoln = '\0';
2473 		dnam = bol + strspn(bol, " \t");
2474 		delimp = dnam + strcspn(dnam, " ="); delim = *delimp; *delimp = '\0';
2475 		dval = delimp + 1; dval += strspn(dval, " ="); actval = atol(dval);
2476 
2477 		switch (get_mibval_thresholds(hinfo, classname, mibname, keyname, dnam, &minval, &maxval, &matchexp, &rulecolor, &group)) {
2478 		  case -1:
2479 			/* This means: No rules at all for this host. So just drop all further processing */
2480 			*anyrules = 0;
2481 			break;
2482 
2483 		  case 0:
2484 			/* No rules for this key/value, but there might be for others */
2485 			break;
2486 
2487 		  default:
2488 			if (actval < minval) {
2489 				if (keyname)
2490 					sprintf(msgline, "&%s %s:%s %ld (minimum: %ld)\n",
2491 						colorname(rulecolor), keyname, dnam, actval, minval);
2492 				else
2493 					sprintf(msgline, "&%s %s %ld (minimum: %ld)\n",
2494 						colorname(rulecolor), dnam, actval, minval);
2495 				addtobuffer(summarybuf, msgline);
2496 				if (rulecolor > color) color = rulecolor;
2497 				if (group) addalertgroup(group);
2498 			}
2499 
2500 			if (actval > maxval) {
2501 				if (keyname)
2502 					sprintf(msgline, "&%s %s:%s %ld (maximum: %ld)\n",
2503 						colorname(rulecolor), keyname, dnam, actval, maxval);
2504 				else
2505 					sprintf(msgline, "&%s %s %ld (maximum: %ld)\n",
2506 						colorname(rulecolor), dnam, actval, maxval);
2507 				addtobuffer(summarybuf, msgline);
2508 				if (rulecolor > color) color = rulecolor;
2509 				if (group) addalertgroup(group);
2510 			}
2511 
2512 			if (matchexp) {
2513 				if (!namematch(dval, ((exprlist_t *)matchexp)->pattern, ((exprlist_t *)matchexp)->exp)) {
2514 					if (rulecolor > color) color = rulecolor;
2515 					if (group) addalertgroup(group);
2516 
2517 					if (keyname)
2518 						sprintf(msgline, "&%s %s:%s %s (expected: %s)\n",
2519 								colorname(rulecolor), keyname, dnam, dval, ((exprlist_t *)matchexp)->pattern);
2520 					else
2521 						sprintf(msgline, "&%s %s %s (expected: %s)\n",
2522 								colorname(rulecolor), dnam, dval, ((exprlist_t *)matchexp)->pattern);
2523 				}
2524 				else {
2525 					if (keyname)
2526 						sprintf(msgline, "&green %s:%s %s\n", keyname, dnam, dval);
2527 					else
2528 						sprintf(msgline, "&green %s %s\n", dnam, dval);
2529 				}
2530 
2531 				addtobuffer(summarybuf, msgline);
2532 			}
2533 			break;
2534 		}
2535 
2536 		*delimp = delim;
2537 		if (eoln) {
2538 			*eoln = '\n';
2539 			bol = eoln + 1;
2540 		}
2541 		else {
2542 			bol = NULL;
2543 		}
2544 	}
2545 
2546 	return color;
2547 }
2548 
scan_log(void * hinfo,char * classname,char * logname,char * logdata,char * section,strbuffer_t * summarybuf)2549 int scan_log(void *hinfo, char *classname,
2550 	     char *logname, char *logdata, char *section, strbuffer_t *summarybuf)
2551 {
2552 	int result = COL_GREEN;
2553 	char *hostname, *pagename;
2554 	c_rule_t *rule;
2555 	int nofile = 0;
2556 	char *boln, *eoln;
2557 	char msgline[PATH_MAX];
2558 
2559 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
2560 	pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
2561 
2562 	nofile = (strncmp(logdata, "Cannot open logfile ", 20) == 0);
2563 
2564 	for (rule = getrule(hostname, pagename, classname, hinfo, C_LOG); (rule); rule = getrule(NULL, NULL, NULL, hinfo, C_LOG)) {
2565 		int anylines = 0;
2566 
2567 		/* First, check if the filename matches */
2568 		if (!rule->rule.log.logfile || !namematch(logname, rule->rule.log.logfile->pattern, rule->rule.log.logfile->exp)) continue;
2569 
2570 		if (nofile) {
2571 			if (!(rule->chkflags & CHK_OPTIONAL)) {
2572 				if (COL_YELLOW > result) result = COL_YELLOW;
2573 				addalertgroup(rule->groups);
2574 				addtobuffer(summarybuf, "&yellow Logfile not accessible \n");
2575 			}
2576 
2577 			continue;
2578 		}
2579 
2580 		/* Next, check for a match anywhere in the data*/
2581 		if (!(rule->rule.log.matchexp && patternmatch(logdata, rule->rule.log.matchexp->pattern, rule->rule.log.matchexp->exp))) continue;
2582 
2583 		/* Some data in there matches what we want. Look at each line. */
2584 		boln = logdata;
2585 		while (boln) {
2586 			eoln = strchr(boln, '\n'); if (eoln) *eoln = '\0';
2587 			if (patternmatch(boln, rule->rule.log.matchone->pattern, rule->rule.log.matchone->exp)) {
2588 				dbgprintf("Line '%s' matches\n", boln);
2589 
2590 				/* It matches. But maybe we'll ignore it ? */
2591 				if (rule->rule.log.ignoreexp && patternmatch(boln, rule->rule.log.ignoreexp->pattern, rule->rule.log.ignoreexp->exp)) {
2592 					/* Ignore it */
2593 				}
2594 				else {
2595 					/* We wants it ... */
2596 					dbgprintf("FOUND match in line '%s'\n", boln);
2597 					anylines++;
2598 					sprintf(msgline, "&%s ", colorname(rule->rule.log.color));
2599 					addtobuffer(summarybuf, msgline);
2600 					addtobuffer(summarybuf, prehtmlquoted(boln));
2601 					addtobuffer(summarybuf, "\n");
2602 				}
2603 			}
2604 
2605 			if (eoln) {
2606 				*eoln = '\n';
2607 				boln = eoln+1;
2608 			}
2609 			else boln = NULL;
2610 		}
2611 
2612 		/* We have a match */
2613 		if (anylines) {
2614 			dbgprintf("Log rule at line %d matched\n", rule->cfid);
2615 			if (rule->rule.log.color != COL_GREEN) addalertgroup(rule->groups);
2616 			if (rule->rule.log.color > result) result = rule->rule.log.color;
2617 		}
2618 	}
2619 
2620 	return result;
2621 }
2622 
check_file(void * hinfo,char * classname,char * filename,char * filedata,char * section,strbuffer_t * summarybuf,off_t * filesize,char ** id,int * trackit,int * anyrules)2623 int check_file(void *hinfo, char *classname,
2624 	       char *filename, char *filedata, char *section,
2625 	       strbuffer_t *summarybuf, off_t *filesize,
2626 	       char **id, int *trackit, int *anyrules)
2627 {
2628 	int result = COL_GREEN;
2629 	char *hostname, *pagename;
2630 	c_rule_t *rwalk;
2631 	char *boln, *eoln;
2632 	char msgline[PATH_MAX];
2633 
2634 	int exists = 1, ftype = 0, islink = 0;
2635 	off_t fsize = 0;
2636 	unsigned int fmode = 0, linkcount = 0;
2637 	int ownerid = -1, groupid = -1;
2638 	char *ownerstr = NULL, *groupstr = NULL;
2639 	unsigned int ctime = 0, mtime = 0, atime = 0, clock = 0;
2640 	unsigned int ctimedif, mtimedif, atimedif;
2641 	char *md5hash = NULL, *sha1hash = NULL, *sha256hash = NULL, *sha512hash = NULL, *sha224hash = NULL, *sha384hash = NULL, *rmd160hash = NULL;
2642 
2643 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
2644 	pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
2645 	*trackit = *anyrules = 0;
2646 
2647 	boln = filedata;
2648 	while (boln && *boln) {
2649 		eoln = strchr(boln, '\n'); if (eoln) *eoln = '\0';
2650 
2651 		if (strncmp(boln, "ERROR:", 6) == 0) {
2652 			exists = 0;
2653 		}
2654 		else if (strncmp(boln, "type:", 5) == 0) {
2655 			char *tstr;
2656 
2657 			tstr = strchr(boln, '(');
2658 			if (tstr) {
2659 				if (strncmp(tstr, "(file", 5) == 0) ftype = S_IFREG;
2660 				else if (strncmp(tstr, "(directory", 10) == 0) ftype = S_IFDIR;
2661 				else if (strncmp(tstr, "(char-device", 12) == 0) ftype = S_IFCHR;
2662 				else if (strncmp(tstr, "(block-device", 13) == 0) ftype = S_IFBLK;
2663 				else if (strncmp(tstr, "(FIFO", 5) == 0) ftype = S_IFIFO;
2664 				else if (strncmp(tstr, "(socket", 7) == 0) ftype = S_IFSOCK;
2665 				else if (strstr(tstr, ", symlink -> ") == 0) islink = 1;
2666 			}
2667 		}
2668 		else if (strncmp(boln, "mode:", 5) == 0) {
2669 			fmode = strtol(boln+5, NULL, 8);
2670 		}
2671 		else if (strncmp(boln, "linkcount:", 10) == 0) {
2672 			linkcount = atoi(boln+6);
2673 		}
2674 		else if (strncmp(boln, "owner:", 6) == 0) {
2675 			ownerid = atoi(boln+6);
2676 			ownerstr = strchr(boln, '(');
2677 			if (ownerstr) {
2678 				char *estr;
2679 				ownerstr++;
2680 				estr = strchr(ownerstr, ')'); if (estr) *estr = '\0';
2681 			}
2682 		}
2683 		else if (strncmp(boln, "group:", 6) == 0) {
2684 			groupid = atoi(boln+6);
2685 			groupstr = strchr(boln, '(');
2686 			if (groupstr) {
2687 				char *estr;
2688 				groupstr++;
2689 				estr = strchr(groupstr, ')'); if (estr) *estr = '\0';
2690 			}
2691 		}
2692 		else if (strncmp(boln, "size:", 5) == 0) {
2693 			fsize = filesize_value(boln+5);
2694 		}
2695 		else if (strncmp(boln, "clock:", 6) == 0) {
2696 			clock = atoi(boln+6);
2697 		}
2698 		else if (strncmp(boln, "atime:", 6) == 0) {
2699 			atime = atoi(boln+6);
2700 		}
2701 		else if (strncmp(boln, "ctime:", 6) == 0) {
2702 			ctime = atoi(boln+6);
2703 		}
2704 		else if (strncmp(boln, "mtime:", 6) == 0) {
2705 			mtime = atoi(boln+6);
2706 		}
2707 		else if (strncmp(boln, "md5:", 4) == 0) {
2708 			md5hash = boln+4;
2709 		}
2710 		else if (strncmp(boln, "sha1:", 5) == 0) {
2711 			sha1hash = boln+5;
2712 		}
2713 		else if (strncmp(boln, "sha256:", 7) == 0) {
2714 			sha256hash = boln+7;
2715 		}
2716 		else if (strncmp(boln, "sha512:", 7) == 0) {
2717 			sha512hash = boln+7;
2718 		}
2719 		else if (strncmp(boln, "sha224:", 7) == 0) {
2720 			sha224hash = boln+7;
2721 		}
2722 		else if (strncmp(boln, "sha384:", 7) == 0) {
2723 			sha384hash = boln+7;
2724 		}
2725 		else if (strncmp(boln, "rmd160:", 7) == 0) {
2726 			rmd160hash = boln+7;
2727 		}
2728 
2729 		if (eoln) { boln = eoln+1; } else boln = NULL;
2730 	}
2731 
2732 	*filesize = fsize;
2733 
2734 	if (clock == 0) clock = getcurrenttime(NULL);
2735 	ctimedif = clock - ctime;
2736 	atimedif = clock - atime;
2737 	mtimedif = clock - mtime;
2738 
2739 	for (rwalk = getrule(hostname, pagename, classname, hinfo, C_FILE); (rwalk); rwalk = getrule(NULL, NULL, NULL, hinfo, C_FILE)) {
2740 		int rulecolor = COL_GREEN;
2741 
2742 		/* First, check if the filename matches */
2743 		if (!rwalk->rule.fcheck.filename || !namematch(filename, rwalk->rule.fcheck.filename->pattern, rwalk->rule.fcheck.filename->exp)) continue;
2744 
2745 		*anyrules = 1;
2746 		if (!exists) {
2747 			if (rwalk->chkflags & CHK_OPTIONAL) goto nextcheck;
2748 
2749 			if (!(rwalk->flags & FCHK_NOEXIST)) {
2750 				/* Required file does not exist */
2751 				rulecolor = rwalk->rule.fcheck.color;
2752 				addtobuffer(summarybuf, "File is missing\n");
2753 			}
2754 			goto nextcheck;
2755 		}
2756 
2757 		if (rwalk->flags & FCHK_NOEXIST) {
2758 			/* File exists, but it shouldn't */
2759 			rulecolor = rwalk->rule.fcheck.color;
2760 			addtobuffer(summarybuf, "File exists\n");
2761 			goto nextcheck;
2762 		}
2763 
2764 		if (rwalk->flags & FCHK_TYPE) {
2765 			if ( ((rwalk->rule.fcheck.ftype == S_IFLNK) && !islink) || (rwalk->rule.fcheck.ftype != ftype) ) {
2766 				rulecolor = rwalk->rule.fcheck.color;
2767 				sprintf(msgline, "File is a %s - should be %s\n",
2768 					ftypestr(ftype), ftypestr(rwalk->rule.fcheck.ftype));
2769 				addtobuffer(summarybuf, msgline);
2770 			}
2771 		}
2772 		if (rwalk->flags & FCHK_MODE) {
2773 			if (rwalk->rule.fcheck.fmode != fmode) {
2774 				rulecolor = rwalk->rule.fcheck.color;
2775 				sprintf(msgline, "File is mode %03o - should be %03o\n",
2776 					fmode, rwalk->rule.fcheck.fmode);
2777 				addtobuffer(summarybuf, msgline);
2778 			}
2779 		}
2780 		if (rwalk->flags & FCHK_MINSIZE) {
2781 			if (fsize < rwalk->rule.fcheck.minsize) {
2782 				rulecolor = rwalk->rule.fcheck.color;
2783 #ifdef _LARGEFILE_SOURCE
2784 				sprintf(msgline, "File has size %lld  - should be >%lld\n",
2785 					(long long int)fsize, (long long int)rwalk->rule.fcheck.minsize);
2786 #else
2787 				sprintf(msgline, "File has size %ld  - should be >%ld\n",
2788 					(long int)fsize, (long int)rwalk->rule.fcheck.minsize);
2789 #endif
2790 				addtobuffer(summarybuf, msgline);
2791 			}
2792 		}
2793 		if (rwalk->flags & FCHK_MAXSIZE) {
2794 			if (fsize > rwalk->rule.fcheck.maxsize) {
2795 				rulecolor = rwalk->rule.fcheck.color;
2796 #ifdef _LARGEFILE_SOURCE
2797 				sprintf(msgline, "File has size %lld  - should be <%lld\n",
2798 					(long long int)fsize, (long long int)rwalk->rule.fcheck.maxsize);
2799 #else
2800 				sprintf(msgline, "File has size %ld  - should be <%ld\n",
2801 					(long int)fsize, (long int)rwalk->rule.fcheck.maxsize);
2802 #endif
2803 				addtobuffer(summarybuf, msgline);
2804 			}
2805 		}
2806 		if (rwalk->flags & FCHK_EQLSIZE) {
2807 			if (fsize != rwalk->rule.fcheck.eqlsize) {
2808 				rulecolor = rwalk->rule.fcheck.color;
2809 #ifdef _LARGEFILE_SOURCE
2810 				sprintf(msgline, "File has size %lld  - should be %lld\n",
2811 					(long long int)fsize, (long long int)rwalk->rule.fcheck.eqlsize);
2812 #else
2813 				sprintf(msgline, "File has size %ld  - should be %ld\n",
2814 					(long int)fsize, (long int)rwalk->rule.fcheck.eqlsize);
2815 #endif
2816 				addtobuffer(summarybuf, msgline);
2817 			}
2818 		}
2819 		if (rwalk->flags & FCHK_MINLINKS) {
2820 			if (linkcount < rwalk->rule.fcheck.minlinks) {
2821 				rulecolor = rwalk->rule.fcheck.color;
2822 				sprintf(msgline, "File has linkcount %u  - should be >%u\n",
2823 					linkcount, rwalk->rule.fcheck.minlinks);
2824 				addtobuffer(summarybuf, msgline);
2825 			}
2826 		}
2827 		if (rwalk->flags & FCHK_MAXLINKS) {
2828 			if (linkcount > rwalk->rule.fcheck.maxlinks) {
2829 				rulecolor = rwalk->rule.fcheck.color;
2830 				sprintf(msgline, "File has linkcount %u  - should be <%u\n",
2831 					linkcount, rwalk->rule.fcheck.maxlinks);
2832 				addtobuffer(summarybuf, msgline);
2833 			}
2834 		}
2835 		if (rwalk->flags & FCHK_OWNERID) {
2836 			if (ownerid != rwalk->rule.fcheck.ownerid) {
2837 				rulecolor = rwalk->rule.fcheck.color;
2838 				sprintf(msgline, "File is owned by user %u  - should be %u\n",
2839 					ownerid, rwalk->rule.fcheck.ownerid);
2840 				addtobuffer(summarybuf, msgline);
2841 			}
2842 		}
2843 		if (rwalk->flags & FCHK_OWNERSTR) {
2844 			if (!ownerstr) ownerstr = "(No owner data)";
2845 			if (strcmp(ownerstr, rwalk->rule.fcheck.ownerstr) != 0) {
2846 				rulecolor = rwalk->rule.fcheck.color;
2847 				sprintf(msgline, "File is owned by user %s  - should be %s\n",
2848 					ownerstr, rwalk->rule.fcheck.ownerstr);
2849 				addtobuffer(summarybuf, msgline);
2850 			}
2851 		}
2852 		if (rwalk->flags & FCHK_GROUPID) {
2853 			if (groupid != rwalk->rule.fcheck.groupid) {
2854 				rulecolor = rwalk->rule.fcheck.color;
2855 				sprintf(msgline, "File is owned by group %u  - should be %u\n",
2856 					groupid, rwalk->rule.fcheck.groupid);
2857 				addtobuffer(summarybuf, msgline);
2858 			}
2859 		}
2860 		if (rwalk->flags & FCHK_GROUPSTR) {
2861 			if (!groupstr) groupstr = "(No group data)";
2862 			if (strcmp(groupstr, rwalk->rule.fcheck.groupstr) != 0) {
2863 				rulecolor = rwalk->rule.fcheck.color;
2864 				sprintf(msgline, "File is owned by group %s  - should be %s\n",
2865 					groupstr, rwalk->rule.fcheck.groupstr);
2866 				addtobuffer(summarybuf, msgline);
2867 			}
2868 		}
2869 		if (rwalk->flags & FCHK_CTIMEMIN) {
2870 			if (ctimedif < rwalk->rule.fcheck.minctimedif) {
2871 				rulecolor = rwalk->rule.fcheck.color;
2872 				sprintf(msgline, "File status changed %u seconds ago - should be >%u\n",
2873 					ctimedif, rwalk->rule.fcheck.minctimedif);
2874 				addtobuffer(summarybuf, msgline);
2875 			}
2876 		}
2877 		if (rwalk->flags & FCHK_CTIMEMAX) {
2878 			if (ctimedif > rwalk->rule.fcheck.maxctimedif) {
2879 				rulecolor = rwalk->rule.fcheck.color;
2880 				sprintf(msgline, "File status changed %u seconds ago - should be <%u\n",
2881 					ctimedif, rwalk->rule.fcheck.maxctimedif);
2882 				addtobuffer(summarybuf, msgline);
2883 			}
2884 		}
2885 		if (rwalk->flags & FCHK_MTIMEMIN) {
2886 			if (mtimedif < rwalk->rule.fcheck.minmtimedif) {
2887 				rulecolor = rwalk->rule.fcheck.color;
2888 				sprintf(msgline, "File was modified %u seconds ago - should be >%u\n",
2889 					mtimedif, rwalk->rule.fcheck.minmtimedif);
2890 				addtobuffer(summarybuf, msgline);
2891 			}
2892 		}
2893 		if (rwalk->flags & FCHK_MTIMEMAX) {
2894 			if (mtimedif > rwalk->rule.fcheck.maxmtimedif) {
2895 				rulecolor = rwalk->rule.fcheck.color;
2896 				sprintf(msgline, "File was modified %u seconds ago - should be <%u\n",
2897 					mtimedif, rwalk->rule.fcheck.maxmtimedif);
2898 				addtobuffer(summarybuf, msgline);
2899 			}
2900 		}
2901 		if (rwalk->flags & FCHK_ATIMEMIN) {
2902 			if (atimedif < rwalk->rule.fcheck.minatimedif) {
2903 				rulecolor = rwalk->rule.fcheck.color;
2904 				sprintf(msgline, "File was accessed %u seconds ago - should be >%u\n",
2905 					atimedif, rwalk->rule.fcheck.minatimedif);
2906 				addtobuffer(summarybuf, msgline);
2907 			}
2908 		}
2909 		if (rwalk->flags & FCHK_ATIMEMAX) {
2910 			if (atimedif > rwalk->rule.fcheck.maxatimedif) {
2911 				rulecolor = rwalk->rule.fcheck.color;
2912 				sprintf(msgline, "File was accessed %u seconds ago - should be <%u\n",
2913 					atimedif, rwalk->rule.fcheck.maxatimedif);
2914 				addtobuffer(summarybuf, msgline);
2915 			}
2916 		}
2917 		if (rwalk->flags & FCHK_MD5) {
2918 			if (!md5hash) md5hash = "(No MD5 data)";
2919 			if (strcmp(md5hash, rwalk->rule.fcheck.md5hash) != 0) {
2920 				rulecolor = rwalk->rule.fcheck.color;
2921 				sprintf(msgline, "File has MD5 hash %s  - should be %s\n",
2922 					md5hash, rwalk->rule.fcheck.md5hash);
2923 				addtobuffer(summarybuf, msgline);
2924 			}
2925 		}
2926 		if (rwalk->flags & FCHK_SHA1) {
2927 			if (!sha1hash) sha1hash = "(No SHA1 data)";
2928 			if (strcmp(sha1hash, rwalk->rule.fcheck.sha1hash) != 0) {
2929 				rulecolor = rwalk->rule.fcheck.color;
2930 				sprintf(msgline, "File has SHA1 hash %s  - should be %s\n",
2931 					sha1hash, rwalk->rule.fcheck.sha1hash);
2932 				addtobuffer(summarybuf, msgline);
2933 			}
2934 		}
2935 		if (rwalk->flags & FCHK_SHA256) {
2936 			if (!sha256hash) sha256hash = "(No SHA256 data)";
2937 			if (strcmp(sha256hash, rwalk->rule.fcheck.sha256hash) != 0) {
2938 				rulecolor = rwalk->rule.fcheck.color;
2939 				sprintf(msgline, "File has SHA256 hash %s  - should be %s\n",
2940 					sha256hash, rwalk->rule.fcheck.sha256hash);
2941 				addtobuffer(summarybuf, msgline);
2942 			}
2943 		}
2944 		if (rwalk->flags & FCHK_SHA512) {
2945 			if (!sha512hash) sha512hash = "(No SHA256 data)";
2946 			if (strcmp(sha512hash, rwalk->rule.fcheck.sha512hash) != 0) {
2947 				rulecolor = rwalk->rule.fcheck.color;
2948 				sprintf(msgline, "File has SHA512 hash %s  - should be %s\n",
2949 					sha512hash, rwalk->rule.fcheck.sha512hash);
2950 				addtobuffer(summarybuf, msgline);
2951 			}
2952 		}
2953 		if (rwalk->flags & FCHK_SHA224) {
2954 			if (!sha224hash) sha224hash = "(No SHA224 data)";
2955 			if (strcmp(sha224hash, rwalk->rule.fcheck.sha224hash) != 0) {
2956 				rulecolor = rwalk->rule.fcheck.color;
2957 				sprintf(msgline, "File has SHA224 hash %s  - should be %s\n",
2958 					sha224hash, rwalk->rule.fcheck.sha224hash);
2959 				addtobuffer(summarybuf, msgline);
2960 			}
2961 		}
2962 		if (rwalk->flags & FCHK_SHA384) {
2963 			if (!sha384hash) sha384hash = "(No SHA384 data)";
2964 			if (strcmp(sha384hash, rwalk->rule.fcheck.sha384hash) != 0) {
2965 				rulecolor = rwalk->rule.fcheck.color;
2966 				sprintf(msgline, "File has SHA384 hash %s  - should be %s\n",
2967 					sha384hash, rwalk->rule.fcheck.sha384hash);
2968 				addtobuffer(summarybuf, msgline);
2969 			}
2970 		}
2971 		if (rwalk->flags & FCHK_RMD160) {
2972 			if (!rmd160hash) rmd160hash = "(No RMD160 data)";
2973 			if (strcmp(rmd160hash, rwalk->rule.fcheck.rmd160hash) != 0) {
2974 				rulecolor = rwalk->rule.fcheck.color;
2975 				sprintf(msgline, "File has RMD160 hash %s  - should be %s\n",
2976 					rmd160hash, rwalk->rule.fcheck.rmd160hash);
2977 				addtobuffer(summarybuf, msgline);
2978 			}
2979 		}
2980 		if (rwalk->chkflags & CHK_TRACKIT) {
2981 			*trackit = (trackit || (ftype == S_IFREG));
2982 			*id = rwalk->rrdidstr;
2983 		}
2984 
2985 nextcheck:
2986 		if (rulecolor != COL_GREEN) addalertgroup(rwalk->groups);
2987 		if (rulecolor > result) result = rulecolor;
2988 	}
2989 
2990 	return result;
2991 }
2992 
check_dir(void * hinfo,char * classname,char * filename,char * filedata,char * section,strbuffer_t * summarybuf,unsigned long * dirsize,char ** id,int * trackit)2993 int check_dir(void *hinfo, char *classname,
2994 	      char *filename, char *filedata, char *section,
2995 	      strbuffer_t *summarybuf, unsigned long *dirsize,
2996 	      char **id, int *trackit)
2997 {
2998 	int result = COL_GREEN;
2999 	int gotsize = 0;
3000 	char *hostname, *pagename;
3001 	c_rule_t *rwalk;
3002 	char *boln, *eoln;
3003 	char msgline[PATH_MAX];
3004 
3005 	unsigned long dsize = 0;
3006 
3007 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
3008 	pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
3009 	*trackit = 0;
3010 
3011 	boln = filedata;
3012 	while (boln && *boln) {
3013 		unsigned long sz;
3014 		char *p;
3015 
3016 		eoln = strchr(boln, '\n'); if (eoln) *eoln = '\0';
3017 
3018 		/*
3019 		 * We need to check the directory name on each line, to
3020 		 * find the line that gives us the exact directory we want.
3021 		 * NB: Assumes the output is in the form
3022 		 *    12345   /foo/bar/baz
3023 		 */
3024 		sz = atol(boln);
3025 		p = boln + strcspn(boln, " \t");
3026 		if (isspace((int)*p)) p += strspn(p, " \t");
3027 		if (strcmp(p, filename) == 0) { gotsize = 1; dsize = sz; }
3028 
3029 		if (eoln) { *eoln = '\0'; boln = eoln+1; } else boln = NULL;
3030 	}
3031 
3032 	*dirsize = dsize;
3033 
3034 	/* Got the data? */
3035 	if (!gotsize) {
3036 		sprintf(msgline, "Could not determine size of directory %s\n", filename);
3037 		addtobuffer(summarybuf, msgline);
3038 		return COL_YELLOW;
3039 	}
3040 
3041 	for (rwalk = getrule(hostname, pagename, classname, hinfo, C_DIR); (rwalk); rwalk = getrule(NULL, NULL, NULL, hinfo, C_DIR)) {
3042 		int rulecolor = COL_GREEN;
3043 
3044 		/* First, check if the filename matches */
3045 		if (!rwalk->rule.fcheck.filename || !namematch(filename, rwalk->rule.fcheck.filename->pattern, rwalk->rule.fcheck.filename->exp)) continue;
3046 
3047 		if (rwalk->flags & FCHK_MAXSIZE) {
3048 			if (dsize > rwalk->rule.dcheck.maxsize) {
3049 				rulecolor = rwalk->rule.dcheck.color;
3050 				sprintf(msgline, "Directory has size %lu  - should be <%lu\n",
3051 					dsize, rwalk->rule.dcheck.maxsize);
3052 				addtobuffer(summarybuf, msgline);
3053 			}
3054 		}
3055 		else if (rwalk->flags & FCHK_MINSIZE) {
3056 			if (dsize < rwalk->rule.dcheck.minsize) {
3057 				rulecolor = rwalk->rule.dcheck.color;
3058 				sprintf(msgline, "Directory has size %lu  - should be >%lu\n",
3059 					dsize, rwalk->rule.dcheck.minsize);
3060 				addtobuffer(summarybuf, msgline);
3061 			}
3062 		}
3063 		if (rwalk->chkflags & CHK_TRACKIT) {
3064 			*trackit = 1;
3065 			*id = rwalk->rrdidstr;
3066 		}
3067 
3068 		if (rulecolor != COL_GREEN) addalertgroup(rwalk->groups);
3069 		if (rulecolor > result) result = rulecolor;
3070 	}
3071 
3072 	return result;
3073 }
3074 
check_rrdds_thresholds(char * hostname,char * classname,char * pagepaths,char * rrdkey,void * valnames,char * vals)3075 strbuffer_t *check_rrdds_thresholds(char *hostname, char *classname, char *pagepaths, char *rrdkey, void * valnames, char *vals)
3076 {
3077 	static strbuffer_t *resbuf = NULL;
3078 	char msgline[1024];
3079 	c_rule_t *rule;
3080 	char *valscopy = NULL;
3081 	char **vallist = NULL;
3082 	xtreePos_t handle;
3083 	rrdtplnames_t *tpl;
3084 	double val;
3085 	void *hinfo;
3086 
3087 	if (!resbuf) resbuf = newstrbuffer(0);
3088 	clearstrbuffer(resbuf);
3089 
3090 	hinfo = hostinfo(hostname);
3091 	rule = getrule(hostname, pagepaths, classname, hinfo, C_RRDDS);
3092 	while (rule) {
3093 		int rulematch = 0;
3094 
3095 		if (strcmp(rule->rule.rrdds.column, "http") == 0) {
3096 			if (!rule->rule.rrdds.rrdkey || !patternmatch(rrdkey, rule->rule.rrdds.rrdkey->pattern, rule->rule.rrdds.rrdkey->exp)) goto nextrule;
3097 		}
3098 		else {
3099 			if (!rule->rule.rrdds.rrdkey || !namematch(rrdkey, rule->rule.rrdds.rrdkey->pattern, rule->rule.rrdds.rrdkey->exp)) goto nextrule;
3100 		}
3101 
3102 		handle = xtreeFind(valnames, rule->rule.rrdds.rrdds);
3103 		if (handle == xtreeEnd(valnames)) goto nextrule;
3104 		tpl = (rrdtplnames_t *)xtreeData(valnames, handle);
3105 
3106 		/* Split the value-string into individual numbers that we can index */
3107 		if (!vallist) {
3108 			char *p;
3109 			int idx = 0;
3110 
3111 			valscopy = strdup(vals);
3112 			vallist = calloc(128, sizeof(char *));
3113 			vallist[0] = valscopy;
3114 
3115 			for (p = strchr(valscopy, ':'); (p); p = strchr(p+1, ':')) {
3116 				vallist[++idx] = p+1;
3117 				*p = '\0';
3118 			}
3119 		}
3120 
3121 		if (vallist[tpl->idx] == NULL) goto nextrule;
3122 		val = atof(vallist[tpl->idx]);
3123 
3124 		/* Do the checks */
3125 		if (rule->flags & RRDDSCHK_INTVL) {
3126 			rulematch = ( ( ((rule->flags & RRDDSCHK_GT) && (val > rule->rule.rrdds.limitval))  ||
3127 				        ((rule->flags & RRDDSCHK_GE) && (val >= rule->rule.rrdds.limitval)) ) &&
3128 				      ( ((rule->flags & RRDDSCHK_LT) && (val < rule->rule.rrdds.limitval2))  ||
3129 				        ((rule->flags & RRDDSCHK_LE) && (val <= rule->rule.rrdds.limitval2)) ) );
3130 
3131 			if (!rule->statustext) {
3132 				char fmt[100];
3133 
3134 				strcpy(fmt, "&N=&V (");
3135 				if (rule->flags & RRDDSCHK_GT) strcat(fmt, " > &L");
3136 				else if (rule->flags & RRDDSCHK_GE) strcat(fmt, " >= &L");
3137 				strcat(fmt, " and");
3138 				if (rule->flags & RRDDSCHK_LT) strcat(fmt, " < &U)");
3139 				else if (rule->flags & RRDDSCHK_LE) strcat(fmt, " <= &U)");
3140 
3141 				rule->statustext = strdup(fmt);
3142 			}
3143 		}
3144 		else {
3145 			rulematch = ( ((rule->flags & RRDDSCHK_GT) && (val > rule->rule.rrdds.limitval))  ||
3146 				      ((rule->flags & RRDDSCHK_GE) && (val >= rule->rule.rrdds.limitval)) ||
3147 				      ((rule->flags & RRDDSCHK_LT) && (val < rule->rule.rrdds.limitval))  ||
3148 				      ((rule->flags & RRDDSCHK_LE) && (val <= rule->rule.rrdds.limitval))   );
3149 
3150 			if (!rule->statustext) {
3151 				char *fmt = "";
3152 
3153 				if      (rule->flags & RRDDSCHK_GT) fmt = "&N=&V (> &L)";
3154 				else if (rule->flags & RRDDSCHK_GE) fmt = "&N=&V (>= &L)";
3155 				else if (rule->flags & RRDDSCHK_LT) fmt = "&N=&V (< &L)";
3156 				else if (rule->flags & RRDDSCHK_LE) fmt = "&N=&V (<= &L)";
3157 
3158 				rule->statustext = strdup(fmt);
3159 			}
3160 		}
3161 
3162 		if (rulematch) {
3163 			char *bot, *marker;
3164 
3165 			sprintf(msgline, "modify %s.%s %s rrdds ",
3166 				hostname, rule->rule.rrdds.column,
3167 				colorname(rule->rule.rrdds.color));
3168 			addtobuffer(resbuf, msgline);
3169 
3170 			/* Format and add the status text */
3171 			bot = rule->statustext;
3172 			do {
3173 				marker = strchr(bot, '&');
3174 				if (marker) {
3175 					*marker = '\0';
3176 					addtobuffer(resbuf, bot);
3177 					*marker = '&';
3178 					switch (*(marker+1)) {
3179 					  case 'N': addtobuffer(resbuf, rule->rule.rrdds.rrdds);
3180 						    bot = marker+2;
3181 						    break;
3182 
3183 					  case 'V': addtobuffer(resbuf, vallist[tpl->idx]);
3184 						    bot = marker+2;
3185 						    break;
3186 
3187 					  case 'L': sprintf(msgline, "%.2f", rule->rule.rrdds.limitval);
3188 						    addtobuffer(resbuf, msgline);
3189 						    bot = marker+2;
3190 						    break;
3191 
3192 					  case 'U': sprintf(msgline, "%.2f", (rule->flags & RRDDSCHK_INTVL) ? rule->rule.rrdds.limitval2 : rule->rule.rrdds.limitval);
3193 						    addtobuffer(resbuf, msgline);
3194 						    bot = marker+2;
3195 						    break;
3196 
3197 					  default:  addtobuffer(resbuf, "&"); bot = marker+1; break;
3198 					}
3199 				}
3200 				else {
3201 					addtobuffer(resbuf, bot);
3202 					bot = NULL;
3203 				}
3204 			} while (bot);
3205 
3206 			addtobuffer(resbuf, "\n\n");
3207 		}
3208 
3209 nextrule:
3210 		rule = getrule(NULL, NULL, NULL, hinfo, C_RRDDS);
3211 	}
3212 
3213 	if (valscopy) xfree(valscopy);
3214 	if (vallist) xfree(vallist);
3215 
3216 	return (STRBUFLEN(resbuf) > 0) ? resbuf : NULL;
3217 }
3218 
3219 
get_mqqueue_thresholds(void * hinfo,char * classname,char * qmgrname,char * qname,int * warnlen,int * critlen,int * warnage,int * critage,char ** trackit)3220 void get_mqqueue_thresholds(void *hinfo, char *classname, char *qmgrname, char *qname, int *warnlen, int *critlen, int *warnage, int *critage, char **trackit)
3221 {
3222 	char *hostname, *pagepaths;
3223 	c_rule_t *rule;
3224 
3225 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
3226 	pagepaths = xmh_item(hinfo, XMH_ALLPAGEPATHS);
3227 
3228 	*warnlen = *critlen = *warnage = *critage = -1;
3229 	*trackit = NULL;
3230 
3231 	rule = getrule(hostname, pagepaths, classname, hinfo, C_MQ_QUEUE);
3232 	while (rule) {
3233 		if (rule->rule.mqqueue.qname && rule->rule.mqqueue.qmgrname &&
3234 		    namematch(qname, rule->rule.mqqueue.qname->pattern, rule->rule.mqqueue.qname->exp) &&
3235 		    namematch(qmgrname, rule->rule.mqqueue.qmgrname->pattern, rule->rule.mqqueue.qmgrname->exp)) {
3236 			*warnlen = rule->rule.mqqueue.warnlen;
3237 			*critlen = rule->rule.mqqueue.critlen;
3238 			*warnage = rule->rule.mqqueue.warnage;
3239 			*critage = rule->rule.mqqueue.critage;
3240 			if (rule->chkflags & CHK_TRACKIT) *trackit = (rule->rrdidstr ? rule->rrdidstr : "");
3241 			return;
3242 		}
3243 
3244 		rule = getrule(NULL, NULL, NULL, hinfo, C_MQ_QUEUE);
3245 	}
3246 }
3247 
get_mqchannel_params(void * hinfo,char * classname,char * qmgrname,char * chnname,char * chnstatus,int * color)3248 int get_mqchannel_params(void *hinfo, char *classname, char *qmgrname, char *chnname, char *chnstatus, int *color)
3249 {
3250 	char *hostname, *pagepaths;
3251 	c_rule_t *rule;
3252 
3253 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
3254 	pagepaths = xmh_item(hinfo, XMH_ALLPAGEPATHS);
3255 
3256 	rule = getrule(hostname, pagepaths, classname, hinfo, C_MQ_CHANNEL);
3257 	while (rule) {
3258 		if (rule->rule.mqchannel.chnname && rule->rule.mqchannel.qmgrname &&
3259 		    namematch(chnname, rule->rule.mqchannel.chnname->pattern, rule->rule.mqchannel.chnname->exp) &&
3260 		    namematch(qmgrname, rule->rule.mqchannel.qmgrname->pattern, rule->rule.mqchannel.qmgrname->exp)) {
3261 			if (rule->rule.mqchannel.alertstates && namematch(chnstatus, rule->rule.mqchannel.alertstates->pattern, rule->rule.mqchannel.alertstates->exp)) {
3262 				*color = COL_RED;
3263 			}
3264 			else if (rule->rule.mqchannel.warnstates && namematch(chnstatus, rule->rule.mqchannel.warnstates->pattern, rule->rule.mqchannel.warnstates->exp)) {
3265 				*color = COL_YELLOW;
3266 			}
3267 			else {
3268 				*color = COL_GREEN;
3269 			}
3270 
3271 			return 1;
3272 		}
3273 
3274 		rule = getrule(NULL, NULL, NULL, hinfo, C_MQ_CHANNEL);
3275 	}
3276 
3277 	return 0;
3278 }
3279 
3280 
3281 typedef struct mon_proc_t {
3282 	c_rule_t *rule;
3283 	struct mon_proc_t *next;
3284 } mon_proc_t;
3285 
clear_counts(void * hinfo,char * classname,ruletype_t ruletype,mon_proc_t ** head,mon_proc_t ** tail,mon_proc_t ** walk)3286 static int clear_counts(void *hinfo, char *classname, ruletype_t ruletype,
3287 			mon_proc_t **head, mon_proc_t **tail, mon_proc_t **walk)
3288 {
3289 	char *hostname, *pagename;
3290 	c_rule_t *rule;
3291 	int count = 0;
3292 
3293 	while (*head) {
3294 		mon_proc_t *tmp = *head;
3295 		*head = (*head)->next;
3296 		xfree(tmp);
3297 	}
3298 	*head = *tail = *walk = NULL;
3299 
3300 	hostname = xmh_item(hinfo, XMH_HOSTNAME);
3301 	pagename = xmh_item(hinfo, XMH_ALLPAGEPATHS);
3302 
3303 	rule = getrule(hostname, pagename, classname, hinfo, ruletype);
3304 	while (rule) {
3305 		mon_proc_t *newitem = (mon_proc_t *)calloc(1, sizeof(mon_proc_t));
3306 
3307 		newitem->rule = rule;
3308 		newitem->next = NULL;
3309 		if (*tail) { (*tail)->next = newitem; *tail = newitem; }
3310 		else { *head = *tail = newitem; }
3311 
3312 		count++;
3313 		switch (rule->ruletype) {
3314 		  case C_DISK : rule->rule.disk.dcount = 0; break;
3315 		  case C_INODE: rule->rule.inode.icount = 0; break;
3316 		  case C_PROC : rule->rule.proc.pcount = 0; break;
3317 		  case C_PORT : rule->rule.port.pcount = 0; break;
3318 		  case C_SVC  : rule->rule.svc.scount = 0; break;
3319 		  default: break;
3320 		}
3321 
3322 		rule = getrule(NULL, NULL, NULL, hinfo, ruletype);
3323 	}
3324 
3325 	*walk = *head;
3326 	return count;
3327 }
3328 
add_count(char * pname,mon_proc_t * head)3329 static void add_count(char *pname, mon_proc_t *head)
3330 {
3331 	mon_proc_t *pwalk;
3332 
3333 	if (!pname) return;
3334 
3335 	for (pwalk = head; (pwalk); pwalk = pwalk->next) {
3336 		switch (pwalk->rule->ruletype) {
3337 		  case C_PROC:
3338 			if (!pwalk->rule->rule.proc.procexp->exp) {
3339 				/*
3340 				 * No pattern, just see if the token in the config file is
3341 				 * present in the string we got from "ps". So you can setup
3342 				 * the config to look for "cron" and it will actually find "/usr/sbin/cron".
3343 				 */
3344 				if (strstr(pname, pwalk->rule->rule.proc.procexp->pattern))
3345 					pwalk->rule->rule.proc.pcount++;
3346 			}
3347 			else {
3348 				/*
3349 				 * Strip the initial spaces, pipes and so forth seen if an ASCII forest was generated
3350 				 * This allows PCRE regexes using a '^' to remain useful.
3351 				 */
3352 				pname += strspn(pname, " |\\_");
3353 				if (!pname) break;
3354 				if (namematch(pname, pwalk->rule->rule.proc.procexp->pattern, pwalk->rule->rule.proc.procexp->exp))
3355 					pwalk->rule->rule.proc.pcount++;
3356 			}
3357 			break;
3358 
3359 		  case C_DISK:
3360 			if (!pwalk->rule->rule.disk.fsexp->exp) {
3361 				if (strstr(pname, pwalk->rule->rule.disk.fsexp->pattern))
3362 					pwalk->rule->rule.disk.dcount++;
3363 			}
3364 			else {
3365 				if (namematch(pname, pwalk->rule->rule.disk.fsexp->pattern, pwalk->rule->rule.disk.fsexp->exp))
3366 					pwalk->rule->rule.disk.dcount++;
3367 			}
3368 			break;
3369 
3370 		  case C_INODE:
3371 			if (!pwalk->rule->rule.inode.fsexp->exp) {
3372 				if (strstr(pname, pwalk->rule->rule.inode.fsexp->pattern))
3373 					pwalk->rule->rule.inode.icount++;
3374 			}
3375 			else {
3376 				if (namematch(pname, pwalk->rule->rule.inode.fsexp->pattern, pwalk->rule->rule.inode.fsexp->exp))
3377 					pwalk->rule->rule.inode.icount++;
3378 			}
3379 
3380 		  default: break;
3381 		}
3382 	}
3383 }
3384 
check_expr_match(char * s,exprlist_t * inclexp,exprlist_t * exclexp)3385 static int check_expr_match(char *s, exprlist_t *inclexp, exprlist_t *exclexp)
3386 {
3387 	int inclmatch = 0;
3388 	int exclmatch = 0;
3389 
3390 	if (inclexp) {
3391 		if (namematch(s, inclexp->pattern, inclexp->exp)) inclmatch = 1;
3392 	}
3393 	else inclmatch = 1;
3394 
3395 	/* If rejected by include spec, no need to check excludes */
3396 	if (inclmatch == 0) return 0;
3397 
3398 	if (exclexp) {
3399 		if (namematch(s, exclexp->pattern, exclexp->exp)) exclmatch = 1;
3400 	}
3401 
3402 	/* If the exclude matched, then the whole thing does not match */
3403 	if (exclmatch) return 0;
3404 
3405 	/* Include- and exclude-patterns match OK, we have a match */
3406 	return 1;
3407 }
3408 
add_count3(char * pname0,char * pname1,char * pname2,mon_proc_t * head)3409 static void add_count3(char *pname0, char *pname1, char *pname2 , mon_proc_t *head)
3410 {
3411 	mon_proc_t *pwalk;
3412 	int mymatch;
3413 
3414 	if (!pname0) return;
3415 	if (!pname1) return;
3416 	if (!pname2) return;
3417 
3418 	for (pwalk = head; (pwalk); pwalk = pwalk->next) {
3419 		switch (pwalk->rule->ruletype) {
3420 		  case C_PORT:
3421 		        mymatch = 0;
3422 
3423 			if (check_expr_match(pname0, pwalk->rule->rule.port.localexp, pwalk->rule->rule.port.exlocalexp)) mymatch++;
3424 			if (check_expr_match(pname1, pwalk->rule->rule.port.remoteexp, pwalk->rule->rule.port.exremoteexp)) mymatch++;
3425 			if (check_expr_match(pname2, pwalk->rule->rule.port.stateexp, pwalk->rule->rule.port.exstateexp)) mymatch++;
3426 
3427 			if (mymatch == 3) {pwalk->rule->rule.port.pcount++;}
3428 			break;
3429 
3430 		  case C_SVC:
3431 			mymatch = 0;
3432 
3433 			if (check_expr_match(pname0, pwalk->rule->rule.svc.svcexp, NULL)) {
3434 				mymatch++;
3435 
3436 				/* Save the actual startup-method and state for later display in the status message */
3437 				pwalk->rule->rule.svc.svcname = strdup(pname0);
3438 				pwalk->rule->rule.svc.startup = strdup(pname1);
3439 				pwalk->rule->rule.svc.state = strdup(pname2);
3440 
3441 				/* Startupexp and stateexp are optional - if no criteria defined, then they do match */
3442 				if (!pwalk->rule->rule.svc.startupexp || check_expr_match(pname1, pwalk->rule->rule.svc.startupexp, NULL)) mymatch++;
3443 				if (!pwalk->rule->rule.svc.stateexp || check_expr_match(pname2, pwalk->rule->rule.svc.stateexp, NULL)) mymatch++;
3444 			}
3445 
3446 			if (mymatch == 3) {pwalk->rule->rule.svc.scount++;}
3447 			break;
3448 
3449 		  default:
3450 			break;
3451 		}
3452 	}
3453 }
3454 
check_count(int * count,ruletype_t ruletype,int * lowlim,int * uplim,int * color,mon_proc_t ** walk,char ** id,int * trackit,char ** group)3455 static char *check_count(int *count, ruletype_t ruletype, int *lowlim, int *uplim, int *color, mon_proc_t **walk, char **id, int *trackit,
3456 		char **group)
3457 {
3458 	char *result = NULL;
3459 
3460 	*color = COL_GREEN;
3461 	*count = 0;
3462 	if (*walk == NULL) return NULL;
3463 
3464 	switch (ruletype) {
3465 	  case C_PROC:
3466 		result = (*walk)->rule->statustext;
3467 		if (!result) result = (*walk)->rule->rule.proc.procexp->pattern;
3468 		*count = (*walk)->rule->rule.proc.pcount;
3469 		*lowlim = (*walk)->rule->rule.proc.pmin;
3470 		*uplim = (*walk)->rule->rule.proc.pmax;
3471 		if ((*lowlim !=  0) && (*count < *lowlim)) *color = (*walk)->rule->rule.proc.color;
3472 		if ((*uplim  != -1) && (*count > *uplim)) *color = (*walk)->rule->rule.proc.color;
3473 		*trackit = ((*walk)->rule->chkflags & CHK_TRACKIT);
3474 		*id = (*walk)->rule->rrdidstr;
3475 		if (group) *group = (*walk)->rule->groups;
3476 		break;
3477 
3478 	  case C_DISK:
3479 		result = (*walk)->rule->rule.disk.fsexp->pattern;
3480 		*count = (*walk)->rule->rule.disk.dcount;
3481 		*lowlim = (*walk)->rule->rule.disk.dmin;
3482 		*uplim = (*walk)->rule->rule.disk.dmax;
3483 		if ((*lowlim !=  0) && (*count < *lowlim)) *color = (*walk)->rule->rule.disk.color;
3484 		if ((*uplim  != -1) && (*count > *uplim)) *color = (*walk)->rule->rule.disk.color;
3485 		if (group) *group = (*walk)->rule->groups;
3486 		break;
3487 
3488 	  case C_INODE:
3489 		result = (*walk)->rule->rule.inode.fsexp->pattern;
3490 		*count = (*walk)->rule->rule.inode.icount;
3491 		*lowlim = (*walk)->rule->rule.inode.imin;
3492 		*uplim = (*walk)->rule->rule.inode.imax;
3493 		*color = COL_GREEN;
3494 		if ((*lowlim !=  0) && (*count < *lowlim)) *color = (*walk)->rule->rule.inode.color;
3495 		if ((*uplim  != -1) && (*count > *uplim)) *color = (*walk)->rule->rule.inode.color;
3496 		if (group) *group = (*walk)->rule->groups;
3497 		break;
3498 
3499 	  case C_PORT:
3500 		result = (*walk)->rule->statustext;
3501 		if (!result) {
3502 			int sz = 1024;
3503 			char *p;
3504 
3505 			if ((*walk)->rule->rule.port.localexp)
3506 				sz += strlen((*walk)->rule->rule.port.localexp->pattern) + 10;
3507 			if ((*walk)->rule->rule.port.exlocalexp)
3508 				sz += strlen((*walk)->rule->rule.port.exlocalexp->pattern) + 10;
3509 			if ((*walk)->rule->rule.port.remoteexp)
3510 				sz += strlen((*walk)->rule->rule.port.remoteexp->pattern) + 10;
3511 			if ((*walk)->rule->rule.port.exremoteexp)
3512 				sz += strlen((*walk)->rule->rule.port.exremoteexp->pattern) + 10;
3513 			if ((*walk)->rule->rule.port.stateexp)
3514 				sz += strlen((*walk)->rule->rule.port.stateexp->pattern) + 10;
3515 			if ((*walk)->rule->rule.port.exstateexp)
3516 				sz += strlen((*walk)->rule->rule.port.exstateexp->pattern) + 10;
3517 
3518 			(*walk)->rule->statustext = (char *)malloc(sz + 1);
3519 			p = (*walk)->rule->statustext;
3520 			if ((*walk)->rule->rule.port.localexp)
3521 				p += sprintf(p, "local=%s ", (*walk)->rule->rule.port.localexp->pattern);
3522 			if ((*walk)->rule->rule.port.exlocalexp)
3523 				p += sprintf(p, "exlocal=%s ", (*walk)->rule->rule.port.exlocalexp->pattern);
3524 			if ((*walk)->rule->rule.port.remoteexp)
3525 				p += sprintf(p, "remote=%s ", (*walk)->rule->rule.port.remoteexp->pattern);
3526 			if ((*walk)->rule->rule.port.exremoteexp)
3527 				p += sprintf(p, "exremote=%s ", (*walk)->rule->rule.port.exremoteexp->pattern);
3528 			if ((*walk)->rule->rule.port.stateexp)
3529 				p += sprintf(p, "state=%s ", (*walk)->rule->rule.port.stateexp->pattern);
3530 			if ((*walk)->rule->rule.port.exstateexp)
3531 				p += sprintf(p, "exstate=%s ", (*walk)->rule->rule.port.exstateexp->pattern);
3532 			*p = '\0';
3533 			strcat((*walk)->rule->statustext, ":");
3534 
3535 			result = (*walk)->rule->statustext;
3536 		}
3537 		*count = (*walk)->rule->rule.port.pcount;
3538 		*lowlim = (*walk)->rule->rule.port.pmin;
3539 		*uplim = (*walk)->rule->rule.port.pmax;
3540 		if ((*lowlim !=  0) && (*count < *lowlim)) *color = (*walk)->rule->rule.port.color;
3541 		if ((*uplim  != -1) && (*count > *uplim)) *color = (*walk)->rule->rule.port.color;
3542 		*trackit = ((*walk)->rule->chkflags & CHK_TRACKIT);
3543 		*id = (*walk)->rule->rrdidstr;
3544 		if (group) *group = (*walk)->rule->groups;
3545 		break;
3546 
3547 	  case C_SVC:
3548 		/* Have to clear this each time since it contains current state */
3549 		// result = (*walk)->rule->statustext;
3550 		if (!result) {
3551 			int sz = 1024;
3552 			char *p;
3553 
3554 			/* Current state */
3555 			if ((*walk)->rule->rule.svc.svcname)
3556 				sz += strlen((*walk)->rule->rule.svc.svcname) + 10;
3557 			if ((*walk)->rule->rule.svc.startup)
3558 				sz += strlen((*walk)->rule->rule.svc.startup) + 10;
3559 			if ((*walk)->rule->rule.svc.state)
3560 				sz += strlen((*walk)->rule->rule.svc.state) + 10;
3561 			if ((*walk)->rule->rule.svc.startupexp)
3562 				sz += strlen((*walk)->rule->rule.svc.startupexp->pattern) + 10;
3563 			if ((*walk)->rule->rule.svc.stateexp)
3564 				sz += strlen((*walk)->rule->rule.svc.stateexp->pattern) + 10;
3565 
3566 			if ((*walk)->rule->statustext != NULL) xfree((*walk)->rule->statustext);
3567 			(*walk)->rule->statustext = (char *)malloc(sz + 1);
3568 
3569 			p = (*walk)->rule->statustext;
3570 			if ((*walk)->rule->rule.svc.svcname) {
3571 				p += sprintf(p, "%s is %s/%s", (*walk)->rule->rule.svc.svcname,
3572 					     ((*walk)->rule->rule.svc.state ? (*walk)->rule->rule.svc.state : "Unknown"),
3573 					     ((*walk)->rule->rule.svc.startup ? (*walk)->rule->rule.svc.startup : "Unknown"));
3574 			}
3575 			else {
3576 				/* Did not find the service matching our wanted criteria */
3577 				p += sprintf(p, "%s: No matching service", (*walk)->rule->rule.svc.svcexp->pattern);
3578 			}
3579 			p += sprintf(p, " - want %s/%s",
3580 				     ((*walk)->rule->rule.svc.stateexp ? (*walk)->rule->rule.svc.stateexp->pattern : "Any"),
3581 				     ((*walk)->rule->rule.svc.startupexp ? (*walk)->rule->rule.svc.startupexp->pattern : "Any"));
3582 			*p = '\0';
3583 
3584 			result = (*walk)->rule->statustext;
3585 
3586 			/* We free the extra buffers */
3587 			if ((*walk)->rule->rule.svc.svcname)
3588 				xfree((*walk)->rule->rule.svc.svcname);
3589 			if ((*walk)->rule->rule.svc.state)
3590 				xfree((*walk)->rule->rule.svc.state);
3591 			if ((*walk)->rule->rule.svc.startup)
3592 				xfree((*walk)->rule->rule.svc.startup);
3593 		}
3594 		*count = (*walk)->rule->rule.svc.scount;
3595 		if (*count == 0) *color = (*walk)->rule->rule.svc.color;
3596 		if (group) *group = (*walk)->rule->groups;
3597 		break;
3598 
3599 	  default: break;
3600 	}
3601 
3602 	*walk = (*walk)->next;
3603 
3604 	return result;
3605 }
3606 
3607 static mon_proc_t *phead = NULL, *ptail = NULL, *pmonwalk = NULL;
3608 static mon_proc_t *dhead = NULL, *dtail = NULL, *dmonwalk = NULL;
3609 static mon_proc_t *ihead = NULL, *itail = NULL, *imonwalk = NULL;
3610 static mon_proc_t *porthead = NULL, *porttail = NULL, *portmonwalk = NULL;
3611 static mon_proc_t *svchead = NULL, *svctail = NULL, *svcmonwalk = NULL;
3612 
clear_process_counts(void * hinfo,char * classname)3613 int clear_process_counts(void *hinfo, char *classname)
3614 {
3615 	return clear_counts(hinfo, classname, C_PROC, &phead, &ptail, &pmonwalk);
3616 }
3617 
clear_disk_counts(void * hinfo,char * classname)3618 int clear_disk_counts(void *hinfo, char *classname)
3619 {
3620 	return clear_counts(hinfo, classname, C_DISK, &dhead, &dtail, &dmonwalk);
3621 }
3622 
clear_inode_counts(void * hinfo,char * classname)3623 int clear_inode_counts(void *hinfo, char *classname)
3624 {
3625 	return clear_counts(hinfo, classname, C_INODE, &ihead, &itail, &imonwalk);
3626 }
3627 
clear_port_counts(void * hinfo,char * classname)3628 int clear_port_counts(void *hinfo, char *classname)
3629 {
3630 	return clear_counts(hinfo, classname, C_PORT, &porthead, &porttail, &portmonwalk);
3631 }
3632 
clear_svc_counts(void * hinfo,char * classname)3633 int clear_svc_counts(void *hinfo, char *classname)
3634 {
3635         return clear_counts(hinfo, classname, C_SVC, &svchead, &svctail, &svcmonwalk);
3636 }
3637 
add_process_count(char * pname)3638 void add_process_count(char *pname)
3639 {
3640 	add_count(pname, phead);
3641 }
3642 
add_disk_count(char * dname)3643 void add_disk_count(char *dname)
3644 {
3645 	add_count(dname, dhead);
3646 }
3647 
add_inode_count(char * iname)3648 void add_inode_count(char *iname)
3649 {
3650 	add_count(iname, ihead);
3651 }
3652 
add_port_count(char * localstr,char * foreignstr,char * stname)3653 void add_port_count(char *localstr, char *foreignstr, char *stname)
3654 {
3655 	add_count3(localstr, foreignstr, stname, porthead);
3656 }
3657 
add_svc_count(char * localstr,char * foreignstr,char * stname)3658 void add_svc_count(char *localstr, char *foreignstr, char *stname)
3659 {
3660         add_count3(localstr, foreignstr, stname, svchead);
3661 }
3662 
check_process_count(int * count,int * lowlim,int * uplim,int * color,char ** id,int * trackit,char ** group)3663 char *check_process_count(int *count, int *lowlim, int *uplim, int *color, char **id, int *trackit, char **group)
3664 {
3665 	return check_count(count, C_PROC, lowlim, uplim, color, &pmonwalk, id, trackit, group);
3666 }
3667 
check_disk_count(int * count,int * lowlim,int * uplim,int * color,char ** group)3668 char *check_disk_count(int *count, int *lowlim, int *uplim, int *color, char **group)
3669 {
3670 	return check_count(count, C_DISK, lowlim, uplim, color, &dmonwalk, NULL, NULL, group);
3671 }
3672 
check_inode_count(int * count,int * lowlim,int * uplim,int * color,char ** group)3673 char *check_inode_count(int *count, int *lowlim, int *uplim, int *color, char **group)
3674 {
3675 	return check_count(count, C_INODE, lowlim, uplim, color, &imonwalk, NULL, NULL, group);
3676 }
3677 
check_port_count(int * count,int * lowlim,int * uplim,int * color,char ** id,int * trackit,char ** group)3678 char *check_port_count(int *count, int *lowlim, int *uplim, int *color, char **id, int *trackit, char **group)
3679 {
3680 	return check_count(count, C_PORT, lowlim, uplim, color, &portmonwalk, id, trackit, group);
3681 }
3682 
check_svc_count(int * count,int * color,char ** group)3683 char *check_svc_count(int *count, int *color, char **group)
3684 {
3685         return check_count(count, C_SVC, NULL, NULL, color, &svcmonwalk, NULL, NULL, group);
3686 }
3687