1 /*----------------------------------------------------------------------------*/
2 /* Xymon status-log viewer CGI. */
3 /* */
4 /* This CGI tool shows an HTML version of a status log. */
5 /* */
6 /* Copyright (C) 2004-2011 Henrik Storner <henrik@storner.dk> */
7 /* */
8 /* This program is released under the GNU General Public License (GPL), */
9 /* version 2. See the file "COPYING" for details. */
10 /* */
11 /*----------------------------------------------------------------------------*/
12
13 static char rcsid[] = "$Id: svcstatus.c 8069 2019-07-23 15:29:06Z jccleaver $";
14
15 #include <limits.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <ctype.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <libgen.h>
25
26 #include "libxymon.h"
27 #include "version.h"
28 #include "svcstatus-info.h"
29 #include "svcstatus-trends.h"
30
31 /* Command-line params */
32 static enum { SRC_XYMOND, SRC_HISTLOGS, SRC_CLIENTLOGS } source = SRC_XYMOND;
33 static int wantserviceid = 1;
34 SBUF_DEFINE(multigraphs);
35 static int locatorbased = 0;
36 static char *critconfigfn = NULL;
37 static char *accessfn = NULL;
38
39 /* CGI params */
40 static char *hostname = NULL;
41 static char *service = NULL;
42 static char *tstamp = NULL;
43 static char *nkprio = NULL, *nkttgroup = NULL, *nkttextra = NULL;
44 static enum { FRM_STATUS, FRM_CLIENT } outform = FRM_STATUS;
45 STATIC_SBUF_DEFINE(clienturi);
46 static int backsecs = 0;
47 static time_t fromtime = 0, endtime = 0;
48
49 static char errortxt[1000];
50 STATIC_SBUF_DEFINE(hostdatadir);
51
52
errormsg(int status,char * msg)53 static void errormsg(int status, char *msg)
54 {
55 snprintf(errortxt, sizeof(errortxt),
56 "Status: %d\nRefresh: 30\nContent-type: %s\n\n<html><head><title>Invalid request</title></head>\n<body>%s</body></html>\n",
57 status, xgetenv("HTMLCONTENTTYPE"), msg);
58
59 errortxt[sizeof(errortxt)-1] = '\0';
60 }
61
parse_query(void)62 static int parse_query(void)
63 {
64 cgidata_t *cgidata = cgi_request();
65 cgidata_t *cwalk;
66
67 cwalk = cgidata;
68 while (cwalk) {
69 if (strcasecmp(cwalk->name, "HOST") == 0) {
70 hostname = strdup(basename(cwalk->value));
71 }
72 else if (strcasecmp(cwalk->name, "SERVICE") == 0) {
73 service = strdup(basename(cwalk->value));
74 }
75 else if (strcasecmp(cwalk->name, "HOSTSVC") == 0) {
76 /* For backwards compatibility */
77 char *p = strrchr(cwalk->value, '.');
78 if (p) {
79 *p = '\0';
80 hostname = strdup(basename(cwalk->value));
81 service = strdup(p+1);
82 for (p=strchr(hostname, ','); (p); p = strchr(p, ',')) *p = '.';
83 }
84 }
85 else if (strcasecmp(cwalk->name, "TIMEBUF") == 0) {
86 /* Only for the historical logs */
87 tstamp = strdup(basename(cwalk->value));
88 }
89 else if (strcasecmp(cwalk->name, "CLIENT") == 0) {
90 char *p;
91
92 hostname = strdup(cwalk->value);
93 p = hostname; while ((p = strchr(p, ',')) != NULL) *p = '.';
94 service = strdup("");
95 outform = FRM_CLIENT;
96 }
97 else if (strcasecmp(cwalk->name, "SECTION") == 0) {
98 service = strdup(cwalk->value);
99 }
100 else if (strcasecmp(cwalk->name, "NKPRIO") == 0) {
101 nkprio = strdup(cwalk->value);
102 }
103 else if (strcasecmp(cwalk->name, "NKTTGROUP") == 0) {
104 nkttgroup = strdup(cwalk->value);
105 }
106 else if (strcasecmp(cwalk->name, "NKTTEXTRA") == 0) {
107 nkttextra = strdup(cwalk->value);
108 }
109 else if ((strcmp(cwalk->name, "backsecs") == 0) && cwalk->value && strlen(cwalk->value)) {
110 backsecs += atoi(cwalk->value);
111 }
112 else if ((strcmp(cwalk->name, "backmins") == 0) && cwalk->value && strlen(cwalk->value)) {
113 backsecs += 60*atoi(cwalk->value);
114 }
115 else if ((strcmp(cwalk->name, "backhours") == 0) && cwalk->value && strlen(cwalk->value)) {
116 backsecs += 60*60*atoi(cwalk->value);
117 }
118 else if ((strcmp(cwalk->name, "backdays") == 0) && cwalk->value && strlen(cwalk->value)) {
119 backsecs += 24*60*60*atoi(cwalk->value);
120 }
121 else if ((strcmp(cwalk->name, "FROMTIME") == 0) && cwalk->value && strlen(cwalk->value)) {
122 fromtime = eventreport_time(cwalk->value);
123 }
124 else if ((strcmp(cwalk->name, "TOTIME") == 0) && cwalk->value && strlen(cwalk->value)) {
125 endtime = eventreport_time(cwalk->value);
126 }
127
128 cwalk = cwalk->next;
129 }
130
131 if (backsecs == 0) {
132 if (getenv("TRENDSECONDS")) backsecs = atoi(getenv("TRENDSECONDS"));
133 else backsecs = 48*60*60;
134 }
135
136 if (!hostname || !service || ((source == SRC_HISTLOGS) && !tstamp) ) {
137 errormsg(403, "Invalid request");
138 return 1;
139 }
140
141 if (strcmp(service, xgetenv("CLIENTCOLUMN")) == 0) {
142 /* Make this a client request */
143 char *p = strdup(basename(hostname));
144 xfree(hostname); hostname = p; /* no need to convert to dots, since we'll already have them */
145 xfree(service); /* service does double-duty as the 'section' param */
146 outform = FRM_CLIENT;
147 }
148
149 if (outform == FRM_STATUS) {
150 char *p, *req;
151 char *hostquoted = htmlquoted(hostname);
152
153 req = getenv("SCRIPT_NAME");
154 SBUF_MALLOC(clienturi, strlen(req) + 10 + strlen(hostquoted));
155 strncpy(clienturi, req, clienturi_buflen);
156 p = strchr(clienturi, '?'); if (p) *p = '\0'; else p = clienturi + strlen(clienturi);
157 snprintf(p, (clienturi_buflen - (clienturi - p)), "?CLIENT=%s", hostquoted);
158 }
159
160 return 0;
161 }
162
loadhostdata(char * hostname,char ** ip,char ** displayname,char ** compacts,int full)163 int loadhostdata(char *hostname, char **ip, char **displayname, char **compacts, int full)
164 {
165 void *hinfo = NULL;
166 int loadres;
167
168 if (full) {
169 loadres = load_hostnames(xgetenv("HOSTSCFG"), NULL, get_fqdn());
170 }
171 else {
172 loadres = load_hostinfo(hostname);
173 }
174
175 if ((loadres != 0) && (loadres != -2)) {
176 errormsg(500, "Cannot load host configuration");
177 return 1;
178 }
179
180 if ((loadres == -2) || (hinfo = hostinfo(hostname)) == NULL) {
181 errormsg(403, "No such host");
182 return 1;
183 }
184
185 *ip = xmh_item(hinfo, XMH_IP);
186 *displayname = xmh_item(hinfo, XMH_DISPLAYNAME);
187 if (!(*displayname)) *displayname = hostname;
188 *compacts = xmh_item(hinfo, XMH_COMPACT);
189
190 return 0;
191 }
192
do_request(void)193 int do_request(void)
194 {
195 int color = 0, flapping = 0;
196 char timesincechange[100];
197 time_t logtime = 0, acktime = 0, disabletime = 0;
198 SBUF_DEFINE(firstline);
199 char *log = NULL, *sender = NULL, *clientid = NULL, *flags = NULL; /* These are free'd */
200 char *restofmsg = NULL, *ackmsg = NULL, *dismsg = NULL, *acklist=NULL, *modifiers = NULL; /* These are just used */
201 int ishtmlformatted = 0;
202 int clientavail = 0;
203 char *ip = NULL, *displayname = NULL, *compacts;
204
205 if (parse_query() != 0) return 1;
206
207 {
208 char *p = NULL;
209 if (!service || !strlen(service)) p = csp_header("svcstatus");
210 else {
211 if (strcasecmp(service, xgetenv("INFOCOLUMN")) == 0) p = csp_header("svcstatus-info");
212 else if (strcasecmp(service, xgetenv("TRENDSCOLUMN")) == 0) p = csp_header("svcstatus-trends");
213 else {
214 int d = atoi(xgetenv("XYMWEBREFRESH"));
215 fprintf(stdout, "Refresh: %d\n", ((d > 0) ? d : 60) );
216 p = csp_header("svcstatus");
217 }
218 }
219 if (p) fprintf(stdout, "%s", p);
220 }
221 /* Load the host data (for access control) */
222 if (accessfn) {
223 load_hostinfo(hostname);
224 load_web_access_config(accessfn);
225 if (!web_access_allowed(getenv("REMOTE_USER"), hostname, service, WEB_ACCESS_VIEW)) {
226 errormsg(403, "Not available (restricted).");
227 return 1;
228 }
229 }
230
231 {
232 char *s;
233
234 s = xgetenv("CLIENTLOGS");
235 if (s) {
236 SBUF_MALLOC(hostdatadir, strlen(s) + strlen(hostname) + 12);
237 snprintf(hostdatadir, hostdatadir_buflen, "%s/%s", s, hostname);
238 }
239 else {
240 s = xgetenv("XYMONVAR");
241 SBUF_MALLOC(hostdatadir, strlen(s) + strlen(hostname) + 12);
242 snprintf(hostdatadir, hostdatadir_buflen, "%s/hostdata/%s", s, hostname);
243 }
244 }
245
246 if (outform == FRM_CLIENT) {
247 if (source == SRC_XYMOND) {
248 SBUF_DEFINE(xymondreq);
249 int xymondresult;
250 sendreturn_t *sres = newsendreturnbuf(1, NULL);
251
252 SBUF_MALLOC(xymondreq, 1024 + strlen(hostname) + (service ? strlen(service) : 0));
253 snprintf(xymondreq, xymondreq_buflen, "clientlog %s", hostname);
254 if (service && *service) snprintf(xymondreq + strlen(xymondreq), (xymondreq_buflen - strlen(xymondreq)), " section=%s", service);
255
256 xymondresult = sendmessage(xymondreq, NULL, XYMON_TIMEOUT, sres);
257 if (xymondresult != XYMONSEND_OK) {
258 SBUF_DEFINE(errtxt);
259
260 SBUF_MALLOC(errtxt, 1024 + MAX_HTMLQUOTE_FACTOR*strlen(xymondreq));
261 snprintf(errtxt, errtxt_buflen, "Status not available: Req=%s, result=%d\n", htmlquoted(xymondreq), xymondresult);
262 errormsg(500, errtxt);
263 return 1;
264 }
265 else {
266 log = getsendreturnstr(sres, 1);
267 }
268 freesendreturnbuf(sres);
269 }
270 else if (source == SRC_HISTLOGS) {
271 char logfn[PATH_MAX];
272 FILE *fd;
273
274 snprintf(logfn, sizeof(logfn), "%s/%s", hostdatadir, tstamp);
275 fd = fopen(logfn, "r");
276 if (fd) {
277 struct stat st;
278 int n;
279
280 fstat(fileno(fd), &st);
281 if (S_ISREG(st.st_mode)) {
282 log = (char *)malloc(st.st_size + 1);
283 n = fread(log, 1, st.st_size, fd);
284 if (n >= 0) *(log+n) = '\0'; else *log = '\0';
285 }
286 fclose(fd);
287 }
288 }
289
290 restofmsg = (log ? log : strdup("<No data>\n"));
291 }
292 else if ((strcmp(service, xgetenv("TRENDSCOLUMN")) == 0) || (strcmp(service, xgetenv("INFOCOLUMN")) == 0)) {
293 int fullload = (strcmp(service, xgetenv("INFOCOLUMN")) == 0);
294
295 if (loadhostdata(hostname, &ip, &displayname, &compacts, fullload) != 0) return 1;
296
297 ishtmlformatted = 1;
298 sethostenv(displayname, ip, service, colorname(COL_GREEN), hostname);
299 sethostenv_refresh(600);
300 color = COL_GREEN;
301 logtime = getcurrenttime(NULL);
302 strncpy(timesincechange, "0 minutes", sizeof(timesincechange));
303
304 if (strcmp(service, xgetenv("TRENDSCOLUMN")) == 0) {
305 if (locatorbased) {
306 char *cgiurl, *qres;
307
308 qres = locator_query(hostname, ST_RRD, &cgiurl);
309 if (!qres) {
310 errprintf("Cannot find RRD files for host %s\n", hostname);
311 }
312 else {
313 /* Redirect browser to the real server */
314 fprintf(stdout, "Location: %s/svcstatus.sh?HOST=%s&SERVICE=%s\n\n",
315 cgiurl, hostname, service);
316 return 0;
317 }
318 }
319 else {
320 if (endtime == 0) endtime = getcurrenttime(NULL);
321
322 if (fromtime == 0) {
323 fromtime = endtime - backsecs;
324 sethostenv_backsecs(backsecs);
325 }
326 else {
327 sethostenv_eventtime(fromtime, endtime);
328 }
329
330 log = restofmsg = generate_trends(hostname, fromtime, endtime);
331 }
332 }
333 else if (strcmp(service, xgetenv("INFOCOLUMN")) == 0) {
334 log = restofmsg = generate_info(hostname, critconfigfn);
335 }
336 }
337 else if (source == SRC_XYMOND) {
338 SBUF_DEFINE(xymondreq);
339 int xymondresult;
340 char *items[25];
341 int icount;
342 time_t logage, clntstamp;
343 char *sumline, *msg, *compitem, *complist;
344 sendreturn_t *sres;
345
346 if (loadhostdata(hostname, &ip, &displayname, &compacts, 0) != 0) return 1;
347
348 complist = NULL;
349 if (compacts && *compacts) {
350 char *p;
351
352 compitem = strtok(compacts, ",");
353 while (compitem && !complist) {
354 p = strchr(compitem, '='); if (p) *p = '\0';
355 if (strcmp(service, compitem) == 0) complist = p+1;
356 compitem = strtok(NULL, ",");
357 }
358 }
359
360 /* We need not check that hostname is valid, has already been done with loadhostdata() */
361 if (!complist) {
362 pcre *dummy = NULL;
363
364 /* Check service as a pcre pattern. And no spaces in servicenames */
365 if (strchr(service, ' ') == NULL) dummy = compileregex(service);
366 if (dummy == NULL) {
367 errormsg(500, "Invalid testname pattern");
368 return 1;
369 }
370
371 freeregex(dummy);
372 SBUF_MALLOC(xymondreq, 1024 + strlen(hostname) + strlen(service));
373 snprintf(xymondreq, xymondreq_buflen, "xymondlog host=%s test=%s fields=hostname,testname,color,flags,lastchange,logtime,validtime,acktime,disabletime,sender,cookie,ackmsg,dismsg,client,acklist,XMH_IP,XMH_DISPLAYNAME,clntstamp,flapinfo,modifiers", hostname, service);
374 }
375 else {
376 pcre *dummy = NULL;
377 SBUF_DEFINE(re);
378
379 SBUF_MALLOC(re, 5 + strlen(complist));
380 snprintf(re, re_buflen, "^(%s)$", complist);
381 dummy = compileregex(re);
382 if (dummy == NULL) {
383 errormsg(500, "Invalid testname pattern");
384 return 1;
385 }
386
387 freeregex(dummy);
388 SBUF_MALLOC(xymondreq, 1024 + strlen(hostname) + strlen(re));
389 snprintf(xymondreq, xymondreq_buflen, "xymondboard host=^%s$ test=%s fields=testname,color,lastchange", hostname, re);
390 }
391
392 sres = newsendreturnbuf(1, NULL);
393 xymondresult = sendmessage(xymondreq, NULL, XYMON_TIMEOUT, sres);
394 if (xymondresult == XYMONSEND_OK) log = getsendreturnstr(sres, 1);
395 freesendreturnbuf(sres);
396 if ((xymondresult != XYMONSEND_OK) || (log == NULL) || (strlen(log) == 0)) {
397 errormsg(404, "Status not available\n");
398 return 1;
399 }
400
401 if (!complist) {
402 char *p;
403
404 sumline = log; p = strchr(log, '\n'); *p = '\0';
405 msg = (p+1); p = strchr(msg, '\n');
406 if (!p) {
407 firstline = strdup(msg);
408 restofmsg = NULL;
409 }
410 else {
411 *p = '\0';
412 firstline = strdup(msg);
413 restofmsg = (p+1);
414 *p = '\n';
415 }
416
417 memset(items, 0, sizeof(items));
418 p = gettok(sumline, "|"); icount = 0;
419 while (p && (icount < 20)) {
420 items[icount++] = p;
421 p = gettok(NULL, "|");
422 }
423
424 /*
425 * hostname, [0]
426 * testname, [1]
427 * color, [2]
428 * flags, [3]
429 * lastchange, [4]
430 * logtime, [5]
431 * validtime, [6]
432 * acktime, [7]
433 * disabletime, [8]
434 * sender, [9]
435 * cookie, [10]
436 * ackmsg, [11]
437 * dismsg, [12]
438 * client, [13]
439 * acklist [14]
440 * XMH_IP [15]
441 * XMH_DISPLAYNAME [16]
442 * clienttstamp [17]
443 * flapping [18]
444 * modifiers [19]
445 */
446 color = parse_color(items[2]);
447 flags = strdup(items[3]);
448 logage = getcurrenttime(NULL) - atoi(items[4]);
449 timesincechange[0] = '\0';
450 p = timesincechange;
451 {
452 int days = (int) (logage / 86400);
453 int hours = (int) ((logage % 86400) / 3600);
454 int minutes = (int) ((logage % 3600) / 60);
455
456 if (days > 1) p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "%d days, ", days);
457 else if (days == 1) p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "1 day, ");
458
459 if (hours == 1) p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "1 hour, ");
460 else p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "%d hours, ", hours);
461
462 if (minutes == 1) p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "1 minute");
463 else p += snprintf(p, (sizeof(timesincechange) - (p - timesincechange)), "%d minutes", minutes);
464 }
465 logtime = atoi(items[5]);
466 if (items[7] && strlen(items[7])) acktime = atoi(items[7]);
467 if (items[8] && strlen(items[8])) disabletime = atoi(items[8]);
468 sender = strdup(items[9]);
469
470 if (items[11] && strlen(items[11])) ackmsg = items[11];
471 if (ackmsg) nldecode(ackmsg);
472
473 if (items[12] && strlen(items[12])) dismsg = items[12];
474 if (dismsg) nldecode(dismsg);
475
476 if (items[13]) clientavail = (*items[13] == 'Y');
477
478 acklist = ((items[14] && *items[14]) ? strdup(items[14]) : NULL);
479
480 ip = (items[15] ? items[15] : "");
481 displayname = ((items[16] && *items[16]) ? items[16] : hostname);
482 clntstamp = ((items[17] && *items[17]) ? atol(items[17]) : 0);
483 flapping = (items[18] ? (*items[18] == '1') : 0);
484 modifiers = (items[19] && *(items[19])) ? items[19] : NULL;
485
486 sethostenv(displayname, ip, service, colorname(COL_GREEN), hostname);
487 sethostenv_refresh(60);
488 }
489 else {
490 /* Compressed status display */
491 strbuffer_t *cmsg;
492 char *row, *p_row, *p_fld;
493 SBUF_DEFINE(nonhistenv);
494
495 color = COL_GREEN;
496
497 cmsg = newstrbuffer(0);
498 addtobuffer(cmsg, "<table width=\"80%\" summary=\"Compacted Status Info\">\n");
499
500 row = strtok_r(log, "\n", &p_row);
501 while (row) {
502 /* testname,color,lastchange */
503 char *testname, *itmcolor, *chgs;
504 time_t lastchange;
505 int icolor;
506
507 testname = strtok_r(row, "|", &p_fld);
508 itmcolor = strtok_r(NULL, "|", &p_fld);
509 chgs = strtok_r(NULL, "|", &p_fld);
510 lastchange = atoi(chgs);
511
512 icolor = parse_color(itmcolor);
513 if (icolor > color) color = icolor;
514
515 addtobuffer(cmsg, "<tr><td align=left>&");
516 addtobuffer(cmsg, itmcolor);
517 addtobuffer(cmsg, " <a href=\"");
518 addtobuffer(cmsg, hostsvcurl(hostname, testname, 1));
519 addtobuffer(cmsg, "\">");
520 addtobuffer(cmsg, htmlquoted(testname));
521 addtobuffer(cmsg, "</a></td></tr>\n");
522
523 row = strtok_r(NULL, "\n", &p_row);
524 }
525
526 addtobuffer(cmsg, "</table>\n");
527 ishtmlformatted = 1;
528
529 sethostenv(displayname, ip, service, colorname(color), hostname);
530 sethostenv_refresh(60);
531 logtime = getcurrenttime(NULL);
532 strncpy(timesincechange, "0 minutes", sizeof(timesincechange));
533
534 log = restofmsg = grabstrbuffer(cmsg);
535
536 SBUF_MALLOC(firstline, 1024);
537 snprintf(firstline, firstline_buflen, "%s Compressed status display\n", colorname(color));
538
539 SBUF_MALLOC(nonhistenv, 10 + strlen(service));
540 snprintf(nonhistenv, nonhistenv_buflen, "NONHISTS=%s", service);
541 putenv(nonhistenv);
542 }
543 }
544 else if (source == SRC_HISTLOGS) {
545 char logfn[PATH_MAX];
546 struct stat st;
547 FILE *fd;
548 /*
549 * Some clients (Unix disk reports) don't have a newline before the
550 * "Status unchanged in ..." text. Most do, but at least Solaris and
551 * AIX do not. So just look for the text, not the newline.
552 */
553 char *statusunchangedtext = "Status unchanged in ";
554 char *receivedfromtext = "Message received from ";
555 char *clientidtext = "Client data ID ";
556 char *p, *unchangedstr, *receivedfromstr, *clientidstr, *hostnamedash;
557 int n;
558
559 if (!tstamp) { errormsg(500, "Invalid request"); return 1; }
560
561 if (loadhostdata(hostname, &ip, &displayname, &compacts, 0) != 0) return 1;
562 hostnamedash = strdup(hostname);
563 p = hostnamedash; while ((p = strchr(p, '.')) != NULL) *p = '_';
564 p = hostnamedash; while ((p = strchr(p, ',')) != NULL) *p = '_';
565 snprintf(logfn, sizeof(logfn), "%s/%s/%s/%s", xgetenv("XYMONHISTLOGS"), hostnamedash, service, tstamp);
566 xfree(hostnamedash);
567 p = tstamp; while ((p = strchr(p, '_')) != NULL) *p = ' ';
568 sethostenv_histlog(tstamp);
569
570 if ((stat(logfn, &st) == -1) || (st.st_size < 10) || (!S_ISREG(st.st_mode))) {
571 errormsg(404, "Historical status log not available\n");
572 return 1;
573 }
574
575 fd = fopen(logfn, "r");
576 if (!fd) {
577 errormsg(404, "Unable to access historical logfile\n");
578 return 1;
579 }
580 log = (char *)malloc(st.st_size+1);
581 n = fread(log, 1, st.st_size, fd);
582 if (n >= 0) *(log+n) = '\0'; else *log = '\0';
583 fclose(fd);
584
585 p = strchr(log, '\n');
586 if (!p) {
587 firstline = strdup(log);
588 restofmsg = NULL;
589 }
590 else {
591 *p = '\0';
592 firstline = strdup(log);
593 restofmsg = (p+1);
594 *p = '\n';
595 }
596
597
598 color = parse_color(log);
599
600 p = strstr(log, "<!-- [flags:");
601 if (p) {
602 p += strlen("<!-- [flags:");
603 n = strspn(p, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
604 flags = (char *)malloc(n+1);
605 strncpy(flags, p, n);
606 *(flags + n) = '\0';
607 }
608
609 timesincechange[0] = '\0';
610
611 p = clientidstr = strstr(restofmsg, clientidtext);
612 if (p) {
613 p += strlen(clientidtext);
614 n = strspn(p, "0123456789");
615 clientid = (char *)malloc(n+1);
616 strncpy(clientid, p, n);
617 *(clientid+n) = '\0';
618 }
619
620 p = unchangedstr = strstr(restofmsg, statusunchangedtext);
621 if (p) {
622 p += strlen(statusunchangedtext);
623 n = strcspn(p, "\n"); if (n >= sizeof(timesincechange)) n = sizeof(timesincechange);
624 strncpy(timesincechange, p, n);
625 timesincechange[n] = '\0';
626 }
627
628 p = receivedfromstr = strstr(restofmsg, receivedfromtext);
629 if (p) {
630 p += strlen(receivedfromtext);
631 n = strspn(p, "0123456789.");
632 sender = (char *)malloc(n+1);
633 strncpy(sender, p, n);
634 *(sender+n) = '\0';
635 }
636
637 /* Kill the "Status unchanged ..." and "Message received ..." lines */
638 if (unchangedstr) *unchangedstr = '\0';
639 if (receivedfromstr) *receivedfromstr = '\0';
640 }
641
642 if (outform == FRM_CLIENT) {
643 fprintf(stdout, "Content-type: text/plain\n\n");
644 fprintf(stdout, "%s", restofmsg);
645 }
646 else {
647 if (clientid && (source == SRC_HISTLOGS)) {
648 if (locatorbased) {
649 char *cgiurl, *qres;
650
651 qres = locator_query(hostname, ST_HOSTDATA, &cgiurl);
652 if (!qres) {
653 errprintf("Cannot find hostdata files for host %s\n", hostname);
654 }
655 else {
656 SBUF_REALLOC(clienturi, 1024 + strlen(cgiurl) + MAX_HTMLQUOTE_FACTOR*strlen(htmlquoted(hostname)) + strlen(clientid));
657 snprintf(clienturi, clienturi_buflen, "%s/svcstatus.sh?CLIENT=%s&TIMEBUF=%s",
658 cgiurl, htmlquoted(hostname), clientid);
659 }
660 }
661 else {
662 char logfn[PATH_MAX];
663 struct stat st;
664
665 snprintf(logfn, sizeof(logfn), "%s/%s", hostdatadir, clientid);
666 clientavail = (stat(logfn, &st) == 0);
667
668 if (clientavail) {
669 int curlen = strlen(clienturi);
670
671 SBUF_REALLOC(clienturi, 1024 + curlen + strlen(clientid));
672 snprintf(clienturi + curlen, (clienturi_buflen - curlen), "&TIMEBUF=%s", clientid);
673 }
674 }
675 }
676
677 fprintf(stdout, "Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE"));
678 generate_html_log(hostname,
679 displayname,
680 service,
681 ip,
682 color, flapping,
683 (sender ? sender : "Xymon"),
684 (flags ? flags : ""),
685 logtime, timesincechange,
686 (firstline ? firstline : ""),
687 (restofmsg ? restofmsg : ""),
688 modifiers,
689 acktime, ackmsg, acklist,
690 disabletime, dismsg,
691 (source == SRC_HISTLOGS),
692 wantserviceid,
693 ishtmlformatted,
694 locatorbased,
695 multigraphs, (clientavail ? clienturi : NULL),
696 nkprio, nkttgroup, nkttextra,
697 backsecs,
698 stdout);
699 }
700
701 /* Cleanup CGI params */
702 if (hostname) xfree(hostname);
703 if (service) xfree(service);
704 if (tstamp) xfree(tstamp);
705
706 /* Cleanup main vars */
707 if (clientid) xfree(clientid);
708 if (sender) xfree(sender);
709 if (flags) xfree(flags);
710 if (firstline) xfree(firstline);
711 if (log) xfree(log);
712
713 return 0;
714 }
715
716
main(int argc,char * argv[])717 int main(int argc, char *argv[])
718 {
719 int argi;
720 char *envarea = NULL;
721
722 multigraphs = ",disk,inode,qtree,quotas,snapshot,TblSpace,if_load,";
723
724 for (argi = 1; (argi < argc); argi++) {
725 if (strcmp(argv[argi], "--historical") == 0) {
726 source = SRC_HISTLOGS;
727 }
728 else if (strncmp(argv[argi], "--history=", 10) == 0) {
729 char *val = strchr(argv[argi], '=')+1;
730
731 if (strcmp(val, "none") == 0)
732 histlocation = HIST_NONE;
733 else if (strcmp(val, "top") == 0)
734 histlocation = HIST_TOP;
735 else if (strcmp(val, "bottom") == 0)
736 histlocation = HIST_BOTTOM;
737 }
738 else if (argnmatch(argv[argi], "--env=")) {
739 char *p = strchr(argv[argi], '=');
740 loadenv(p+1, envarea);
741 }
742 else if (argnmatch(argv[argi], "--area=")) {
743 char *p = strchr(argv[argi], '=');
744 envarea = strdup(p+1);
745 }
746 else if (strcmp(argv[argi], "--no-svcid") == 0) {
747 wantserviceid = 0;
748 }
749 else if (argnmatch(argv[argi], "--templates=")) {
750 char *p = strchr(argv[argi], '=');
751 sethostenv_template(p+1);
752 }
753 else if (argnmatch(argv[argi], "--multigraphs=")) {
754 char *p = strchr(argv[argi], '=');
755 SBUF_MALLOC(multigraphs, strlen(p+1) + 3);
756 snprintf(multigraphs, multigraphs_buflen, ",%s,", p+1);
757 }
758 else if (strcmp(argv[argi], "--no-disable") == 0) {
759 showenadis = 0;
760 }
761 else if (strcmp(argv[argi], "--no-jsvalidation") == 0) {
762 usejsvalidation = 0;
763 }
764 else if (strcmp(argv[argi], "--old-critical-config") == 0) {
765 newcritconfig = 0;
766 }
767 else if (strcmp(argv[argi], "--debug") == 0) {
768 debug = 1;
769 }
770 else if (argnmatch(argv[argi], "--locator=")) {
771 char *p = strchr(argv[argi], '=');
772 locator_init(p+1);
773 locatorbased = 1;
774 }
775 else if (argnmatch(argv[argi], "--critical-config=")) {
776 char *p = strchr(argv[argi], '=');
777 critconfigfn = strdup(p+1);
778 }
779 else if (argnmatch(argv[argi], "--access=")) {
780 char *p = strchr(argv[argi], '=');
781 accessfn = strdup(p+1);
782 }
783 }
784
785 redirect_cgilog("svcstatus");
786
787 *errortxt = '\0';
788 hostname = service = tstamp = NULL;
789 if (do_request() != 0) {
790 fprintf(stdout, "%s", errortxt);
791 return 1;
792 }
793
794 return 0;
795 }
796
797