1 /*----------------------------------------------------------------------------*/
2 /* Xymon CGI tool to generate a report of the Xymon configuration */
3 /* */
4 /* Copyright (C) 2003-2011 Henrik Storner <henrik@storner.dk> */
5 /* */
6 /* This program is released under the GNU General Public License (GPL), */
7 /* version 2. See the file "COPYING" for details. */
8 /* */
9 /*----------------------------------------------------------------------------*/
10
11 static char rcsid[] = "$Id: confreport.c 8069 2019-07-23 15:29:06Z jccleaver $";
12
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <limits.h>
16 #include <stdio.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <ctype.h>
22 #include <time.h>
23 #include <dirent.h>
24
25 #include "libxymon.h"
26
27 typedef struct hostlist_t {
28 char *hostname;
29 int testcount;
30 htnames_t *tests;
31 htnames_t *disks, *svcs, *procs;
32 struct hostlist_t *next;
33 } hostlist_t;
34
35 typedef struct coltext_t {
36 char *colname;
37 char *coldescr;
38 int used;
39 struct coltext_t *next;
40 } coltext_t;
41
42 hostlist_t *hosthead = NULL;
43 static char *pingcolumn = "conn";
44 static char *coldelim = ";";
45 static coltext_t *chead = NULL;
46 static int ccount = 0;
47 static int criticalonly = 0;
48 static int newcritconfig = 1;
49
50 SBUF_DEFINE(pingplus);
51
errormsg(char * msg)52 void errormsg(char *msg)
53 {
54 printf("Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
55 printf("<html><head><title>Invalid request</title></head>\n");
56 printf("<body>%s</body></html>\n", msg);
57 exit(1);
58 }
59
host_compare(const void * v1,const void * v2)60 static int host_compare(const void *v1, const void *v2)
61 {
62 hostlist_t **h1 = (hostlist_t **)v1;
63 hostlist_t **h2 = (hostlist_t **)v2;
64
65 return strcmp((*h1)->hostname, (*h2)->hostname);
66 }
67
test_compare(const void * v1,const void * v2)68 static int test_compare(const void *v1, const void *v2)
69 {
70 htnames_t **t1 = (htnames_t **)v1;
71 htnames_t **t2 = (htnames_t **)v2;
72
73 return strcmp((*t1)->name, (*t2)->name);
74 }
75
76
is_net_test(char * tname)77 static int is_net_test(char *tname)
78 {
79 char *miscnet[] = { NULL, "http", "dns", "dig", "rpc", "ntp", "ldap", "content", "sslcert", NULL };
80 int i;
81
82 miscnet[0] = pingcolumn; /* Cannot be computed in advance */
83 if (find_tcp_service(tname)) return 1;
84 for (i=0; (miscnet[i]); i++) if (strcmp(tname, miscnet[i]) == 0) return 1;
85
86 return 0;
87 }
88
89
use_columndoc(char * column)90 void use_columndoc(char *column)
91 {
92 coltext_t *cwalk;
93
94 for (cwalk = chead; (cwalk && strcasecmp(cwalk->colname, column)); cwalk = cwalk->next);
95 if (cwalk) cwalk->used = 1;
96 }
97
98 typedef struct tag_t {
99 char *columnname;
100 char *visualdata; /* The URL or other end-user visible test spec. */
101 char *expdata;
102 int b1, b2, b3; /* "badFOO" values, if any */
103 struct tag_t *next;
104 } tag_t;
105
print_disklist(char * hostname)106 static void print_disklist(char *hostname)
107 {
108 /*
109 * We get the list of monitored disks/filesystems by looking at the
110 * set of disk RRD files for this host. That way we do not have to
111 * parse the disk status reports that come in many different flavours.
112 */
113
114 char dirname[PATH_MAX];
115 char fn[PATH_MAX];
116 DIR *d;
117 struct dirent *de;
118 char *p;
119
120 snprintf(dirname, sizeof(dirname)-1, "%s/%s", xgetenv("XYMONRRDS"), hostname);
121 d = opendir(dirname);
122 if (!d) return;
123
124 while ((de = readdir(d)) != NULL) {
125 if (strncmp(de->d_name, "disk,", 5) == 0) {
126 strncpy(fn, de->d_name + 4, sizeof(fn));
127 p = strstr(fn, ".rrd"); if (!p) continue;
128 *p = '\0';
129 p = fn; while ((p = strchr(p, ',')) != NULL) *p = '/';
130 fprintf(stdout, "%s<br>\n", fn);
131 }
132 }
133
134 closedir(d);
135 }
136
criticalval(char * hname,char * tname,char * alerts)137 char *criticalval(char *hname, char *tname, char *alerts)
138 {
139 STATIC_SBUF_DEFINE(result);
140
141 if (result) xfree(result);
142
143 if (newcritconfig) {
144 SBUF_DEFINE(key);
145 critconf_t *critrec;
146
147 SBUF_MALLOC(key, strlen(hname) + strlen(tname) + 2);
148 snprintf(key, key_buflen, "%s|%s", hname, tname);
149 critrec = get_critconfig(key, CRITCONF_FIRSTMATCH, NULL);
150 if (!critrec) {
151 result = strdup("No");
152 }
153 else {
154 char *tspec;
155
156 tspec = (critrec->crittime ? timespec_text(critrec->crittime) : "24x7");
157 SBUF_MALLOC(result, strlen(tspec) + 30);
158 snprintf(result, result_buflen, "%s prio %d", tspec, critrec->priority);
159 }
160 xfree(key);
161 }
162 else {
163 result = strdup((checkalert(alerts, tname) ? "Yes" : "No"));
164 }
165
166 return result;
167 }
168
169
print_host(hostlist_t * host,htnames_t * testnames[],int testcount)170 static void print_host(hostlist_t *host, htnames_t *testnames[], int testcount)
171 {
172 int testi, rowcount, netcount;
173 void *hinfo = hostinfo(host->hostname);
174 char *dispname = NULL, *clientalias = NULL, *comment = NULL, *description = NULL, *pagepathtitle = NULL;
175 char *net = NULL, *alerts = NULL;
176 char *crittime = NULL, *downtime = NULL, *reporttime = NULL;
177 char *itm;
178 tag_t *taghead = NULL;
179 int contidx = 0, haveping = 0;
180 char contcol[1024];
181 activealerts_t *alert;
182 strbuffer_t *buf = newstrbuffer(0);
183
184 fprintf(stdout, "<p style=\"page-break-before: always\">\n");
185 fprintf(stdout, "<table width=\"100%%\" border=1 summary=\"%s configuration\">\n", host->hostname);
186
187 pagepathtitle = xmh_item(hinfo, XMH_PAGEPATHTITLE);
188 if (!pagepathtitle || (strlen(pagepathtitle) == 0)) pagepathtitle = "Top page";
189 dispname = xmh_item(hinfo, XMH_DISPLAYNAME);
190 if (dispname && (strcmp(dispname, host->hostname) == 0)) dispname = NULL;
191 clientalias = xmh_item(hinfo, XMH_CLIENTALIAS);
192 if (clientalias && (strcmp(clientalias, host->hostname) == 0)) clientalias = NULL;
193 comment = xmh_item(hinfo, XMH_COMMENT);
194 description = xmh_item(hinfo, XMH_DESCRIPTION);
195 net = xmh_item(hinfo, XMH_NET);
196 alerts = xmh_item(hinfo, XMH_NK);
197 crittime = xmh_item(hinfo, XMH_NKTIME); if (!crittime) crittime = "24x7"; else crittime = strdup(timespec_text(crittime));
198 downtime = xmh_item(hinfo, XMH_DOWNTIME); if (downtime) downtime = strdup(timespec_text(downtime));
199 reporttime = xmh_item(hinfo, XMH_REPORTTIME); if (!reporttime) reporttime = "24x7"; else reporttime = strdup(timespec_text(reporttime));
200
201 rowcount = 1;
202 if (pagepathtitle) rowcount++;
203 if (dispname || clientalias) rowcount++;
204 if (comment) rowcount++;
205 if (description) rowcount++;
206 if (!newcritconfig && crittime) rowcount++;
207 if (downtime) rowcount++;
208 if (reporttime) rowcount++;
209
210 fprintf(stdout, "<tr>\n");
211 fprintf(stdout, "<th rowspan=%d align=left width=\"25%%\" valign=top>Basics</th>\n", rowcount);
212 fprintf(stdout, "<th align=center>%s (%s)</th>\n",
213 (dispname ? dispname : host->hostname), xmh_item(hinfo, XMH_IP));
214 fprintf(stdout, "</tr>\n");
215
216 if (dispname || clientalias) {
217 fprintf(stdout, "<tr><td>Aliases:");
218 if (dispname) fprintf(stdout, " %s", dispname);
219 if (clientalias) fprintf(stdout, " %s", clientalias);
220 fprintf(stdout, "</td></tr>\n");
221 }
222 if (pagepathtitle) fprintf(stdout, "<tr><td>Monitoring location: %s</td></tr>\n", pagepathtitle);
223 if (comment) fprintf(stdout, "<tr><td>Comment: %s</td></tr>\n", comment);
224 if (description) fprintf(stdout, "<tr><td>Description: %s</td></tr>\n", description);
225 if (!newcritconfig && crittime) fprintf(stdout, "<tr><td>Critical monitoring period: %s</td></tr>\n", crittime);
226 if (downtime) fprintf(stdout, "<tr><td>Planned downtime: %s</td></tr>\n", downtime);
227 if (reporttime) fprintf(stdout, "<tr><td>SLA Reporting Period: %s</td></tr>\n", reporttime);
228
229
230 /* Build a list of the network tests */
231 itm = xmh_item_walk(hinfo);
232 while (itm) {
233 char *visdata = NULL, *colname = NULL, *expdata = NULL;
234 weburl_t bu;
235 int httpextra = 0;
236
237 /* Skip modifiers */
238 itm += strspn(itm, "?!~");
239
240 if ( argnmatch(itm, "http") ||
241 argnmatch(itm, "content=http") ||
242 argnmatch(itm, "cont;http") ||
243 argnmatch(itm, "cont=") ||
244 argnmatch(itm, "nocont;http") ||
245 argnmatch(itm, "nocont=") ||
246 argnmatch(itm, "post;http") ||
247 argnmatch(itm, "post=") ||
248 argnmatch(itm, "nopost;http") ||
249 argnmatch(itm, "nopost=") ||
250 argnmatch(itm, "type;http") ||
251 argnmatch(itm, "type=") ) {
252 visdata = decode_url(itm, &bu);
253 colname = bu.columnname;
254 if (!colname) {
255 if (bu.expdata) {
256 httpextra = 1;
257 if (contidx == 0) {
258 colname = "content";
259 contidx++;
260 }
261 else {
262 snprintf(contcol, sizeof(contcol)-1, "content%d", contidx);
263 colname = contcol;
264 contidx++;
265 }
266 }
267 else {
268 colname = "http";
269 }
270 }
271 expdata = bu.expdata;
272 }
273 else if (strncmp(itm, "rpc=", 4) == 0) {
274 colname = "rpc";
275 visdata = strdup(itm+4);
276 }
277 else if (strncmp(itm, "dns=", 4) == 0) {
278 colname = "dns";
279 visdata = strdup(itm+4);
280 }
281 else if (strncmp(itm, "dig=", 4) == 0) {
282 colname = "dns";
283 visdata = strdup(itm+4);
284 }
285 else if (strncmp(itm, pingplus, strlen(pingplus)) == 0) {
286 haveping = 1;
287 colname = pingcolumn;
288 visdata = strdup(itm+strlen(pingplus));
289 }
290 else if (is_net_test(itm)) {
291 colname = strdup(itm);
292 visdata = strdup("");
293 }
294
295 if (!visdata) visdata = strdup("");
296 if (colname) {
297 tag_t *newitem;
298
299 addtolist:
300 for (newitem = taghead; (newitem && strcmp(newitem->columnname, colname)); newitem = newitem->next);
301
302 if (!newitem) {
303 newitem = (tag_t *)calloc(1, sizeof(tag_t));
304 newitem->columnname = strdup(colname);
305 newitem->visualdata = (visdata ? strdup(visdata) : NULL);
306 newitem->expdata = (expdata ? strdup(expdata) : NULL);
307 newitem->next = taghead;
308 taghead = newitem;
309 }
310 else {
311 /* Multiple tags for one column - must be http */
312 newitem->visualdata = newitem->visualdata ?
313 (char *)realloc(newitem->visualdata, strlen(newitem->visualdata) + strlen(visdata) + 5) :
314 (char *)malloc(strlen(visdata) + 5);
315 strcat(newitem->visualdata, "<br>");
316 strcat(newitem->visualdata, visdata);
317 }
318
319 if (httpextra) {
320 httpextra = 0;
321 colname = "http";
322 expdata = NULL;
323 goto addtolist;
324 }
325 }
326
327 itm = xmh_item_walk(NULL);
328 }
329
330 if (!haveping && !xmh_item(hinfo, XMH_FLAG_NOCONN)) {
331 for (testi = 0; (testi < testcount); testi++) {
332 if (strcmp(testnames[testi]->name, pingcolumn) == 0) {
333 tag_t *newitem = (tag_t *)calloc(1, sizeof(tag_t));
334 newitem->columnname = strdup(pingcolumn);
335 newitem->next = taghead;
336 taghead = newitem;
337 }
338 }
339 }
340
341 /* Add the "badFOO" settings */
342 itm = xmh_item_walk(hinfo);
343 while (itm) {
344 if (strncmp(itm, "bad", 3) == 0) {
345 char *tname, *p;
346 int b1, b2, b3, n = -1;
347 tag_t *tag = NULL;
348
349 tname = itm+3;
350 p = strchr(tname, ':');
351 if (p) {
352 *p = '\0';
353 n = sscanf(p+1, "%d:%d:%d", &b1, &b2, &b3);
354 for (tag = taghead; (tag && strcmp(tag->columnname, tname)); tag = tag->next);
355 *p = ':';
356 }
357
358 if (tag && (n == 3)) {
359 tag->b1 = b1; tag->b2 = b2; tag->b3 = b3;
360 }
361 }
362
363 itm = xmh_item_walk(NULL);
364 }
365
366 if (taghead) {
367 fprintf(stdout, "<tr>\n");
368 fprintf(stdout, "<th align=left valign=top>Network tests");
369 if (net) fprintf(stdout, "<br>(from %s)", net);
370 fprintf(stdout, "</th>\n");
371
372 fprintf(stdout, "<td><table border=0 cellpadding=\"3\" cellspacing=\"5\" summary=\"%s network tests\">\n", host->hostname);
373 fprintf(stdout, "<tr><th align=left valign=top>Service</th><th align=left valign=top>Critical</th><th align=left valign=top>C/Y/R limits</th><th align=left valign=top>Specifics</th></tr>\n");
374 }
375 for (testi = 0, netcount = 0; (testi < testcount); testi++) {
376 tag_t *twalk;
377
378 for (twalk = taghead; (twalk && strcasecmp(twalk->columnname, testnames[testi]->name)); twalk = twalk->next);
379 if (!twalk) continue;
380
381 use_columndoc(testnames[testi]->name);
382 fprintf(stdout, "<tr>");
383 fprintf(stdout, "<td valign=top>%s</td>", testnames[testi]->name);
384 fprintf(stdout, "<td valign=top>%s</td>", criticalval(host->hostname, testnames[testi]->name, alerts));
385
386 fprintf(stdout, "<td valign=top>");
387 if (twalk->b1 || twalk->b2 || twalk->b3) {
388 fprintf(stdout, "%d/%d/%d", twalk->b1, twalk->b2, twalk->b3);
389 }
390 else {
391 fprintf(stdout, "-/-/-");
392 }
393 fprintf(stdout, "</td>");
394
395 fprintf(stdout, "<td valign=top>");
396 fprintf(stdout, "<i>%s</i>", (twalk->visualdata ? twalk->visualdata : " "));
397 if (twalk->expdata) fprintf(stdout, " must return <i>'%s'</i>", twalk->expdata);
398 fprintf(stdout, "</td>");
399
400 fprintf(stdout, "</tr>");
401 netcount++;
402 }
403 if (taghead) {
404 fprintf(stdout, "</table></td>\n");
405 fprintf(stdout, "</tr>\n");
406 }
407
408
409 if (netcount != testcount) {
410 fprintf(stdout, "<tr>\n");
411 fprintf(stdout, "<th align=left valign=top>Local tests</th>\n");
412 fprintf(stdout, "<td><table border=0 cellpadding=\"3\" cellspacing=\"5\" summary=\"%s local tests\">\n", host->hostname);
413 fprintf(stdout, "<tr><th align=left valign=top>Service</th><th align=left valign=top>Critical</th><th align=left valign=top>C/Y/R limits</th><th align=left valign=top>Configuration <i>(NB: Thresholds on client may differ)</i></th></tr>\n");
414 }
415 for (testi = 0; (testi < testcount); testi++) {
416 tag_t *twalk;
417
418 for (twalk = taghead; (twalk && strcasecmp(twalk->columnname, testnames[testi]->name)); twalk = twalk->next);
419 if (twalk) continue;
420
421 use_columndoc(testnames[testi]->name);
422 fprintf(stdout, "<tr>");
423 fprintf(stdout, "<td valign=top>%s</td>", testnames[testi]->name);
424 fprintf(stdout, "<td valign=top>%s</td>", criticalval(host->hostname, testnames[testi]->name, alerts));
425 fprintf(stdout, "<td valign=top>-/-/-</td>");
426
427 /* Make up some default configuration data */
428 fprintf(stdout, "<td valign=top>");
429 if (strcmp(testnames[testi]->name, "cpu") == 0) {
430 fprintf(stdout, "UNIX - Yellow: Load average > 1.5, Red: Load average > 3.0<br>");
431 fprintf(stdout, "Windows - Yellow: CPU utilisation > 80%%, Red: CPU utilisation > 95%%");
432 }
433 else if (strcmp(testnames[testi]->name, "disk") == 0) {
434 fprintf(stdout, "Default limits: Yellow 90%% full, Red 95%% full<br>\n");
435 print_disklist(host->hostname);
436 }
437 else if (strcmp(testnames[testi]->name, "memory") == 0) {
438 fprintf(stdout, "Yellow: swap/pagefile use > 80%%, Red: swap/pagefile use > 90%%");
439 }
440 else if (strcmp(testnames[testi]->name, "procs") == 0) {
441 htnames_t *walk;
442
443 if (!host->procs) fprintf(stdout, "No processes monitored<br>\n");
444
445 for (walk = host->procs; (walk); walk = walk->next) {
446 fprintf(stdout, "%s<br>\n", walk->name);
447 }
448 }
449 else if (strcmp(testnames[testi]->name, "svcs") == 0) {
450 htnames_t *walk;
451
452 if (!host->svcs) fprintf(stdout, "No services monitored<br>\n");
453
454 for (walk = host->svcs; (walk); walk = walk->next) {
455 fprintf(stdout, "%s<br>\n", walk->name);
456 }
457 }
458 else {
459 fprintf(stdout, " ");
460 }
461 fprintf(stdout, "</td>");
462
463 fprintf(stdout, "</tr>");
464 }
465 if (netcount != testcount) {
466 fprintf(stdout, "</table></td>\n");
467 fprintf(stdout, "</tr>\n");
468 }
469
470 /* Do the alerts */
471 alert = (activealerts_t *)calloc(1, sizeof(activealerts_t));
472 alert->hostname = host->hostname;
473 alert->location = xmh_item(hinfo, XMH_ALLPAGEPATHS);
474 strncpy(alert->ip, "127.0.0.1", sizeof(alert->ip));
475 alert->color = COL_RED;
476 alert->pagemessage = "";
477 alert->state = A_PAGING;
478 alert->cookie = 12345;
479 alert_printmode(2);
480 for (testi = 0; (testi < testcount); testi++) {
481 alert->testname = testnames[testi]->name;
482 if (have_recipient(alert, NULL)) print_alert_recipients(alert, buf);
483 }
484 xfree(alert);
485
486 if (STRBUFLEN(buf) > 0) {
487 fprintf(stdout, "<tr>\n");
488 fprintf(stdout, "<th align=left valign=top>Alerts</th>\n");
489 fprintf(stdout, "<td><table border=0 cellpadding=\"3\" cellspacing=\"5\" summary=\"%s alerts\">\n", host->hostname);
490 fprintf(stdout, "<tr><th>Service</th><th>Recipient</th><th>1st Delay</th><th>Stop after</th><th>Repeat</th><th>Time of Day</th><th>Colors</th></tr>\n");
491
492 fprintf(stdout, "%s", STRBUF(buf));
493
494 fprintf(stdout, "</table></td>\n");
495 fprintf(stdout, "</tr>\n");
496 }
497
498 /* Finish off this host */
499 fprintf(stdout, "</table>\n");
500
501 freestrbuffer(buf);
502 }
503
504
coltext_compare(const void * v1,const void * v2)505 static int coltext_compare(const void *v1, const void *v2)
506 {
507 coltext_t **t1 = (coltext_t **)v1;
508 coltext_t **t2 = (coltext_t **)v2;
509
510 return strcmp((*t1)->colname, (*t2)->colname);
511 }
512
load_columndocs(void)513 void load_columndocs(void)
514 {
515 char fn[PATH_MAX];
516 FILE *fd;
517 strbuffer_t *inbuf;
518
519 snprintf(fn, sizeof(fn)-1, "%s/etc/columndoc.csv", xgetenv("XYMONHOME"));
520 fd = fopen(fn, "r"); if (!fd) return;
521
522 inbuf = newstrbuffer(0);
523 initfgets(fd);
524
525 /* Skip the header line */
526 if (!unlimfgets(inbuf, fd)) { fclose(fd); freestrbuffer(inbuf); return; }
527
528 while (unlimfgets(inbuf, fd)) {
529 char *s1 = NULL, *s2 = NULL;
530
531 s1 = strtok(STRBUF(inbuf), coldelim);
532 if (s1) s2 = strtok(NULL, coldelim);
533
534 if (s1 && s2) {
535 coltext_t *newitem = (coltext_t *)calloc(1, sizeof(coltext_t));
536 newitem->colname = strdup(s1);
537 newitem->coldescr = strdup(s2);
538 newitem->next = chead;
539 chead = newitem;
540 ccount++;
541 }
542 }
543 fclose(fd);
544 freestrbuffer(inbuf);
545 }
546
547
print_columndocs(void)548 void print_columndocs(void)
549 {
550 coltext_t **clist;
551 coltext_t *cwalk;
552 int i;
553
554 clist = (coltext_t **)malloc(ccount * sizeof(coltext_t *));
555 for (i=0, cwalk=chead; (cwalk); cwalk=cwalk->next,i++) clist[i] = cwalk;
556 qsort(&clist[0], ccount, sizeof(coltext_t **), coltext_compare);
557
558 fprintf(stdout, "<p style=\"page-break-before: always\">\n");
559 fprintf(stdout, "<table width=\"100%%\" border=1 summary=\"Column descriptions\">\n");
560 fprintf(stdout, "<tr><th colspan=2>Xymon column descriptions</th></tr>\n");
561 for (i=0; (i<ccount); i++) {
562 if (clist[i]->used) {
563 fprintf(stdout, "<tr><td align=left valign=top>%s</td><td>%s</td></tr>\n",
564 clist[i]->colname, clist[i]->coldescr);
565 }
566 }
567
568 fprintf(stdout, "</table>\n");
569 }
570
get_proclist(char * hostname,char * statusbuf)571 htnames_t *get_proclist(char *hostname, char *statusbuf)
572 {
573 char *bol, *eol;
574 SBUF_DEFINE(marker);
575 htnames_t *head = NULL, *tail = NULL;
576
577 if (!statusbuf) return NULL;
578
579 SBUF_MALLOC(marker, strlen(hostname) + 3);
580 snprintf(marker, marker_buflen, "\n%s|", hostname);
581 if (strncmp(statusbuf, marker+1, strlen(marker)-1) == 0) {
582 /* Found at start of buffer */
583 bol = statusbuf;
584 }
585 else {
586 bol = strstr(statusbuf, marker);
587 if (bol) bol++;
588 }
589 xfree(marker);
590
591 if (!bol) return NULL;
592
593 bol += strlen(hostname) + 1; /* Skip hostname and delimiter */
594 marker = bol;
595 eol = strchr(bol, '\n'); if (eol) *eol = '\0';
596 marker = strstr(marker, "\\n&");
597 while (marker) {
598 char *p;
599 htnames_t *newitem;
600
601 marker += strlen("\\n&");
602 if (strncmp(marker, "green", 5) == 0) marker += 5;
603 else if (strncmp(marker, "yellow", 6) == 0) marker += 6;
604 else if (strncmp(marker, "red", 3) == 0) marker += 3;
605 else marker = NULL;
606
607 if (marker) {
608 marker += strspn(marker, " \t");
609
610 p = strstr(marker, "\\n"); if (p) *p = '\0';
611 newitem = (htnames_t *)malloc(sizeof(htnames_t));
612 newitem->name = strdup(marker);
613 newitem->next = NULL;
614 if (!tail) {
615 head = tail = newitem;
616 }
617 else {
618 tail->next = newitem;
619 tail = newitem;
620 }
621
622 if (p) {
623 *p = '\\';
624 }
625
626 marker = strstr(marker, "\\n&");
627 }
628 }
629 if (eol) *eol = '\n';
630
631 return head;
632 }
633
main(int argc,char * argv[])634 int main(int argc, char *argv[])
635 {
636 int argi, hosti, testi;
637 char *pagepattern = NULL, *hostpattern = NULL;
638 char *envarea = NULL, *cookie = NULL, *nexthost;
639 SBUF_DEFINE(xymoncmd);
640 SBUF_DEFINE(procscmd);
641 SBUF_DEFINE(svcscmd);
642 int alertcolors, alertinterval;
643 char configfn[PATH_MAX];
644 char *respbuf = NULL, *procsbuf = NULL, *svcsbuf = NULL;
645 hostlist_t *hwalk;
646 htnames_t *twalk;
647 hostlist_t **allhosts = NULL;
648 htnames_t **alltests = NULL;
649 int hostcount = 0, maxtests = 0;
650 time_t now = getcurrenttime(NULL);
651 sendreturn_t *sres;
652 char *critconfigfn = NULL;
653 int patternerror = 0;
654
655 for (argi=1; (argi < argc); argi++) {
656 if (argnmatch(argv[argi], "--env=")) {
657 char *p = strchr(argv[argi], '=');
658 loadenv(p+1, envarea);
659 }
660 else if (argnmatch(argv[argi], "--area=")) {
661 char *p = strchr(argv[argi], '=');
662 envarea = strdup(p+1);
663 }
664 else if (strcmp(argv[argi], "--debug") == 0) {
665 debug = 1;
666 }
667 else if (argnmatch(argv[argi], "--delimiter=")) {
668 char *p = strchr(argv[argi], '=');
669 coldelim = strdup(p+1);
670 }
671 else if (strcmp(argv[argi], "--critical") == 0) {
672 criticalonly = 1;
673 }
674 else if (strcmp(argv[argi], "--old-critical-config") == 0) {
675 newcritconfig = 0;
676 }
677 else if (argnmatch(argv[argi], "--critical-config=")) {
678 char *p = strchr(argv[argi], '=');
679 critconfigfn = strdup(p+1);
680 }
681 }
682
683 redirect_cgilog("confreport");
684
685 load_hostnames(xgetenv("HOSTSCFG"), NULL, get_fqdn());
686 load_critconfig(critconfigfn);
687
688 SBUF_MALLOC(pingplus, 6); strncpy(pingplus, "conn=", pingplus_buflen);
689
690 /* Setup the filter we use for the report */
691 cookie = get_cookie("pagepath"); if (cookie && *cookie) pagepattern = strdup(cookie);
692 cookie = get_cookie("host"); if (cookie && *cookie) hostpattern = strdup(cookie);
693
694 /* Fetch the list of host+test statuses we currently know about */
695 if (pagepattern) {
696 pcre *dummy;
697 SBUF_DEFINE(re);
698
699 SBUF_MALLOC(re, 8 + 2*strlen(pagepattern));
700 snprintf(re, re_buflen, "^%s$|^%s/.+", pagepattern, pagepattern);
701 dummy = compileregex(re);
702 if (dummy) {
703 freeregex(dummy);
704
705 SBUF_MALLOC(xymoncmd, 2*strlen(pagepattern) + 1024);
706 SBUF_MALLOC(procscmd, 2*strlen(pagepattern) + 1024);
707 SBUF_MALLOC(svcscmd, 2*strlen(pagepattern) + 1024);
708
709 snprintf(xymoncmd, xymoncmd_buflen, "xymondboard page=%s fields=hostname,testname", re);
710 snprintf(procscmd, procscmd_buflen, "xymondboard page=%s test=procs fields=hostname,msg", re);
711 snprintf(svcscmd, svcscmd_buflen, "xymondboard page=%s test=svcs fields=hostname,msg", re);
712 }
713 else
714 patternerror = 1;
715
716 xfree(re);
717 }
718 else if (hostpattern) {
719 pcre *dummy;
720 SBUF_DEFINE(re);
721
722 SBUF_MALLOC(re,3 + strlen(hostpattern));
723 snprintf(re, re_buflen, "^%s$", hostpattern);
724 dummy = compileregex(re);
725 if (dummy) {
726 freeregex(dummy);
727
728 SBUF_MALLOC(xymoncmd, strlen(hostpattern) + 1024);
729 SBUF_MALLOC(procscmd, strlen(hostpattern) + 1024);
730 SBUF_MALLOC(svcscmd, strlen(hostpattern) + 1024);
731
732 snprintf(xymoncmd, xymoncmd_buflen, "xymondboard host=^%s$ fields=hostname,testname", hostpattern);
733 snprintf(procscmd, procscmd_buflen, "xymondboard host=^%s$ test=procs fields=hostname,msg", hostpattern);
734 snprintf(svcscmd, svcscmd_buflen, "xymondboard host=^%s$ test=svcs fields=hostname,msg", hostpattern);
735 }
736 else
737 patternerror = 1;
738
739 xfree(re);
740 }
741 else {
742 SBUF_MALLOC(xymoncmd, 1024);
743 SBUF_MALLOC(procscmd, 1024);
744 SBUF_MALLOC(svcscmd, 1024);
745
746 snprintf(xymoncmd, xymoncmd_buflen, "xymondboard fields=hostname,testname");
747 snprintf(procscmd, procscmd_buflen, "xymondboard test=procs fields=hostname,msg");
748 snprintf(svcscmd, svcscmd_buflen, "xymondboard test=svcs fields=hostname,msg");
749 }
750
751 if (patternerror) {
752 errormsg("Invalid host/page filter\n");
753 return 1;
754 }
755
756 sres = newsendreturnbuf(1, NULL);
757
758 if (sendmessage(xymoncmd, NULL, XYMON_TIMEOUT, sres) != XYMONSEND_OK) {
759 errormsg("Cannot contact the Xymon server\n");
760 return 1;
761 }
762 respbuf = getsendreturnstr(sres, 1);
763 if (sendmessage(procscmd, NULL, XYMON_TIMEOUT, sres) != XYMONSEND_OK) {
764 errormsg("Cannot contact the Xymon server\n");
765 return 1;
766 }
767 procsbuf = getsendreturnstr(sres, 1);
768 if (sendmessage(svcscmd, NULL, XYMON_TIMEOUT, sres) != XYMONSEND_OK) {
769 errormsg("Cannot contact the Xymon server\n");
770 return 1;
771 }
772 svcsbuf = getsendreturnstr(sres, 1);
773
774 freesendreturnbuf(sres);
775
776 if (!respbuf) {
777 errormsg("Unable to find host information\n");
778 return 1;
779 }
780
781 /* Parse it into a usable list */
782 nexthost = respbuf;
783 do {
784 char *hname, *tname, *eoln;
785 int wanted = 1;
786
787 eoln = strchr(nexthost, '\n'); if (eoln) *eoln = '\0';
788 hname = nexthost;
789 tname = strchr(nexthost, '|'); if (tname) { *tname = '\0'; tname++; }
790
791 if (criticalonly) {
792 void *hinfo = hostinfo(hname);
793 char *alerts = xmh_item(hinfo, XMH_NK);
794
795 if (newcritconfig) {
796 if (strcmp(criticalval(hname, tname, alerts), "No") == 0 ) wanted = 0;
797 } else {
798 if (!alerts) wanted = 0;
799 }
800 }
801
802 if (wanted && hname && tname && strcmp(hname, "summary") && strcmp(tname, xgetenv("INFOCOLUMN")) && strcmp(tname, xgetenv("TRENDSCOLUMN"))) {
803 htnames_t *newitem = (htnames_t *)malloc(sizeof(htnames_t));
804
805 for (hwalk = hosthead; (hwalk && strcmp(hwalk->hostname, hname)); hwalk = hwalk->next);
806 if (!hwalk) {
807 hwalk = (hostlist_t *)calloc(1, sizeof(hostlist_t));
808 hwalk->hostname = strdup(hname);
809 hwalk->procs = get_proclist(hname, procsbuf);
810 hwalk->svcs = get_proclist(hname, svcsbuf);
811 hwalk->next = hosthead;
812 hosthead = hwalk;
813 hostcount++;
814 }
815
816 newitem->name = strdup(tname);
817 newitem->next = hwalk->tests;
818 hwalk->tests = newitem;
819 hwalk->testcount++;
820 }
821
822 if (eoln) {
823 nexthost = eoln+1;
824 if (*nexthost == '\0') nexthost = NULL;
825 }
826 } while (nexthost);
827
828 if (hostcount > 0) {
829 allhosts = (hostlist_t **) malloc(hostcount * sizeof(hostlist_t *));
830 for (hwalk = hosthead, hosti=0; (hwalk); hwalk = hwalk->next, hosti++) {
831 allhosts[hosti] = hwalk;
832 if (hwalk->testcount > maxtests) maxtests = hwalk->testcount;
833 }
834 if (maxtests > 0) alltests = (htnames_t **) malloc(maxtests * sizeof(htnames_t *));
835 qsort(&allhosts[0], hostcount, sizeof(hostlist_t **), host_compare);
836 }
837
838 if ((hostcount == 0) || (maxtests == 0)) {
839 printf("Content-Type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
840 printf("<html><body><h1>No hosts or tests to report!</h1></body></html>\n");
841 return 0;
842 }
843
844 /* Get the static info */
845 load_all_links();
846 init_tcp_services();
847 pingcolumn = xgetenv("PINGCOLUMN");
848 SBUF_REALLOC(pingplus, strlen(pingcolumn) + 3);
849 snprintf(pingplus, pingplus_buflen, "%s=", pingcolumn);
850
851 /* Load alert config */
852 alertcolors = colorset(xgetenv("ALERTCOLORS"), ((1 << COL_GREEN) | (1 << COL_BLUE)));
853 alertinterval = 60*atoi(xgetenv("ALERTREPEAT"));
854 snprintf(configfn, sizeof(configfn)-1, "%s/etc/alerts.cfg", xgetenv("XYMONHOME"));
855 load_alertconfig(configfn, alertcolors, alertinterval);
856 load_columndocs();
857
858
859 printf("Content-Type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
860 sethostenv("", "", "", colorname(COL_BLUE), NULL);
861 headfoot(stdout, "confreport", "", "header", COL_BLUE);
862
863 fprintf(stdout, "<table width=\"100%%\" border=0>\n");
864 fprintf(stdout, "<tr><th align=center colspan=2><font size=\"+2\">Xymon configuration Report</font></th></tr>\n");
865 fprintf(stdout, "<tr><th valign=top align=left>Date</th><td>%s</td></tr>\n", ctime(&now));
866 fprintf(stdout, "<tr><th valign=top align=left>%d hosts included</th><td>\n", hostcount);
867 for (hosti=0; (hosti < hostcount); hosti++) {
868 fprintf(stdout, "%s ", allhosts[hosti]->hostname);
869 }
870 fprintf(stdout, "</td></tr>\n");
871 if (criticalonly) {
872 fprintf(stdout, "<tr><th valign=top align=left>Filter</th><td>Only data for the "Critical Systems" view reported</td></tr>\n");
873 }
874 fprintf(stdout, "</table>\n");
875
876 headfoot(stdout, "confreport", "", "front", COL_BLUE);
877
878 for (hosti=0; (hosti < hostcount); hosti++) {
879 for (twalk = allhosts[hosti]->tests, testi = 0; (twalk); twalk = twalk->next, testi++) {
880 alltests[testi] = twalk;
881 }
882 qsort(&alltests[0], allhosts[hosti]->testcount, sizeof(htnames_t **), test_compare);
883
884 print_host(allhosts[hosti], alltests, allhosts[hosti]->testcount);
885 }
886
887 headfoot(stdout, "confreport", "", "back", COL_BLUE);
888 print_columndocs();
889
890 headfoot(stdout, "confreport", "", "footer", COL_BLUE);
891
892 return 0;
893 }
894
895