hostinfo * rpc_manager::lookup_host (const net_address &r) { str key = strbuf () << r.hostname << ":" << r.port << "\n"; hostinfo *h = hosts[key]; if (!h) { if (hosts.size () > max_host_cache) { hostinfo *o = hostlru.first; hostlru.remove (o); hosts.remove (o); remove_host (o); delete (o); } h = New hostinfo (r); h->key = key; hostlru.insert_tail (h); hosts.insert (h); } else { // record recent access hostlru.remove (h); hostlru.insert_tail (h); } assert (h); return h; }
char *check_downtime(char *hostname, char *testname) { namelist_t *hinfo = hostinfo(hostname); char *dtag; if (hinfo == NULL) return NULL; dtag = bbh_item(hinfo, BBH_DOWNTIME); if (dtag && *dtag) { static char *downtag = NULL; static unsigned char *cause = NULL; static int causelen = 0; char *s1, *s2, *s3, *s4, *s5, *p; char timetxt[30]; if (downtag) xfree(downtag); if (cause) xfree(cause); p = downtag = strdup(dtag); do { /* Its either DAYS:START:END or SERVICE:DAYS:START:END:CAUSE */ s1 = p; p += strcspn(p, ":"); if (*p != '\0') { *p = '\0'; p++; } s2 = p; p += strcspn(p, ":"); if (*p != '\0') { *p = '\0'; p++; } s3 = p; p += strcspn(p, ":;,"); if ((*p == ',') || (*p == ';') || (*p == '\0')) { if (*p != '\0') { *p = '\0'; p++; } snprintf(timetxt, sizeof(timetxt), "%s:%s:%s", s1, s2, s3); cause = strdup("Planned downtime"); s1 = "*"; } else if (*p == ':') { *p = '\0'; p++; s4 = p; p += strcspn(p, ":"); if (*p != '\0') { *p = '\0'; p++; } s5 = p; p += strcspn(p, ",;"); if (*p != '\0') { *p = '\0'; p++; } snprintf(timetxt, sizeof(timetxt), "%s:%s:%s", s2, s3, s4); getescapestring(s5, &cause, &causelen); } if (within_sla(timetxt, 0)) { char *onesvc, *buf; if (strcmp(s1, "*") == 0) return cause; onesvc = strtok_r(s1, ",", &buf); while (onesvc) { if (strcmp(onesvc, testname) == 0) return cause; onesvc = strtok_r(NULL, ",", &buf); } } } while (*p); } return NULL; }
void loadhostdata(char *hostname, char **ip, char **displayname) { namelist_t *hinfo = NULL; load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn()); if ((hinfo = hostinfo(hostname)) == NULL) { errormsg("No such host"); exit(1); } *ip = bbh_item(hinfo, BBH_IP); *displayname = bbh_item(hinfo, BBH_DISPLAYNAME); if (!(*displayname)) *displayname = hostname; }
int unwantedcolumn(char *hostname, char *testname) { void *hinfo; char *nc, *tok; int result = 0; hinfo = hostinfo(hostname); if (!hinfo) return 1; nc = bbh_item(hinfo, BBH_NOCOLUMNS); if (!nc) return 0; nc = strdup(nc); tok = strtok(nc, ","); while (tok && (result == 0)) { if (strcmp(tok, testname) == 0) result = 1; tok = strtok(NULL, ","); } return result; }
int main(int argc, char *argv[]) { char *msg; int seq; int argi; int alertcolors, alertinterval; char *configfn = NULL; char *checkfn = NULL; int checkpointinterval = 900; char acklogfn[PATH_MAX]; FILE *acklogfd = NULL; char notiflogfn[PATH_MAX]; FILE *notiflogfd = NULL; char *tracefn = NULL; struct sigaction sa; int configchanged; time_t lastxmit = 0; MEMDEFINE(acklogfn); MEMDEFINE(notiflogfn); libxymon_init(argv[0]); /* Dont save the error buffer */ save_errbuf = 0; /* Load alert config */ alertcolors = colorset(xgetenv("ALERTCOLORS"), ((1 << COL_GREEN) | (1 << COL_BLUE))); alertinterval = 60*atoi(xgetenv("ALERTREPEAT")); /* Create our loookup-trees */ hostnames = xtreeNew(strcasecmp); testnames = xtreeNew(strcasecmp); locations = xtreeNew(strcasecmp); for (argi=1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--config=")) { configfn = strdup(strchr(argv[argi], '=')+1); } else if (argnmatch(argv[argi], "--checkpoint-file=")) { checkfn = strdup(strchr(argv[argi], '=')+1); } else if (argnmatch(argv[argi], "--checkpoint-interval=")) { char *p = strchr(argv[argi], '=') + 1; checkpointinterval = atoi(p); } else if (argnmatch(argv[argi], "--dump-config")) { load_alertconfig(configfn, alertcolors, alertinterval); dump_alertconfig(1); return 0; } else if (argnmatch(argv[argi], "--cfid")) { include_configid = 1; } else if (argnmatch(argv[argi], "--test")) { char *testhost = NULL, *testservice = NULL, *testpage = NULL, *testcolor = "red", *testgroups = NULL; void *hinfo; int testdur = 0; FILE *logfd = NULL; activealerts_t *awalk = NULL; int paramno = 0; argi++; if (argi < argc) testhost = argv[argi]; argi++; if (argi < argc) testservice = argv[argi]; argi++; while (argi < argc) { if (strncasecmp(argv[argi], "--duration=", 11) == 0) { testdur = durationvalue(strchr(argv[argi], '=')+1); } else if (strncasecmp(argv[argi], "--color=", 8) == 0) { testcolor = strchr(argv[argi], '=')+1; } else if (strncasecmp(argv[argi], "--group=", 8) == 0) { testgroups = strchr(argv[argi], '=')+1; } else if (strncasecmp(argv[argi], "--time=", 7) == 0) { fakestarttime = (time_t)atoi(strchr(argv[argi], '=')+1); } else { paramno++; if (paramno == 1) testdur = atoi(argv[argi]); else if (paramno == 2) testcolor = argv[argi]; else if (paramno == 3) fakestarttime = (time_t) atoi(argv[argi]); } argi++; } if ((testhost == NULL) || (testservice == NULL)) { printf("Usage: xymond_alert --test HOST SERVICE [options]\n"); printf("Possible options:\n\t[--duration=MINUTES]\n\t[--color=COLOR]\n\t[--group=GROUPNAME]\n\t[--time=TIMESPEC]\n"); return 1; } load_hostnames(xgetenv("HOSTSCFG"), NULL, get_fqdn()); hinfo = hostinfo(testhost); if (hinfo) { testpage = strdup(xmh_item(hinfo, XMH_ALLPAGEPATHS)); } else { errprintf("Host not found in hosts.cfg - assuming it is on the top page\n"); testpage = ""; } awalk = (activealerts_t *)calloc(1, sizeof(activealerts_t)); awalk->hostname = find_name(hostnames, testhost); awalk->testname = find_name(testnames, testservice); awalk->location = find_name(locations, testpage); awalk->ip = strdup("127.0.0.1"); awalk->color = awalk->maxcolor = parse_color(testcolor); awalk->pagemessage = "Test of the alert configuration"; awalk->eventstart = getcurrenttime(NULL) - testdur*60; awalk->groups = (testgroups ? strdup(testgroups) : NULL); awalk->state = A_PAGING; awalk->cookie = 12345; awalk->next = NULL; logfd = fopen("/dev/null", "w"); starttrace(NULL); testonly = 1; load_alertconfig(configfn, alertcolors, alertinterval); load_holidays(0); send_alert(awalk, logfd); return 0; } else if (argnmatch(argv[argi], "--trace=")) { tracefn = strdup(strchr(argv[argi], '=')+1); starttrace(tracefn); } else if (net_worker_option(argv[argi])) { /* Handled in the subroutine */ } else if (standardoption(argv[argi])) { if (showhelp) return 0; } else { errprintf("Unknown option '%s'\n", argv[argi]); } } /* Do the network stuff if needed */ net_worker_run(ST_ALERT, LOC_SINGLESERVER, NULL); if (checkfn) { load_checkpoint(checkfn); nextcheckpoint = gettimer() + checkpointinterval; dbgprintf("Next checkpoint at %d, interval %d\n", (int) nextcheckpoint, checkpointinterval); } setup_signalhandler("xymond_alert"); /* Need to handle these ourselves, so we can shutdown and save state-info */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = sig_handler; sigaction(SIGPIPE, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGCHLD, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); sigaction(SIGHUP, &sa, NULL); if (xgetenv("XYMONSERVERLOGS")) { sprintf(acklogfn, "%s/acknowledge.log", xgetenv("XYMONSERVERLOGS")); acklogfd = fopen(acklogfn, "a"); sprintf(notiflogfn, "%s/notifications.log", xgetenv("XYMONSERVERLOGS")); notiflogfd = fopen(notiflogfn, "a"); } /* * The general idea here is that this loop handles receiving of alert- * and ack-messages from the master daemon, and maintains a list of * host+test combinations that may have alerts going out. * * This module does not deal with any specific alert-configuration, * it just picks up the alert messages, maintains the list of * known tests that are in some sort of critical condition, and * periodically pushes alerts to the do_alert.c module for handling. * * The only modification of alerts that happen here is the handling * of when the next alert is due. It calls into the next_alert() * routine to learn when an alert should be repeated, and also * deals with Acknowledgments that stop alerts from going out for * a period of time. */ while (running) { char *eoln, *restofmsg; char *metadata[20]; char *p; int metacount; char *hostname = NULL, *testname = NULL; struct timespec timeout; time_t now, nowtimer; int anytogo; activealerts_t *awalk; int childstat; nowtimer = gettimer(); if (checkfn && (nowtimer > nextcheckpoint)) { dbgprintf("Saving checkpoint\n"); nextcheckpoint = nowtimer + checkpointinterval; save_checkpoint(checkfn); if (acklogfd) acklogfd = freopen(acklogfn, "a", acklogfd); if (notiflogfd) notiflogfd = freopen(notiflogfn, "a", notiflogfd); } timeout.tv_sec = 60; timeout.tv_nsec = 0; msg = get_xymond_message(C_PAGE, "xymond_alert", &seq, &timeout); if (msg == NULL) { running = 0; continue; } /* See what time it is - must happen AFTER the timeout */ now = getcurrenttime(NULL); /* Split the message in the first line (with meta-data), and the rest */ eoln = strchr(msg, '\n'); if (eoln) { *eoln = '\0'; restofmsg = eoln+1; } else { restofmsg = ""; } /* * Now parse the meta-data into elements. * We use our own "gettok()" routine which works * like strtok(), but can handle empty elements. */ metacount = 0; memset(&metadata, 0, sizeof(metadata)); p = gettok(msg, "|"); while (p && (metacount < 19)) { metadata[metacount] = p; metacount++; p = gettok(NULL, "|"); } metadata[metacount] = NULL; if (metacount > 3) hostname = metadata[3]; if (metacount > 4) testname = metadata[4]; if ((metacount > 10) && (strncmp(metadata[0], "@@page", 6) == 0)) { /* @@page|timestamp|sender|hostname|testname|hostip|expiretime|color|prevcolor|changetime|location|cookie|osname|classname|grouplist|modifiers */ int newcolor, newalertstatus, oldalertstatus; dbgprintf("Got page message from %s:%s\n", hostname, testname); traceprintf("@@page %s:%s:%s=%s\n", hostname, testname, metadata[10], metadata[7]); awalk = find_active(hostname, testname); if (awalk == NULL) { char *hwalk = find_name(hostnames, hostname); char *twalk = find_name(testnames, testname); char *pwalk = find_name(locations, metadata[10]); awalk = (activealerts_t *)calloc(1, sizeof(activealerts_t)); awalk->hostname = hwalk; awalk->testname = twalk; awalk->location = pwalk; awalk->cookie = -1; awalk->state = A_DEAD; /* * Use changetime here, if we restart the alert module then * this gets the duration values more right than using "now". * Also, define this only when a new alert arrives - we should * NOT clear this when a status goes yellow->red, or if it * flaps between yellow and red. */ awalk->eventstart = atoi(metadata[9]); add_active(awalk->hostname, awalk); traceprintf("New record\n"); } newcolor = parse_color(metadata[7]); oldalertstatus = ((alertcolors & (1 << awalk->color)) != 0); newalertstatus = ((alertcolors & (1 << newcolor)) != 0); traceprintf("state %d->%d\n", oldalertstatus, newalertstatus); if (newalertstatus) { /* It's in an alert state. */ awalk->color = newcolor; awalk->state = A_PAGING; if (newcolor > awalk->maxcolor) { if (awalk->maxcolor != 0) { /* * Severity has increased (yellow -> red). * Clear the repeat-interval, and set maxcolor to * the new color. If it drops to yellow again, * maxcolor stays at red, so a test that flaps * between yellow and red will only alert on red * the first time, and then follow the repeat * interval. */ dbgprintf("Severity increased, cleared repeat interval: %s/%s %s->%s\n", awalk->hostname, awalk->testname, colorname(awalk->maxcolor), colorname(newcolor)); clear_interval(awalk); } awalk->maxcolor = newcolor; } } else { /* * Send one "recovered" message out now, then go to A_DEAD. * Dont update the color here - we want recoveries to go out * only if the alert color triggered an alert */ awalk->state = (newcolor == COL_BLUE) ? A_DISABLED : A_RECOVERED; } if (oldalertstatus != newalertstatus) { dbgprintf("Alert status changed from %d to %d\n", oldalertstatus, newalertstatus); clear_interval(awalk); } if (awalk->ip) xfree(awalk->ip); awalk->ip = strdup(metadata[5]); awalk->cookie = atoi(metadata[11]); if (awalk->osname) xfree(awalk->osname); awalk->osname = (metadata[12] ? strdup(metadata[12]) : NULL); if (awalk->classname) xfree(awalk->classname); awalk->classname = (metadata[13] ? strdup(metadata[13]) : NULL); if (awalk->groups) xfree(awalk->groups); awalk->groups = (metadata[14] ? strdup(metadata[14]) : NULL); if (awalk->pagemessage) xfree(awalk->pagemessage); if (metadata[15]) { /* Modifiers are more interesting than the message itself */ awalk->pagemessage = (char *)malloc(strlen(awalk->hostname) + strlen(awalk->testname) + strlen(colorname(awalk->color)) + strlen(metadata[15]) + strlen(restofmsg) + 10); sprintf(awalk->pagemessage, "%s:%s %s\n%s\n%s", awalk->hostname, awalk->testname, colorname(awalk->color), metadata[15], restofmsg); } else { awalk->pagemessage = strdup(restofmsg); } } else if ((metacount > 5) && (strncmp(metadata[0], "@@ack", 5) == 0)) { /* @@ack|timestamp|sender|hostname|testname|hostip|expiretime */ /* * An ack is handled simply by setting the next * alert-time to when the ack expires. */ time_t nextalert = atoi(metadata[6]); dbgprintf("Got ack message from %s:%s\n", hostname, testname); traceprintf("@@ack: %s:%s now=%d, ackeduntil %d\n", hostname, testname, (int)now, (int)nextalert); awalk = find_active(hostname, testname); if (acklogfd) { int cookie = (awalk ? awalk->cookie : -1); int color = (awalk ? awalk->color : 0); fprintf(acklogfd, "%d\t%d\t%d\t%d\t%s\t%s.%s\t%s\t%s\n", (int)now, cookie, (int)((nextalert - now) / 60), cookie, "np_filename_not_used", hostname, testname, colorname(color), nlencode(restofmsg)); fflush(acklogfd); } if (awalk && (awalk->state == A_PAGING)) { traceprintf("Record updated\n"); awalk->state = A_ACKED; awalk->nextalerttime = nextalert; if (awalk->ackmessage) xfree(awalk->ackmessage); awalk->ackmessage = strdup(restofmsg); } else { traceprintf("No record\n"); } } else if ((metacount > 4) && (strncmp(metadata[0], "@@notify", 5) == 0)) { /* @@notify|timestamp|sender|hostname|testname|pagepath */ char *hwalk = find_name(hostnames, hostname); char *twalk = find_name(testnames, testname); char *pwalk = find_name(locations, (metadata[5] ? metadata[5] : "")); awalk = (activealerts_t *)calloc(1, sizeof(activealerts_t)); awalk->hostname = hwalk; awalk->testname = twalk; awalk->location = pwalk; awalk->cookie = -1; awalk->pagemessage = strdup(restofmsg); awalk->eventstart = getcurrenttime(NULL); awalk->state = A_NOTIFY; add_active(awalk->hostname, awalk); } else if ((metacount > 3) && ((strncmp(metadata[0], "@@drophost", 10) == 0) || (strncmp(metadata[0], "@@dropstate", 11) == 0))) { /* @@drophost|timestamp|sender|hostname */ /* @@dropstate|timestamp|sender|hostname */ xtreePos_t handle; handle = xtreeFind(hostnames, hostname); if (handle != xtreeEnd(hostnames)) { alertanchor_t *anchor = (alertanchor_t *)xtreeData(hostnames, handle); for (awalk = anchor->head; (awalk); awalk = awalk->next) awalk->state = A_DEAD; } } else if ((metacount > 4) && (strncmp(metadata[0], "@@droptest", 10) == 0)) { /* @@droptest|timestamp|sender|hostname|testname */ awalk = find_active(hostname, testname); if (awalk) awalk->state = A_DEAD; } else if ((metacount > 4) && (strncmp(metadata[0], "@@renamehost", 12) == 0)) { /* @@renamehost|timestamp|sender|hostname|newhostname */ /* * We handle rename's simply by dropping the alert. If there is still an * active alert for the host, it will have to be dealt with when the next * status update arrives. */ xtreePos_t handle; handle = xtreeFind(hostnames, hostname); if (handle != xtreeEnd(hostnames)) { alertanchor_t *anchor = (alertanchor_t *)xtreeData(hostnames, handle); for (awalk = anchor->head; (awalk); awalk = awalk->next) awalk->state = A_DEAD; } } else if ((metacount > 5) && (strncmp(metadata[0], "@@renametest", 12) == 0)) { /* @@renametest|timestamp|sender|hostname|oldtestname|newtestname */ /* * We handle rename's simply by dropping the alert. If there is still an * active alert for the host, it will have to be dealt with when the next * status update arrives. */ awalk = find_active(hostname, testname); if (awalk) awalk->state = A_DEAD; } else if (strncmp(metadata[0], "@@shutdown", 10) == 0) { running = 0; errprintf("Got a shutdown message\n"); continue; } else if (strncmp(metadata[0], "@@logrotate", 11) == 0) { char *fn = xgetenv("XYMONCHANNEL_LOGFILENAME"); if (fn && strlen(fn)) { reopen_file(fn, "a", stdout); reopen_file(fn, "a", stderr); if (tracefn) { stoptrace(); starttrace(tracefn); } } continue; } else if (strncmp(metadata[0], "@@reload", 8) == 0) { /* Nothing ... right now */ } else if (strncmp(metadata[0], "@@idle", 6) == 0) { /* Timeout */ } /* * When a burst of alerts happen, we get lots of alert messages * coming in quickly. So lets handle them in bunches and only * do the full alert handling once every 10 secs - that lets us * combine a bunch of alerts into one transmission process. */ if (nowtimer < (lastxmit+10)) continue; lastxmit = nowtimer; /* * Loop through the activealerts list and see if anything is pending. * This is an optimization, we could just as well just fork off the * notification child and let it handle all of it. But there is no * reason to fork a child process unless it is going to do something. */ configchanged = load_alertconfig(configfn, alertcolors, alertinterval); configchanged += load_holidays(0); anytogo = 0; for (awalk = alistBegin(); (awalk); awalk = alistNext()) { int anymatch = 0; switch (awalk->state) { case A_NORECIP: if (!configchanged) break; /* The configuration has changed - switch NORECIP -> PAGING */ awalk->state = A_PAGING; clear_interval(awalk); /* Fall through */ case A_PAGING: if (have_recipient(awalk, &anymatch)) { if (awalk->nextalerttime <= now) anytogo++; } else { if (!anymatch) { awalk->state = A_NORECIP; cleanup_alert(awalk); } } break; case A_ACKED: if (awalk->nextalerttime <= now) { /* An ack has expired, so drop the ack message and switch to A_PAGING */ anytogo++; if (awalk->ackmessage) xfree(awalk->ackmessage); awalk->state = A_PAGING; } break; case A_RECOVERED: case A_DISABLED: case A_NOTIFY: anytogo++; break; case A_DEAD: break; } } dbgprintf("%d alerts to go\n", anytogo); if (anytogo) { pid_t childpid; childpid = fork(); if (childpid == 0) { /* The child */ start_alerts(); for (awalk = alistBegin(); (awalk); awalk = alistNext()) { switch (awalk->state) { case A_PAGING: if (awalk->nextalerttime <= now) { send_alert(awalk, notiflogfd); } break; case A_ACKED: /* Cannot be A_ACKED unless the ack is still valid, so no alert. */ break; case A_RECOVERED: case A_DISABLED: case A_NOTIFY: send_alert(awalk, notiflogfd); break; case A_NORECIP: case A_DEAD: break; } } finish_alerts(); /* Child does not continue */ exit(0); } else if (childpid < 0) { errprintf("Fork failed, cannot send alerts: %s\n", strerror(errno)); } } /* Update the state flag and the next-alert timestamp */ for (awalk = alistBegin(); (awalk); awalk = alistNext()) { switch (awalk->state) { case A_PAGING: if (awalk->nextalerttime <= now) awalk->nextalerttime = next_alert(awalk); break; case A_NORECIP: break; case A_ACKED: /* Still cannot get here except if ack is still valid */ break; case A_RECOVERED: case A_DISABLED: case A_NOTIFY: awalk->state = A_DEAD; /* Fall through */ case A_DEAD: cleanup_alert(awalk); break; } } clean_all_active(); /* Pickup any finished child processes to avoid zombies */ while (wait3(&childstat, WNOHANG, NULL) > 0) ; } if (checkfn) save_checkpoint(checkfn); if (acklogfd) fclose(acklogfd); if (notiflogfd) fclose(notiflogfd); stoptrace(); MEMUNDEFINE(notiflogfn); MEMUNDEFINE(acklogfn); if (termsig >= 0) { errprintf("Terminated by signal %d\n", termsig); } return 0; }
void do_notifylog(FILE *output, int maxcount, int maxminutes, char *fromtime, char *totime, char *pageregex, char *expageregex, char *hostregex, char *exhostregex, char *testregex, char *extestregex, char *rcptregex, char *exrcptregex) { FILE *notifylog; char notifylogfilename[PATH_MAX]; time_t firstevent = 0; time_t lastevent = getcurrenttime(NULL); notification_t *head, *walk; struct stat st; char l[MAX_LINE_LEN]; char title[200]; /* For the PCRE matching */ const char *errmsg = NULL; int errofs = 0; pcre *pageregexp = NULL; pcre *expageregexp = NULL; pcre *hostregexp = NULL; pcre *exhostregexp = NULL; pcre *testregexp = NULL; pcre *extestregexp = NULL; pcre *rcptregexp = NULL; pcre *exrcptregexp = NULL; if (maxminutes && (fromtime || totime)) { fprintf(output, "<B>Only one time interval type is allowed!</B>"); return; } if (fromtime) { firstevent = convert_time(fromtime); if(firstevent < 0) { fprintf(output,"<B>Invalid 'from' time: %s</B>", htmlquoted(fromtime)); return; } } else if (maxminutes) { firstevent = getcurrenttime(NULL) - maxminutes*60; } else { firstevent = getcurrenttime(NULL) - 86400; } if (totime) { lastevent = convert_time(totime); if (lastevent < 0) { fprintf(output,"<B>Invalid 'to' time: %s</B>", htmlquoted(totime)); return; } if (lastevent < firstevent) { fprintf(output,"<B>'to' time must be after 'from' time.</B>"); return; } } if (!maxcount) maxcount = 100; if (pageregex && *pageregex) pageregexp = pcre_compile(pageregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (expageregex && *expageregex) expageregexp = pcre_compile(expageregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (hostregex && *hostregex) hostregexp = pcre_compile(hostregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (exhostregex && *exhostregex) exhostregexp = pcre_compile(exhostregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (testregex && *testregex) testregexp = pcre_compile(testregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (extestregex && *extestregex) extestregexp = pcre_compile(extestregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (rcptregex && *rcptregex) rcptregexp = pcre_compile(rcptregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (exrcptregex && *exrcptregex) exrcptregexp = pcre_compile(exrcptregex, PCRE_CASELESS, &errmsg, &errofs, NULL); sprintf(notifylogfilename, "%s/notifications.log", xgetenv("XYMONSERVERLOGS")); notifylog = fopen(notifylogfilename, "r"); if (notifylog && (stat(notifylogfilename, &st) == 0)) { time_t curtime; int done = 0; /* Find a spot in the notification log file close to where the firstevent time is */ fseeko(notifylog, 0, SEEK_END); do { /* Go back maxcount*80 bytes - one entry is ~80 bytes */ if (ftello(notifylog) > maxcount*80) { unsigned int uicurtime; fseeko(notifylog, -maxcount*80, SEEK_CUR); if (fgets(l, sizeof(l), notifylog) && /* Skip to start of line */ fgets(l, sizeof(l), notifylog)) { /* Sun Jan 7 10:29:08 2007 myhost.disk (130.225.226.90) [email protected] 1168162147 100 */ sscanf(l, "%*s %*s %*u %*u:%*u:%*u %*u %*s %*s %*s %u %*d", &uicurtime); curtime = uicurtime; done = (curtime < firstevent); } else { fprintf(output, "Error reading logfile %s: %s\n", notifylogfilename, strerror(errno)); return; } } else { rewind(notifylog); done = 1; } } while (!done); } head = NULL; while (notifylog && (fgets(l, sizeof(l), notifylog))) { unsigned int etim; time_t eventtime; char hostsvc[MAX_LINE_LEN]; char recipient[MAX_LINE_LEN]; char *hostname, *svcname, *p; int itemsfound, pagematch, hostmatch, testmatch, rcptmatch; notification_t *newrec; void *eventhost; struct htnames_t *eventcolumn; int ovector[30]; itemsfound = sscanf(l, "%*s %*s %*u %*u:%*u:%*u %*u %s %*s %s %u %*d", hostsvc, recipient, &etim); eventtime = etim; if (itemsfound != 3) continue; if (eventtime < firstevent) continue; if (eventtime > lastevent) break; hostname = hostsvc; svcname = strrchr(hostsvc, '.'); if (svcname) { *svcname = '\0'; svcname++; } else svcname = ""; eventhost = hostinfo(hostname); if (!eventhost) continue; /* Dont report hosts that no longer exist */ eventcolumn = getname(svcname, 1); p = strchr(recipient, '['); if (p) *p = '\0'; if (pageregexp) { char *pagename; pagename = xmh_item_multi(eventhost, XMH_PAGEPATH); pagematch = 0; while (!pagematch && pagename) { pagematch = (pcre_exec(pageregexp, NULL, pagename, strlen(pagename), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); pagename = xmh_item_multi(NULL, XMH_PAGEPATH); } } else pagematch = 1; if (!pagematch) continue; if (expageregexp) { char *pagename; pagename = xmh_item_multi(eventhost, XMH_PAGEPATH); pagematch = 0; while (!pagematch && pagename) { pagematch = (pcre_exec(expageregexp, NULL, pagename, strlen(pagename), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); pagename = xmh_item_multi(NULL, XMH_PAGEPATH); } } else pagematch = 0; if (pagematch) continue; if (hostregexp) hostmatch = (pcre_exec(hostregexp, NULL, hostname, strlen(hostname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else hostmatch = 1; if (!hostmatch) continue; if (exhostregexp) hostmatch = (pcre_exec(exhostregexp, NULL, hostname, strlen(hostname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else hostmatch = 0; if (hostmatch) continue; if (testregexp) testmatch = (pcre_exec(testregexp, NULL, svcname, strlen(svcname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else testmatch = 1; if (!testmatch) continue; if (extestregexp) testmatch = (pcre_exec(extestregexp, NULL, svcname, strlen(svcname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else testmatch = 0; if (testmatch) continue; if (rcptregexp) rcptmatch = (pcre_exec(rcptregexp, NULL, recipient, strlen(recipient), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else rcptmatch = 1; if (!rcptmatch) continue; if (exrcptregexp) rcptmatch = (pcre_exec(exrcptregexp, NULL, recipient, strlen(recipient), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else rcptmatch = 0; if (rcptmatch) continue; newrec = (notification_t *) malloc(sizeof(notification_t)); newrec->host = eventhost; newrec->service = eventcolumn; newrec->eventtime = eventtime; newrec->recipient = strdup(recipient); newrec->next = head; head = newrec; } if (head) { char *bgcolors[2] = { "#000000", "#000066" }; int bgcolor = 0; int count; struct notification_t *lasttoshow = head; count=0; walk=head; do { count++; lasttoshow = walk; walk = walk->next; } while (walk && (count<maxcount)); if (maxminutes) { sprintf(title, "%d notifications in the past %u minutes", count, (unsigned int)((getcurrenttime(NULL) - lasttoshow->eventtime) / 60)); } else { sprintf(title, "%d notifications sent.", count); } fprintf(output, "<BR><BR>\n"); fprintf(output, "<TABLE SUMMARY=\"Notification log\" BORDER=0>\n"); fprintf(output, "<TR BGCOLOR=\"#333333\">\n"); fprintf(output, "<TD ALIGN=CENTER COLSPAN=4><FONT SIZE=-1 COLOR=\"#33ebf4\">%s</FONT></TD></TR>\n", htmlquoted(title)); fprintf(output, "<TR BGCOLOR=\"#333333\"><TH>Time</TH><TH>Host</TH><TH>Service</TH><TH>Recipient</TH></TR>\n"); for (walk=head; (walk != lasttoshow->next); walk=walk->next) { char *hostname = xmh_item(walk->host, XMH_HOSTNAME); fprintf(output, "<TR BGCOLOR=%s>\n", bgcolors[bgcolor]); bgcolor = ((bgcolor + 1) % 2); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", ctime(&walk->eventtime)); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", hostname); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", walk->service->name); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", walk->recipient); } fprintf(output, "</TABLE>\n"); /* Clean up */ walk = head; do { struct notification_t *tmp = walk; walk = walk->next; xfree(tmp->recipient); xfree(tmp); } while (walk); } else { /* No notifications during the past maxminutes */ if (notifylog) sprintf(title, "No notifications sent in the last %d minutes", maxminutes); else strcpy(title, "No notifications logged"); fprintf(output, "<CENTER><BR>\n"); fprintf(output, "<TABLE SUMMARY=\"%s\" BORDER=0>\n", title); fprintf(output, "<TR BGCOLOR=\"#333333\">\n"); fprintf(output, "<TD ALIGN=CENTER COLSPAN=6><FONT SIZE=-1 COLOR=\"#33ebf4\">%s</FONT></TD>\n", htmlquoted(title)); fprintf(output, "</TR>\n"); fprintf(output, "</TABLE>\n"); fprintf(output, "</CENTER>\n"); } if (notifylog) fclose(notifylog); if (pageregexp) pcre_free(pageregexp); if (expageregexp) pcre_free(expageregexp); if (hostregexp) pcre_free(hostregexp); if (exhostregexp) pcre_free(exhostregexp); if (testregexp) pcre_free(testregexp); if (extestregexp) pcre_free(extestregexp); if (rcptregexp) pcre_free(rcptregexp); if (exrcptregexp) pcre_free(exrcptregexp); }
xymongen_page_t *load_layout(char *pgset) { char pagetag[100], subpagetag[100], subparenttag[100], vpagetag[100], vsubpagetag[100], vsubparenttag[100], grouptag[100], summarytag[100], titletag[100], hosttag[100]; char *name, *link, *onlycols, *exceptcols; char hostname[MAX_LINE_LEN]; xymongen_page_t *toppage, *curpage, *cursubpage, *cursubparent; group_t *curgroup; host_t *curhost; char *curtitle; int ip1, ip2, ip3, ip4; char *p; int fqdn = get_fqdn(); char *cfgdata, *inbol, *ineol, insavchar = '\0'; if (loadhostsfromxymond) { if (load_hostnames("@", NULL, fqdn) != 0) { errprintf("Cannot load host configuration from xymond\n"); return NULL; } } else { if (load_hostnames(xgetenv("HOSTSCFG"), "dispinclude", fqdn) != 0) { errprintf("Cannot load host configuration from %s\n", xgetenv("HOSTSCFG")); return NULL; } } if (first_host() == NULL) { errprintf("Empty configuration from %s\n", (loadhostsfromxymond ? "xymond" : xgetenv("HOSTSCFG"))); return NULL; } dbgprintf("load_layout(pgset=%s)\n", textornull(pgset)); /* * load_hostnames() picks up the hostname definitions, but not the page * layout. So we will scan the file again, this time doing the layout. */ if (pgset == NULL) pgset = ""; sprintf(pagetag, "%spage", pgset); sprintf(subpagetag, "%ssubpage", pgset); sprintf(subparenttag, "%ssubparent", pgset); sprintf(vpagetag, "v%spage", pgset); sprintf(vsubpagetag, "v%ssubpage", pgset); sprintf(vsubparenttag, "v%ssubparent", pgset); sprintf(grouptag, "%sgroup", pgset); sprintf(summarytag, "%ssummary", pgset); sprintf(titletag, "%stitle", pgset); sprintf(hosttag, "%s:", pgset); for (p=hosttag; (*p); p++) *p = toupper((int)*p); toppage = init_page("", "", 0); addtopagelist(toppage); curpage = NULL; cursubpage = NULL; curgroup = NULL; curhost = NULL; cursubparent = NULL; curtitle = NULL; inbol = cfgdata = hostscfg_content(); while (inbol && *inbol) { inbol += strspn(inbol, " \t"); ineol = strchr(inbol, '\n'); if (ineol) { while ((ineol > inbol) && (isspace(*ineol) || (*ineol == '\n'))) ineol--; if (*ineol != '\n') ineol++; insavchar = *ineol; *ineol = '\0'; } dbgprintf("load_layout: -- got line '%s'\n", inbol); if ((strncmp(inbol, pagetag, strlen(pagetag)) == 0) || (strncmp(inbol, vpagetag, strlen(vpagetag)) == 0)) { getnamelink(inbol, &name, &link); if (curpage == NULL) { /* First page - hook it on toppage as a subpage from there */ curpage = toppage->subpages = init_page(name, link, (strncmp(inbol, vpagetag, strlen(vpagetag)) == 0)); } else { curpage = curpage->next = init_page(name, link, (strncmp(inbol, vpagetag, strlen(vpagetag)) == 0)); } curpage->parent = toppage; if (curtitle) { curpage->pretitle = curtitle; curtitle = NULL; } cursubpage = NULL; cursubparent = NULL; curgroup = NULL; curhost = NULL; addtopagelist(curpage); } else if ( (strncmp(inbol, subpagetag, strlen(subpagetag)) == 0) || (strncmp(inbol, vsubpagetag, strlen(vsubpagetag)) == 0) ) { if (curpage == NULL) { errprintf("'subpage' ignored, no preceding 'page' tag : %s\n", inbol); goto nextline; } getnamelink(inbol, &name, &link); if (cursubpage == NULL) { cursubpage = curpage->subpages = init_page(name, link, (strncmp(inbol, vsubpagetag, strlen(vsubpagetag)) == 0)); } else { cursubpage = cursubpage->next = init_page(name, link, (strncmp(inbol, vsubpagetag, strlen(vsubpagetag)) == 0)); } cursubpage->parent = curpage; if (curtitle) { cursubpage->pretitle = curtitle; curtitle = NULL; } cursubparent = NULL; curgroup = NULL; curhost = NULL; addtopagelist(cursubpage); } else if ( (strncmp(inbol, subparenttag, strlen(subparenttag)) == 0) || (strncmp(inbol, vsubparenttag, strlen(vsubparenttag)) == 0) ) { xymongen_page_t *parentpage, *walk; getparentnamelink(inbol, toppage, &parentpage, &name, &link); if (parentpage == NULL) { errprintf("'subparent' ignored, unknown parent page: %s\n", inbol); goto nextline; } cursubparent = init_page(name, link, (strncmp(inbol, vsubparenttag, strlen(vsubparenttag)) == 0)); if (parentpage->subpages == NULL) { parentpage->subpages = cursubparent; } else { for (walk = parentpage->subpages; (walk->next); (walk = walk->next)) ; walk->next = cursubparent; } if (curtitle) { cursubparent->pretitle = curtitle; curtitle = NULL; } cursubparent->parent = parentpage; curgroup = NULL; curhost = NULL; addtopagelist(cursubparent); } else if (strncmp(inbol, grouptag, strlen(grouptag)) == 0) { int sorthosts = (strstr(inbol, "group-sorted") != NULL); getgrouptitle(inbol, pgset, &link, &onlycols, &exceptcols); if (curgroup == NULL) { curgroup = init_group(link, onlycols, exceptcols, sorthosts); if (cursubparent != NULL) { cursubparent->groups = curgroup; } else if (cursubpage != NULL) { /* We're in a subpage */ cursubpage->groups = curgroup; } else if (curpage != NULL) { /* We're on a main page */ curpage->groups = curgroup; } else { /* We're on the top page */ toppage->groups = curgroup; } } else { curgroup->next = init_group(link, onlycols, exceptcols, sorthosts); curgroup = curgroup->next; } if (curtitle) { curgroup->pretitle = curtitle; curtitle = NULL; } curhost = NULL; } else if (sscanf(inbol, "%3d.%3d.%3d.%3d %s", &ip1, &ip2, &ip3, &ip4, hostname) == 5) { void *xymonhost = NULL; int dialup, nonongreen, crittime = 1; double warnpct = reportwarnlevel; int warnstops = reportwarnstops; char *displayname, *clientalias, *comment, *description; char *alertlist, *onwaplist, *reporttime; char *nopropyellowlist, *nopropredlist, *noproppurplelist, *nopropacklist; char *targetpagelist[MAX_TARGETPAGES_PER_HOST]; int targetpagecount; char *hval; /* Check for ".default." hosts - they are ignored. */ if (*hostname == '.') goto nextline; if (!fqdn) { /* Strip any domain from the hostname */ char *p = strchr(hostname, '.'); if (p) *p = '\0'; } /* Get the info */ xymonhost = hostinfo(hostname); if (xymonhost == NULL) { errprintf("Confused - hostname '%s' cannot be found. Ignored\n", hostname); goto nextline; } /* Check for no-display hosts - they are ignored. */ /* But only when we're building the default pageset */ if ((strlen(pgset) == 0) && (xmh_item(xymonhost, XMH_FLAG_NODISP) != NULL)) goto nextline; for (targetpagecount=0; (targetpagecount < MAX_TARGETPAGES_PER_HOST); targetpagecount++) targetpagelist[targetpagecount] = NULL; targetpagecount = 0; dialup = (xmh_item(xymonhost, XMH_FLAG_DIALUP) != NULL); nonongreen = (xmh_item(xymonhost, XMH_FLAG_NONONGREEN) != NULL); alertlist = xmh_item(xymonhost, XMH_NK); hval = xmh_item(xymonhost, XMH_NKTIME); if (hval) crittime = within_sla(xmh_item(xymonhost, XMH_HOLIDAYS), hval, 0); onwaplist = xmh_item(xymonhost, XMH_WML); nopropyellowlist = xmh_item(xymonhost, XMH_NOPROPYELLOW); if (nopropyellowlist == NULL) nopropyellowlist = xmh_item(xymonhost, XMH_NOPROP); nopropredlist = xmh_item(xymonhost, XMH_NOPROPRED); noproppurplelist = xmh_item(xymonhost, XMH_NOPROPPURPLE); nopropacklist = xmh_item(xymonhost, XMH_NOPROPACK); displayname = xmh_item(xymonhost, XMH_DISPLAYNAME); comment = xmh_item(xymonhost, XMH_COMMENT); description = xmh_item(xymonhost, XMH_DESCRIPTION); hval = xmh_item(xymonhost, XMH_WARNPCT); if (hval) warnpct = atof(hval); hval = xmh_item(xymonhost, XMH_WARNSTOPS); if (hval) warnstops = atof(hval); reporttime = xmh_item(xymonhost, XMH_REPORTTIME); clientalias = xmh_item(xymonhost, XMH_CLIENTALIAS); if (xymonhost && (strcmp(xmh_item(xymonhost, XMH_HOSTNAME), clientalias) == 0)) clientalias = NULL; if (xymonhost && (strlen(pgset) > 0)) { /* Walk the clone-list and pick up the target pages for this host */ void *cwalk = xymonhost; do { hval = xmh_item_walk(cwalk); while (hval) { if (strncasecmp(hval, hosttag, strlen(hosttag)) == 0) targetpagelist[targetpagecount++] = strdup(hval+strlen(hosttag)); hval = xmh_item_walk(NULL); } cwalk = next_host(cwalk, 1); } while (cwalk && (strcmp(xmh_item(cwalk, XMH_HOSTNAME), xmh_item(xymonhost, XMH_HOSTNAME)) == 0) && (targetpagecount < MAX_TARGETPAGES_PER_HOST) ); /* * HACK: Check if the pageset tag is present at all in the host * entry. If it isn't, then drop this incarnation of the host. * * Without this, the following hosts.cfg file will have the * www.hswn.dk host listed twice on the alternate pageset: * * adminpage nyc NYC * * 127.0.0.1 localhost # bbd http://localhost/ CLIENT:osiris * 172.16.10.2 www.xymon.com # http://www.xymon.com/ ADMIN:nyc ssh noinfo * * page superdome Superdome * 172.16.10.2 www.xymon.com # noconn * */ if (strstr(inbol, hosttag) == NULL) targetpagecount = 0; } if (strlen(pgset) == 0) { /* * Default pageset generated. Put the host into * whatever group or page is current. */ if (curhost == NULL) { curhost = init_host(hostname, 0, displayname, clientalias, comment, description, ip1, ip2, ip3, ip4, dialup, warnpct, warnstops, reporttime, alertlist, crittime, onwaplist, nopropyellowlist, nopropredlist, noproppurplelist, nopropacklist); if (curgroup != NULL) { curgroup->hosts = curhost; } else if (cursubparent != NULL) { cursubparent->hosts = curhost; } else if (cursubpage != NULL) { cursubpage->hosts = curhost; } else if (curpage != NULL) { curpage->hosts = curhost; } else { toppage->hosts = curhost; } } else { curhost = curhost->next = init_host(hostname, 0, displayname, clientalias, comment, description, ip1, ip2, ip3, ip4, dialup, warnpct, warnstops, reporttime, alertlist, crittime, onwaplist, nopropyellowlist,nopropredlist, noproppurplelist, nopropacklist); } curhost->parent = (cursubparent ? cursubparent : (cursubpage ? cursubpage : curpage)); if (curtitle) { curhost->pretitle = curtitle; curtitle = NULL; } curhost->nonongreen = nonongreen; } else if (targetpagecount) { int pgnum; for (pgnum=0; (pgnum < targetpagecount); pgnum++) { char *targetpagename = targetpagelist[pgnum]; char savechar; int wantedgroup = 0; xymonpagelist_t *targetpage = NULL; /* Put the host into the page specified by the PGSET: tag */ p = strchr(targetpagename, ','); if (p) { savechar = *p; *p = '\0'; wantedgroup = atoi(p+1); } else { savechar = '\0'; p = targetpagename + strlen(targetpagename); } /* Find the page */ if (strcmp(targetpagename, "*") == 0) { *targetpagename = '\0'; } for (targetpage = pagelisthead; (targetpage && (strcmp(targetpagename, targetpage->pageentry->name) != 0)); targetpage = targetpage->next) ; *p = savechar; if (targetpage == NULL) { errprintf("Warning: Cannot find any target page named '%s' in set '%s' - dropping host '%s'\n", targetpagename, pgset, hostname); } else { host_t *newhost = init_host(hostname, 0, displayname, clientalias, comment, description, ip1, ip2, ip3, ip4, dialup, warnpct, warnstops, reporttime, alertlist, crittime, onwaplist, nopropyellowlist,nopropredlist, noproppurplelist, nopropacklist); if (wantedgroup > 0) { group_t *gwalk; host_t *hwalk; int i; for (gwalk = targetpage->pageentry->groups, i=1; (gwalk && (i < wantedgroup)); i++,gwalk=gwalk->next) ; if (gwalk) { if (gwalk->hosts == NULL) gwalk->hosts = newhost; else { for (hwalk = gwalk->hosts; (hwalk->next); hwalk = hwalk->next) ; hwalk->next = newhost; } } else { errprintf("Warning: Cannot find group %d for host %s - dropping host\n", wantedgroup, hostname); } } else { /* Just put in on the page's hostlist */ host_t *walk; if (targetpage->pageentry->hosts == NULL) targetpage->pageentry->hosts = newhost; else { for (walk = targetpage->pageentry->hosts; (walk->next); walk = walk->next) ; walk->next = newhost; } } newhost->parent = targetpage->pageentry; if (curtitle) newhost->pretitle = curtitle; } curtitle = NULL; } } } else if (strncmp(inbol, summarytag, strlen(summarytag)) == 0) { /* summary row.column IP-ADDRESS-OF-PARENT http://xymon.com/ */ char sumname[MAX_LINE_LEN]; char receiver[MAX_LINE_LEN]; char url[MAX_LINE_LEN]; summary_t *newsum; if (sscanf(inbol, "summary %s %s %s", sumname, receiver, url) == 3) { newsum = init_summary(sumname, receiver, url); newsum->next = sumhead; sumhead = newsum; } } else if (strncmp(inbol, titletag, strlen(titletag)) == 0) { /* Save the title for the next entry */ curtitle = strdup(skipwhitespace(skipword(inbol))); } nextline: if (ineol) { *ineol = insavchar; if (*ineol != '\n') ineol = strchr(ineol, '\n'); inbol = (ineol ? ineol+1 : NULL); } else inbol = NULL; } xfree(cfgdata); return toppage; }
int main(int argc, char *argv[]) { int argi; struct sigaction sa; namelist_t *hostwalk; time_t nexttimeout; for (argi=1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--server=")) { char *p = strchr(argv[argi], '='); serverip = strdup(p+1); } else if (argnmatch(argv[argi], "--interval=")) { char *p = strchr(argv[argi], '='); pollinterval = atoi(p+1); } else if (argnmatch(argv[argi], "--log-interval=")) { char *p = strchr(argv[argi], '='); errorloginterval = atoi(p+1); } else if (argnmatch(argv[argi], "--id=")) { char *p = strchr(argv[argi], '='); serverid = atoi(p+1); } else if (strcmp(argv[argi], "--debug") == 0) { debug = 1; } } setup_signalhandler("hobbitfetch"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigmisc_handler; sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); /* SIGUSR1 triggers logging of active requests */ clients = rbtNew(name_compare); nexttimeout = time(NULL) + 60; { /* Seed the random number generator */ struct timeval tv; struct timezone tz; gettimeofday(&tv, &tz); srandom(tv.tv_usec); } do { RbtIterator handle; conn_t *connwalk, *cprev; fd_set fdread, fdwrite; int n, maxfd; struct timeval tmo; time_t now; now = time(NULL); if (now > reloadtime) { /* Time to reload the bb-hosts file */ reloadtime = now + 600; load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn()); for (hostwalk = first_host(); (hostwalk); hostwalk = hostwalk->next) { char *hname; clients_t *newclient; if (!bbh_item(hostwalk, BBH_FLAG_PULLDATA)) continue; hname = bbh_item(hostwalk, BBH_HOSTNAME); handle = rbtFind(clients, hname); if (handle == rbtEnd(clients)) { newclient = (clients_t *)calloc(1, sizeof(clients_t)); newclient->hostname = strdup(hname); rbtInsert(clients, newclient->hostname, newclient); whentoqueue = now; } } } now = time(NULL); if (now > nexttimeout) { /* Check for connections that have timed out */ nexttimeout = now + 60; for (connwalk = chead; (connwalk); connwalk = connwalk->next) { if ((connwalk->tstamp + 60) < now) { if (debug || (connwalk->client->nexterrortxt < now)) { errprintf("Timeout while talking to %s (req %lu): Aborting session\n", addrstring(&connwalk->caddr), connwalk->seq); connwalk->client->nexterrortxt = now + errorloginterval; } flag_cleanup(connwalk); } } } if (needcleanup) { /* Remove any finished requests */ needcleanup = 0; connwalk = chead; cprev = NULL; dbgprintf("Doing cleanup\n"); while (connwalk) { conn_t *zombie; if ((connwalk->action == C_READING) || (connwalk->action == C_WRITING)) { /* Active connection - skip to the next conn_t record */ cprev = connwalk; connwalk = connwalk->next; continue; } if (connwalk->action == C_CLEANUP) { if (connwalk->ctype == C_CLIENT) { /* * Finished getting data from a client, * flag idle and set next poll time. */ connwalk->client->busy = 0; set_polltime(connwalk->client); } else if (connwalk->ctype == C_SERVER) { /* Nothing needed for server cleanups */ } } /* Unlink the request from the list of active connections */ zombie = connwalk; if (cprev == NULL) { chead = zombie->next; connwalk = chead; cprev = NULL; } else { cprev->next = zombie->next; connwalk = zombie->next; } /* Purge the zombie */ dbgprintf("Request completed: req %lu, peer %s, action was %d, type was %d\n", zombie->seq, addrstring(&zombie->caddr), zombie->action, zombie->ctype); close(zombie->sockfd); freestrbuffer(zombie->msgbuf); xfree(zombie); } /* Set the tail pointer correctly */ ctail = chead; if (ctail) { while (ctail->next) ctail = ctail->next; } } if (dumpsessions) { /* Set by SIGUSR1 - dump the list of active requests */ dumpsessions = 0; for (connwalk = chead; (connwalk); connwalk = connwalk->next) { char *ctypestr, *actionstr; char timestr[30]; switch (connwalk->ctype) { case C_CLIENT: ctypestr = "client"; break; case C_SERVER: ctypestr = "server"; break; } switch (connwalk->action) { case C_READING: actionstr = "reading"; break; case C_WRITING: actionstr = "writing"; break; case C_CLEANUP: actionstr = "cleanup"; break; } strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", localtime(&connwalk->tstamp)); errprintf("Request %lu: state %s/%s, peer %s, started %s (%lu secs ago)\n", connwalk->seq, ctypestr, actionstr, addrstring(&connwalk->caddr), timestr, (now - connwalk->tstamp)); } } now = time(NULL); if (now >= whentoqueue) { /* Scan host-tree for clients we need to contact */ for (handle = rbtBegin(clients); (handle != rbtEnd(clients)); handle = rbtNext(clients, handle)) { clients_t *clientwalk; char msgline[100]; strbuffer_t *request; char *pullstr, *ip; int port; clientwalk = (clients_t *)gettreeitem(clients, handle); if (clientwalk->busy) continue; if (clientwalk->nextpoll > now) continue; /* Deleted hosts stay in our tree - but should disappear from the known hosts */ hostwalk = hostinfo(clientwalk->hostname); if (!hostwalk) continue; pullstr = bbh_item(hostwalk, BBH_FLAG_PULLDATA); if (!pullstr) continue; ip = strchr(pullstr, '='); port = atoi(xgetenv("BBPORT")); if (!ip) { ip = strdup(bbh_item(hostwalk, BBH_IP)); } else { /* There is an explicit IP setting in the pulldata tag */ char *p; ip++; /* Skip the '=' */ ip = strdup(ip); p = strchr(ip, ':'); if (p) { *p = '\0'; port = atoi(p+1); } if (*ip == '\0') { /* No IP given, just a port number */ xfree(ip); ip = strdup(bbh_item(hostwalk, BBH_IP)); } } if (strcmp(ip, "0.0.0.0") == 0) { struct hostent *hent; xfree(ip); ip = NULL; hent = gethostbyname(clientwalk->hostname); if (hent) { struct in_addr addr; memcpy(&addr, *(hent->h_addr_list), sizeof(addr)); ip = strdup(inet_ntoa(addr)); } } if (!ip) continue; /* * Build the "pullclient" request, which includes the latest * clientdata config we got from the server. Keep the clientdata * here - we send "pullclient" requests more often that we actually * contact the server, but we should provide the config data always. */ request = newstrbuffer(0); sprintf(msgline, "pullclient %d\n", serverid); addtobuffer(request, msgline); if (clientwalk->clientdata) addtobuffer(request, clientwalk->clientdata); /* Put the request on the connection queue */ addrequest(C_CLIENT, ip, port, request, clientwalk); clientwalk->busy = 1; xfree(ip); } } /* Handle request queue */ FD_ZERO(&fdread); FD_ZERO(&fdwrite); maxfd = -1; for (connwalk = chead; (connwalk); connwalk = connwalk->next) { switch (connwalk->action) { case C_READING: FD_SET(connwalk->sockfd, &fdread); if (connwalk->sockfd > maxfd) maxfd = connwalk->sockfd; break; case C_WRITING: FD_SET(connwalk->sockfd, &fdwrite); if (connwalk->sockfd > maxfd) maxfd = connwalk->sockfd; break; case C_CLEANUP: break; } } /* Do select with a 1 second timeout */ tmo.tv_sec = 1; tmo.tv_usec = 0; n = select(maxfd+1, &fdread, &fdwrite, NULL, &tmo); if (n == -1) { if (errno == EINTR) continue; /* Interrupted, e.g. a SIGHUP */ /* This is a "cannot-happen" failure. Bail out */ errprintf("select failure: %s\n", strerror(errno)); return 0; } if (n == 0) continue; /* Timeout */ for (connwalk = chead; (connwalk); connwalk = connwalk->next) { switch (connwalk->action) { case C_READING: if (FD_ISSET(connwalk->sockfd, &fdread)) grabdata(connwalk); break; case C_WRITING: if (FD_ISSET(connwalk->sockfd, &fdwrite)) senddata(connwalk); break; case C_CLEANUP: break; } } } while (running); return 0; }
int do_ifstat_rrd(char *hostname, char *testname, char *classname, char *pagepaths, char *msg, time_t tstamp) { static int pcres_compiled = 0; static pcre **ifstat_linux_pcres = NULL; static pcre **ifstat_freebsd_pcres = NULL; static pcre **ifstat_freebsdV8_pcres = NULL; static pcre **ifstat_openbsd_pcres = NULL; static pcre **ifstat_netbsd_pcres = NULL; static pcre **ifstat_darwin_pcres = NULL; static pcre **ifstat_solaris_pcres = NULL; static pcre **ifstat_aix_pcres = NULL; static pcre **ifstat_hpux_pcres = NULL; static pcre **ifstat_sco_sv_pcres = NULL; static pcre **ifstat_bbwin_pcres = NULL; enum ostype_t ostype; char *datapart = msg; char *bol, *eoln, *ifname, *rxstr, *txstr, *dummy; int dmatch; void *xmh; pcre *ifname_filter_pcre = NULL; xmh = hostinfo(hostname); if (xmh) { char *ifname_filter_expr = xmh_item(xmh, XMH_INTERFACES); if (ifname_filter_expr && *ifname_filter_expr) ifname_filter_pcre = compileregex(ifname_filter_expr); } if (pcres_compiled == 0) { pcres_compiled = 1; ifstat_linux_pcres = compile_exprs("LINUX", ifstat_linux_exprs, (sizeof(ifstat_linux_exprs) / sizeof(ifstat_linux_exprs[0]))); ifstat_freebsd_pcres = compile_exprs("FREEBSD", ifstat_freebsd_exprs, (sizeof(ifstat_freebsd_exprs) / sizeof(ifstat_freebsd_exprs[0]))); ifstat_freebsdV8_pcres = compile_exprs("FREEBSD", ifstat_freebsdV8_exprs, (sizeof(ifstat_freebsdV8_exprs) / sizeof(ifstat_freebsdV8_exprs[0]))); ifstat_openbsd_pcres = compile_exprs("OPENBSD", ifstat_openbsd_exprs, (sizeof(ifstat_openbsd_exprs) / sizeof(ifstat_openbsd_exprs[0]))); ifstat_netbsd_pcres = compile_exprs("NETBSD", ifstat_netbsd_exprs, (sizeof(ifstat_netbsd_exprs) / sizeof(ifstat_netbsd_exprs[0]))); ifstat_darwin_pcres = compile_exprs("DARWIN", ifstat_darwin_exprs, (sizeof(ifstat_darwin_exprs) / sizeof(ifstat_darwin_exprs[0]))); ifstat_solaris_pcres = compile_exprs("SOLARIS", ifstat_solaris_exprs, (sizeof(ifstat_solaris_exprs) / sizeof(ifstat_solaris_exprs[0]))); ifstat_aix_pcres = compile_exprs("AIX", ifstat_aix_exprs, (sizeof(ifstat_aix_exprs) / sizeof(ifstat_aix_exprs[0]))); ifstat_hpux_pcres = compile_exprs("HPUX", ifstat_hpux_exprs, (sizeof(ifstat_hpux_exprs) / sizeof(ifstat_hpux_exprs[0]))); ifstat_sco_sv_pcres = compile_exprs("SCO_SV", ifstat_sco_sv_exprs, (sizeof(ifstat_sco_sv_exprs) / sizeof(ifstat_sco_sv_exprs[0]))); ifstat_bbwin_pcres = compile_exprs("BBWIN", ifstat_bbwin_exprs, (sizeof(ifstat_bbwin_exprs) / sizeof(ifstat_bbwin_exprs[0]))); } if (ifstat_tpl == NULL) ifstat_tpl = setup_template(ifstat_params); if ((strncmp(msg, "status", 6) == 0) || (strncmp(msg, "data", 4) == 0)) { /* Skip the first line of full status- and data-messages. */ datapart = strchr(msg, '\n'); if (datapart) datapart++; else datapart = msg; } ostype = get_ostype(datapart); datapart = strchr(datapart, '\n'); if (datapart) { datapart++; } else { errprintf("Too few lines in ifstat report from %s\n", hostname); return -1; } dmatch = 0; ifname = rxstr = txstr = dummy = NULL; bol = datapart; while (bol) { eoln = strchr(bol, '\n'); if (eoln) *eoln = '\0'; switch (ostype) { case OS_LINUX22: case OS_LINUX: case OS_RHEL3: case OS_ZVM: case OS_ZVSE: case OS_ZOS: if (pickdata(bol, ifstat_linux_pcres[0], 1, &ifname)) { /* * Linux' netif aliases mess up things. * Clear everything when we see an interface name. * But we dont want to track the "lo" interface. */ /* Strip off the last character if it is a colon (:) */ if (ifname[strlen(ifname)-1] == ':') ifname[strlen(ifname)-1] = '\0'; if (strcmp(ifname, "lo") == 0) { xfree(ifname); ifname = NULL; } else { dmatch = 1; if (rxstr) { xfree(rxstr); rxstr = NULL; } if (txstr) { xfree(txstr); txstr = NULL; } } } else if (pickdata(bol, ifstat_linux_pcres[1], 1, &rxstr, &txstr)) dmatch |= 6; else if (pickdata(bol, ifstat_linux_pcres[2], 1, &rxstr)) dmatch |= 2; else if (pickdata(bol, ifstat_linux_pcres[3], 1, &txstr)) dmatch |= 4; break; case OS_FREEBSD: /* * FreeBSD 8 added an "Idrop" counter in the middle of the data. * See if we match this expression, and if not then fall back to * the old regex without that field. */ if (pickdata(bol, ifstat_freebsdV8_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; else if (pickdata(bol, ifstat_freebsd_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_OPENBSD: if (pickdata(bol, ifstat_openbsd_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_NETBSD: if (pickdata(bol, ifstat_netbsd_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_SOLARIS: if (pickdata(bol, ifstat_solaris_pcres[0], 0, &ifname, &txstr)) dmatch |= 1; else if (pickdata(bol, ifstat_solaris_pcres[1], 0, &dummy, &rxstr)) dmatch |= 6; if (ifname && dummy && (strcmp(ifname, dummy) != 0)) { /* They must match, drop the data */ errprintf("Host %s has weird ifstat data - device name mismatch %s:%s\n", hostname, ifname, dummy); xfree(ifname); xfree(txstr); xfree(rxstr); xfree(dummy); dmatch = 0; } /* Ignore "mac" and "wrsmd" entries - these are for sub-devices for multiple nic's aggregated into one */ /* See http://www.xymon.com/archive/2009/06/msg00204.html for more info */ if (ifname && ((strcmp(ifname, "mac") == 0) || (strcmp(ifname, "wrsmd") == 0)) ) { xfree(ifname); xfree(txstr); dmatch = 0; } if (dummy && ((strcmp(dummy, "mac") == 0) || (strcmp(dummy, "wrsmd") == 0)) ) { xfree(dummy); xfree(rxstr); dmatch = 0; } break; case OS_AIX: if (pickdata(bol, ifstat_aix_pcres[0], 1, &ifname)) { /* Interface names comes first, so any rx/tx data is discarded */ dmatch |= 1; if (rxstr) { xfree(rxstr); rxstr = NULL; } if (txstr) { xfree(txstr); txstr = NULL; } } else if (pickdata(bol, ifstat_aix_pcres[1], 1, &txstr, &rxstr)) dmatch |= 6; break; case OS_HPUX: if (pickdata(bol, ifstat_hpux_pcres[0], 1, &ifname)) { /* Interface names comes first, so any rx/tx data is discarded */ dmatch |= 1; if (rxstr) { xfree(rxstr); rxstr = NULL; } if (txstr) { xfree(txstr); txstr = NULL; } } else if (pickdata(bol, ifstat_hpux_pcres[1], 1, &rxstr)) dmatch |= 2; else if (pickdata(bol, ifstat_hpux_pcres[2], 1, &txstr)) dmatch |= 4; break; case OS_DARWIN: if (pickdata(bol, ifstat_darwin_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_SCO_SV: if (pickdata(bol, ifstat_sco_sv_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; case OS_WIN32_BBWIN: if (pickdata(bol, ifstat_bbwin_pcres[0], 0, &ifname, &rxstr, &txstr)) dmatch = 7; break; default: break; } if ((dmatch == 7) && ifname && rxstr && txstr) { if (!ifname_filter_pcre || matchregex(ifname, ifname_filter_pcre)) { setupfn2("%s.%s.rrd", "ifstat", ifname); snprintf(rrdvalues, sizeof(rrdvalues), "%d:%s:%s", (int)tstamp, txstr, rxstr); create_and_update_rrd(hostname, testname, classname, pagepaths, ifstat_params, ifstat_tpl); } xfree(ifname); xfree(rxstr); xfree(txstr); if (dummy) xfree(dummy); ifname = rxstr = txstr = dummy = NULL; dmatch = 0; } if (eoln) { *eoln = '\n'; bol = eoln+1; if (*bol == '\0') bol = NULL; } else { bol = NULL; } } if (ifname_filter_pcre) freeregex(ifname_filter_pcre); if (ifname) xfree(ifname); if (rxstr) xfree(rxstr); if (txstr) xfree(txstr); if (dummy) xfree(dummy); return 0; }
int main(int argc, char *argv[]) { int argi, hosti, testi; char *pagepattern = NULL, *hostpattern = NULL; char *envarea = NULL, *cookie = NULL, *nexthost; char *hobbitcmd, *procscmd, *svcscmd; int alertcolors, alertinterval; char configfn[PATH_MAX]; char *respbuf = NULL, *procsbuf = NULL, *svcsbuf = NULL; hostlist_t *hwalk; htnames_t *twalk; hostlist_t **allhosts = NULL; htnames_t **alltests = NULL; int hostcount = 0, maxtests = 0; time_t now = getcurrenttime(NULL); sendreturn_t *sres; for (argi=1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--env=")) { char *p = strchr(argv[argi], '='); loadenv(p+1, envarea); } else if (argnmatch(argv[argi], "--area=")) { char *p = strchr(argv[argi], '='); envarea = strdup(p+1); } else if (strcmp(argv[argi], "--debug") == 0) { debug = 1; } else if (argnmatch(argv[argi], "--delimiter=")) { char *p = strchr(argv[argi], '='); coldelim = strdup(p+1); } else if (strcmp(argv[argi], "--critical") == 0) { nkonly = 1; } else if (strcmp(argv[argi], "--old-nk-config") == 0) { newnkconfig = 0; } } redirect_cgilog("hobbit-confreport"); load_hostnames(xgetenv("BBHOSTS"), NULL, get_fqdn()); load_nkconfig(NULL); /* Setup the filter we use for the report */ cookie = get_cookie("pagepath"); if (cookie && *cookie) pagepattern = strdup(cookie); cookie = get_cookie("host"); if (cookie && *cookie) hostpattern = strdup(cookie); /* Fetch the list of host+test statuses we currently know about */ if (pagepattern) { hobbitcmd = (char *)malloc(2*strlen(pagepattern) + 1024); procscmd = (char *)malloc(2*strlen(pagepattern) + 1024); svcscmd = (char *)malloc(2*strlen(pagepattern) + 1024); sprintf(hobbitcmd, "hobbitdboard page=^%s$|^%s/.+ fields=hostname,testname", pagepattern, pagepattern); sprintf(procscmd, "hobbitdboard page=^%s$|^%s/.+ test=procs fields=hostname,msg", pagepattern, pagepattern); sprintf(svcscmd, "hobbitdboard page=^%s$|^%s/.+ test=svcs fields=hostname,msg", pagepattern, pagepattern); } else if (hostpattern) { hobbitcmd = (char *)malloc(strlen(hostpattern) + 1024); procscmd = (char *)malloc(strlen(hostpattern) + 1024); svcscmd = (char *)malloc(strlen(hostpattern) + 1024); sprintf(hobbitcmd, "hobbitdboard host=^%s$ fields=hostname,testname", hostpattern); sprintf(procscmd, "hobbitdboard host=^%s$ test=procs fields=hostname,msg", hostpattern); sprintf(svcscmd, "hobbitdboard host=^%s$ test=svcs fields=hostname,msg", hostpattern); } else { hobbitcmd = (char *)malloc(1024); procscmd = (char *)malloc(1024); svcscmd = (char *)malloc(1024); sprintf(hobbitcmd, "hobbitdboard fields=hostname,testname"); sprintf(procscmd, "hobbitdboard test=procs fields=hostname,msg"); sprintf(svcscmd, "hobbitdboard test=svcs fields=hostname,msg"); } sres = newsendreturnbuf(1, NULL); if (sendmessage(hobbitcmd, NULL, BBTALK_TIMEOUT, sres) != BB_OK) { errormsg("Cannot contact the Hobbit server\n"); return 1; } respbuf = getsendreturnstr(sres, 1); if (sendmessage(procscmd, NULL, BBTALK_TIMEOUT, sres) != BB_OK) { errormsg("Cannot contact the Hobbit server\n"); return 1; } procsbuf = getsendreturnstr(sres, 1); if (sendmessage(svcscmd, NULL, BBTALK_TIMEOUT, sres) != BB_OK) { errormsg("Cannot contact the Hobbit server\n"); return 1; } svcsbuf = getsendreturnstr(sres, 1); freesendreturnbuf(sres); if (!respbuf) { errormsg("Unable to find host information\n"); return 1; } /* Parse it into a usable list */ nexthost = respbuf; do { char *hname, *tname, *eoln; int wanted = 1; eoln = strchr(nexthost, '\n'); if (eoln) *eoln = '\0'; hname = nexthost; tname = strchr(nexthost, '|'); if (tname) { *tname = '\0'; tname++; } if (nkonly) { void *hinfo = hostinfo(hname); char *nkalerts = bbh_item(hinfo, BBH_NK); if (newnkconfig) { if (strcmp(nkval(hname, tname, nkalerts), "No") == 0 ) wanted = 0; } else { if (!nkalerts) wanted = 0; } } if (wanted && hname && tname && strcmp(hname, "summary") && strcmp(tname, xgetenv("INFOCOLUMN")) && strcmp(tname, xgetenv("TRENDSCOLUMN"))) { htnames_t *newitem = (htnames_t *)malloc(sizeof(htnames_t)); for (hwalk = hosthead; (hwalk && strcmp(hwalk->hostname, hname)); hwalk = hwalk->next); if (!hwalk) { hwalk = (hostlist_t *)calloc(1, sizeof(hostlist_t)); hwalk->hostname = strdup(hname); hwalk->procs = get_proclist(hname, procsbuf); hwalk->svcs = get_proclist(hname, svcsbuf); hwalk->next = hosthead; hosthead = hwalk; hostcount++; } newitem->name = strdup(tname); newitem->next = hwalk->tests; hwalk->tests = newitem; hwalk->testcount++; } if (eoln) { nexthost = eoln+1; if (*nexthost == '\0') nexthost = NULL; } } while (nexthost); allhosts = (hostlist_t **) malloc(hostcount * sizeof(hostlist_t *)); for (hwalk = hosthead, hosti=0; (hwalk); hwalk = hwalk->next, hosti++) { allhosts[hosti] = hwalk; if (hwalk->testcount > maxtests) maxtests = hwalk->testcount; } alltests = (htnames_t **) malloc(maxtests * sizeof(htnames_t *)); qsort(&allhosts[0], hostcount, sizeof(hostlist_t **), host_compare); /* Get the static info */ load_all_links(); init_tcp_services(); pingcolumn = xgetenv("PINGCOLUMN"); pingplus = (char *)malloc(strlen(pingcolumn) + 2); sprintf(pingplus, "%s=", pingcolumn); /* Load alert config */ alertcolors = colorset(xgetenv("ALERTCOLORS"), ((1 << COL_GREEN) | (1 << COL_BLUE))); alertinterval = 60*atoi(xgetenv("ALERTREPEAT")); sprintf(configfn, "%s/etc/hobbit-alerts.cfg", xgetenv("BBHOME")); load_alertconfig(configfn, alertcolors, alertinterval); load_columndocs(); printf("Content-Type: %s\n\n", xgetenv("HTMLCONTENTTYPE")); sethostenv("", "", "", colorname(COL_BLUE), NULL); headfoot(stdout, "confreport", "", "header", COL_BLUE); fprintf(stdout, "<table width=\"100%%\" border=0>\n"); fprintf(stdout, "<tr><th align=center colspan=2><font size=\"+2\">Hobbit configuration Report</font></th></tr>\n"); fprintf(stdout, "<tr><th valign=top align=left>Date</th><td>%s</td></tr>\n", ctime(&now)); fprintf(stdout, "<tr><th valign=top align=left>%d hosts included</th><td>\n", hostcount); for (hosti=0; (hosti < hostcount); hosti++) { fprintf(stdout, "%s ", allhosts[hosti]->hostname); } fprintf(stdout, "</td></tr>\n"); if (nkonly) { fprintf(stdout, "<tr><th valign=top align=left>Filter</th><td>Only data for the "Critical Systems" view reported</td></tr>\n"); } fprintf(stdout, "</table>\n"); headfoot(stdout, "confreport", "", "front", COL_BLUE); for (hosti=0; (hosti < hostcount); hosti++) { for (twalk = allhosts[hosti]->tests, testi = 0; (twalk); twalk = twalk->next, testi++) { alltests[testi] = twalk; } qsort(&alltests[0], allhosts[hosti]->testcount, sizeof(htnames_t **), test_compare); print_host(allhosts[hosti], alltests, allhosts[hosti]->testcount); } headfoot(stdout, "confreport", "", "back", COL_BLUE); print_columndocs(); headfoot(stdout, "confreport", "", "footer", COL_BLUE); return 0; }
void print_hoststatus(FILE *output, hstatus_t *itm, void * statetree, void * columns, int prio, int firsthost, int firsthostever) { void *hinfo; char *dispname, *ip, *key; time_t now; xtreePos_t colhandle; now = getcurrenttime(NULL); hinfo = hostinfo(itm->hostname); dispname = xmh_item(hinfo, XMH_DISPLAYNAME); ip = xmh_item(hinfo, XMH_IP); fprintf(output, "<TR>\n"); /* Print the priority */ fprintf(output, "<TD ALIGN=LEFT VALIGN=TOP WIDTH=10%% NOWRAP>"); if (firsthost) if (prio == 99) { if (firsthostever) /* Only non-prioritised hosts, so just drop that text */ fprintf(output, " "); else fprintf(output, "<FONT %s>No priority</FONT>", xgetenv("XYMONPAGEROWFONT")); } else { fprintf(output, "<FONT %s>PRIO %d</FONT>", xgetenv("XYMONPAGEROWFONT"), prio); } else fprintf(output, " "); fprintf(output, "</TD>\n"); /* Print the hostname with a link to the critical systems info page */ fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", hostnamehtml(itm->hostname, NULL, usetooltips)); key = (char *)malloc(1024); for (colhandle = xtreeFirst(columns); (colhandle != xtreeEnd(columns)); colhandle = xtreeNext(columns, colhandle)) { char *colname; xtreePos_t sthandle; fprintf(output, "<TD ALIGN=CENTER>"); colname = (char *)xtreeKey(columns, colhandle); key = (char *)realloc(key, 2 + strlen(itm->hostname) + strlen(colname)); sprintf(key, "%s|%s", itm->hostname, colname); sthandle = xtreeFind(statetree, key); if (sthandle == xtreeEnd(statetree)) { fprintf(output, "-"); } else { hstatus_t *column; char *htmlalttag; char *htmlackstr; column = (hstatus_t *)xtreeData(statetree, sthandle); if (column->config->priority != prio) fprintf(output, "-"); else { time_t age = now - column->lastchange; char *htmlgroupstr; char *htmlextrastr; htmlalttag = alttag(colname, column->color, 0, 1, agestring(age)); htmlackstr = (column->ackmsg ? column->ackmsg : ""); htmlgroupstr = strdup(urlencode(column->config->ttgroup ? column->config->ttgroup : "")); htmlextrastr = strdup(urlencode(column->config->ttextra ? column->config->ttextra : "")); fprintf(output, "<A HREF=\"%s&NKPRIO=%d&NKTTGROUP=%s&NKTTEXTRA=%s\">", hostsvcurl(itm->hostname, colname, 1), prio, htmlgroupstr, htmlextrastr); fprintf(output, "<IMG SRC=\"%s/%s\" ALT=\"%s\" TITLE=\"%s %s\" HEIGHT=\"%s\" WIDTH=\"%s\" BORDER=0></A>", xgetenv("XYMONSKIN"), dotgiffilename(column->color, (column->acktime > 0), (age > oldlimit)), colorname(column->color), htmlalttag, htmlackstr, xgetenv("DOTHEIGHT"), xgetenv("DOTWIDTH")); xfree(htmlgroupstr); xfree(htmlextrastr); } } fprintf(output, "</TD>\n"); } xfree(key); fprintf(output, "</TR>\n"); }
int loadstatus(int maxprio, time_t maxage, int mincolor, int wantacked) { char *board, *bol, *eol; time_t now; /* * We leak memory by dup'ing this and not freeing it. * But we cannot free it, because the tree holding the data * for later printing contains pointers into this string buffer. */ board = strdup(boardmaster); now = getcurrenttime(NULL); treecount++; if (treecount == 1) { rbstate = malloc(sizeof(void *)); hostsonpage = malloc(sizeof(void *)); } else { rbstate = realloc(rbstate, (treecount) * sizeof(void *)); hostsonpage = realloc(hostsonpage, (treecount) * sizeof(void *)); } rbstate[treecount-1] = xtreeNew(strcasecmp); hostsonpage[treecount-1] = xtreeNew(strcasecmp); bol = board; while (bol && (*bol)) { char *endkey; eol = strchr(bol, '\n'); if (eol) *eol = '\0'; /* Find the config entry */ endkey = strchr(bol, '|'); if (endkey) endkey = strchr(endkey+1, '|'); if (endkey) { critconf_t *cfg; char *ackstr, *ackrtimestr, *ackvtimestr, *acklevelstr, *ackbystr, *ackmsgstr; *endkey = '\0'; cfg = get_critconfig(bol, CRITCONF_TIMEFILTER, NULL); *endkey = '|'; if (cfg) { hstatus_t *newitem = (hstatus_t *)calloc(1, sizeof(hstatus_t)); newitem->config = cfg; newitem->hostname = gettok(bol, "|"); newitem->testname = gettok(NULL, "|"); newitem->color = parse_color(gettok(NULL, "|")); newitem->lastchange = atoi(gettok(NULL, "|")); newitem->logtime = atoi(gettok(NULL, "|")); newitem->validtime = atoi(gettok(NULL, "|")); ackstr = gettok(NULL, "|"); ackrtimestr = ackvtimestr = acklevelstr = ackbystr = ackmsgstr = NULL; if (ackstr) { nldecode(ackstr); ackrtimestr = strtok(ackstr, ":"); if (ackrtimestr) ackvtimestr = strtok(NULL, ":"); if (ackvtimestr) acklevelstr = strtok(NULL, ":"); if (acklevelstr) ackbystr = strtok(NULL, ":"); if (ackbystr) ackmsgstr = strtok(NULL, ":"); } if ( (hostinfo(newitem->hostname) == NULL) || ((newitem->config->priority > maxprio) && (newitem->config->priority != 99)) || ((now - newitem->lastchange) > maxage) || (newitem->color < mincolor) || (ackmsgstr && !wantacked) ) { xfree(newitem); } else { if (ackvtimestr && ackbystr && ackmsgstr) { newitem->acktime = atoi(ackvtimestr); newitem->ackedby = strdup(ackbystr); newitem->ackmsg = strdup(ackmsgstr); } newitem->key = (char *)malloc(strlen(newitem->hostname) + strlen(newitem->testname) + 2); sprintf(newitem->key, "%s|%s", newitem->hostname, newitem->testname); xtreeAdd(rbstate[treecount-1], newitem->key, newitem); } } } bol = (eol ? (eol+1) : NULL); } return 0; }
void print_hoststatus(FILE *output, hstatus_t *itm, RbtHandle columns, int prio, int firsthost) { void *hinfo; char *dispname, *ip, *key; time_t now; RbtIterator colhandle; now = getcurrenttime(NULL); hinfo = hostinfo(itm->hostname); dispname = xmh_item(hinfo, XMH_DISPLAYNAME); ip = xmh_item(hinfo, XMH_IP); fprintf(output, "<TR>\n"); /* Print the priority */ fprintf(output, "<TD ALIGN=LEFT VALIGN=TOP WIDTH=25%% NOWRAP>"); if (firsthost) fprintf(output, "<FONT %s>PRIO %d</FONT>", xgetenv("XYMONPAGEROWFONT"), prio); else fprintf(output, " "); fprintf(output, "</TD>\n"); /* Print the hostname with a link to the critical systems info page */ fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", hostnamehtml(itm->hostname, NULL, usetooltips)); key = (char *)malloc(strlen(itm->hostname) + 1024); for (colhandle = rbtBegin(columns); (colhandle != rbtEnd(columns)); colhandle = rbtNext(columns, colhandle)) { void *k1, *k2; char *colname; RbtIterator sthandle; fprintf(output, "<TD ALIGN=CENTER>"); rbtKeyValue(columns, colhandle, &k1, &k2); colname = (char *)k1; sprintf(key, "%s|%s", itm->hostname, colname); sthandle = rbtFind(rbstate, key); if (sthandle == rbtEnd(rbstate)) { fprintf(output, "-"); } else { hstatus_t *column; char *htmlalttag; char *htmlackstr; rbtKeyValue(rbstate, sthandle, &k1, &k2); column = (hstatus_t *)k2; if (column->config->priority != prio) fprintf(output, "-"); else { time_t age = now - column->lastchange; char *htmlgroupstr; char *htmlextrastr; htmlalttag = alttag(colname, column->color, 0, 1, agestring(age)); htmlackstr = (column->ackmsg ? column->ackmsg : ""); htmlgroupstr = strdup(urlencode(column->config->ttgroup ? column->config->ttgroup : "")); htmlextrastr = strdup(urlencode(column->config->ttextra ? column->config->ttextra : "")); fprintf(output, "<A HREF=\"%s&NKPRIO=%d&NKTTGROUP=%s&NKTTEXTRA=%s\">", hostsvcurl(itm->hostname, colname, 1), prio, htmlgroupstr, htmlextrastr); fprintf(output, "<IMG SRC=\"%s/%s\" ALT=\"%s\" TITLE=\"%s %s\" HEIGHT=\"%s\" WIDTH=\"%s\" BORDER=0></A>", xgetenv("XYMONSKIN"), dotgiffilename(column->color, (column->acktime > 0), (age > oldlimit)), colorname(column->color), htmlalttag, htmlackstr, xgetenv("DOTHEIGHT"), xgetenv("DOTWIDTH")); xfree(htmlgroupstr); xfree(htmlextrastr); } } fprintf(output, "</TD>\n"); } xfree(key); fprintf(output, "</TR>\n"); }
void generate_compactitems(state_t **topstate) { void *bbh; compact_t **complist = NULL; int complistsz = 0; hostlist_t *h; entry_t *e; char *compacted; char *tok1, *tok2, *savep1, *savep2; compact_t *itm; int i; state_t *newstate; time_t now = getcurrenttime(NULL); for (h = hostlistBegin(); (h); h = hostlistNext()) { bbh = hostinfo(h->hostentry->hostname); compacted = bbh_item(bbh, BBH_COMPACT); if (!compacted) continue; tok1 = strtok_r(compacted, ",", &savep1); while (tok1) { char *members; itm = (compact_t *)calloc(1, sizeof(compact_t)); itm->compactname = strdup(strtok_r(tok1, "=", &savep2)); members = strtok_r(NULL, "\n", &savep2); itm->members = (char *)malloc(3 + strlen(members)); sprintf(itm->members, "|%s|", members); if (complistsz == 0) { complist = (compact_t **)calloc(2, sizeof(compact_t *)); } else { complist = (compact_t **)realloc(complist, (complistsz+2)*sizeof(compact_t *)); } complist[complistsz++] = itm; complist[complistsz] = NULL; tok1 = strtok_r(NULL, ",", &savep1); } for (e = h->hostentry->entries; (e); e = e->next) { for (i = 0; (i < complistsz); i++) { if (wantedcolumn(e->column->name, complist[i]->members)) { e->compacted = 1; if (e->color > complist[i]->color) complist[i]->color = e->color; if (e->fileage > complist[i]->fileage) complist[i]->fileage = e->fileage; } } } for (i = 0; (i < complistsz); i++) { logdata_t log; char fn[PATH_MAX]; memset(&log, 0, sizeof(log)); sprintf(fn, "%s.%s", commafy(h->hostentry->hostname), complist[i]->compactname); log.hostname = h->hostentry->hostname; log.testname = complist[i]->compactname; log.color = complist[i]->color; log.testflags = ""; log.lastchange = now - complist[i]->fileage; log.logtime = getcurrenttime(NULL); log.validtime = log.logtime + 300; log.sender = ""; log.msg = ""; newstate = init_state(fn, &log); if (newstate) { newstate->next = *topstate; *topstate = newstate; } } } }
void do_acklog(FILE *output, int maxcount, int maxminutes) { FILE *acklog; char acklogfilename[PATH_MAX]; time_t cutoff; struct stat st; char l[MAX_LINE_LEN]; char title[200]; ack_t *acks; int num, ackintime_count; havedoneacklog = 1; cutoff = ( (maxminutes) ? (getcurrenttime(NULL) - maxminutes*60) : 0); if ((!maxcount) || (maxcount > 100)) maxcount = 100; sprintf(acklogfilename, "%s/acknowledge.log", xgetenv("BBSERVERLOGS")); acklog = fopen(acklogfilename, "r"); if (!acklog) { /* BB compatible naming */ sprintf(acklogfilename, "%s/acklog", xgetenv("BBACKS")); acklog = fopen(acklogfilename, "r"); } if (!acklog) { /* If no acklog, that is OK - some people dont use acks */ dbgprintf("Cannot open acklog\n"); return; } /* HACK ALERT! */ if (stat(acklogfilename, &st) == 0) { if (st.st_size != 0) { /* Assume a log entry is max 150 bytes */ if (150*maxcount < st.st_size) { fseeko(acklog, -150*maxcount, SEEK_END); fgets(l, sizeof(l), acklog); if (strchr(l, '\n') == NULL) { errprintf("Oops - couldnt find a newline in acklog\n"); } } } } acks = (ack_t *) calloc(maxcount, sizeof(ack_t)); ackintime_count = num = 0; while (fgets(l, sizeof(l), acklog)) { char ackedby[MAX_LINE_LEN], hosttest[MAX_LINE_LEN], color[10], ackmsg[MAX_LINE_LEN]; char ackfn[PATH_MAX]; char *testname; void *hinfo; int ok; if (atol(l) >= cutoff) { int c_used; char *p, *p1, *hobbitdacker = NULL; sscanf(l, "%u\t%d\t%d\t%d\t%s\t%s\t%s\t%n", (time_t *)&acks[num].acktime, &acks[num].acknum, &acks[num].duration, &acks[num].acknum2, ackedby, hosttest, color, &c_used); p1 = ackmsg; for (p=l+c_used, p1=ackmsg; (*p); ) { /* * Need to de-code the ackmsg - it may have been entered * via a web page that did "%asciival" encoding. */ if ((*p == '%') && (strlen(p) >= 3) && isxdigit((int)*(p+1)) && isxdigit((int)*(p+2))) { char hexnum[3]; hexnum[0] = *(p+1); hexnum[1] = *(p+2); hexnum[2] = '\0'; *p1 = (char) strtol(hexnum, NULL, 16); p1++; p += 3; } else { *p1 = *p; p1++; p++; } } *p1 = '\0'; /* Hobbit uses \n in the ack message, for the "acked by" data. Cut it off. */ nldecode(ackmsg); p = strchr(ackmsg, '\n'); if (p) { if (strncmp(p, "\nAcked by:", 10) == 0) hobbitdacker = p+10; *p = '\0'; } /* Show only the first 30 characters in message */ if (strlen(ackmsg) > 30) ackmsg[30] = '\0'; sprintf(ackfn, "%s/ack.%s", xgetenv("BBACKS"), hosttest); testname = strrchr(hosttest, '.'); if (testname) { *testname = '\0'; testname++; } else testname = "unknown"; ok = 1; /* Ack occurred within wanted timerange ? */ if (ok && (acks[num].acktime < cutoff)) ok = 0; /* Unknown host ? */ hinfo = hostinfo(hosttest); if (!hinfo) ok = 0; if (hinfo && bbh_item(hinfo, BBH_FLAG_NOBB2)) ok = 0; if (ok) { char *ackerp; /* If ack has expired or tag file is gone, the ack is no longer valid */ acks[num].ackvalid = 1; if ((acks[num].acktime + 60*acks[num].duration) < getcurrenttime(NULL)) acks[num].ackvalid = 0; if (acks[num].ackvalid && (stat(ackfn, &st) != 0)) acks[num].ackvalid = 0; if (strcmp(ackedby, "np_filename_not_used") != 0) { ackerp = ackedby; if (strncmp(ackerp, "np_", 3) == 0) ackerp += 3; p = strrchr(ackerp, '_'); if (p > ackerp) *p = '\0'; acks[num].ackedby = strdup(ackerp); } else if (hobbitdacker) { acks[num].ackedby = strdup(hobbitdacker); } else { acks[num].ackedby = ""; } acks[num].hostname = strdup(hosttest); acks[num].testname = strdup(testname); strcat(color, " "); acks[num].color = parse_color(color); acks[num].ackmsg = strdup(ackmsg); ackintime_count++; num = (num + 1) % maxcount; } } } if (ackintime_count > 0) { int firstack, lastack; int period = maxminutes; if (ackintime_count <= maxcount) { firstack = 0; lastack = ackintime_count-1; period = maxminutes; } else { firstack = num; lastack = ( (num == 0) ? maxcount : (num-1)); ackintime_count = maxcount; period = ((getcurrenttime(NULL)-acks[firstack].acktime) / 60); } sprintf(title, "%d events acknowledged in the past %u minutes", ackintime_count, period); fprintf(output, "<BR><BR>\n"); fprintf(output, "<TABLE SUMMARY=\"%s\" BORDER=0>\n", title); fprintf(output, "<TR BGCOLOR=\"#333333\">\n"); fprintf(output, "<TD ALIGN=CENTER COLSPAN=6><FONT SIZE=-1 COLOR=\"#33ebf4\">%s</FONT></TD></TR>\n", title); for (num = lastack; (ackintime_count); ackintime_count--, num = ((num == 0) ? (maxcount-1) : (num - 1)) ) { fprintf(output, "<TR BGCOLOR=#000000>\n"); fprintf(output, "<TD ALIGN=CENTER><FONT COLOR=white>%s</FONT></TD>\n", ctime(&acks[num].acktime)); fprintf(output, "<TD ALIGN=CENTER BGCOLOR=%s><FONT COLOR=black>%s</FONT></TD>\n", colorname(acks[num].color), acks[num].hostname); fprintf(output, "<TD ALIGN=CENTER><FONT COLOR=white>%s</FONT></TD>\n", acks[num].testname); if (acks[num].color != -1) { fprintf(output, "<TD ALIGN=CENTER><IMG SRC=\"%s/%s\"></TD>\n", xgetenv("BBSKIN"), dotgiffilename(acks[num].color, acks[num].ackvalid, 1)); } else fprintf(output, "<TD ALIGN=CENTER><FONT COLOR=white> </FONT></TD>\n"); fprintf(output, "<TD ALIGN=LEFT BGCOLOR=#000033>%s</TD>\n", acks[num].ackedby); fprintf(output, "<TD ALIGN=LEFT>%s</TD></TR>\n", acks[num].ackmsg); } } else { sprintf(title, "No events acknowledged in the last %u minutes", maxminutes); fprintf(output, "<BR><BR>\n"); fprintf(output, "<TABLE SUMMARY=\"%s\" BORDER=0>\n", title); fprintf(output, "<TR BGCOLOR=\"#333333\">\n"); fprintf(output, "<TD ALIGN=CENTER COLSPAN=6><FONT SIZE=-1 COLOR=\"#33ebf4\">%s</FONT></TD></TR>\n", title); } fprintf(output, "</TABLE>\n"); fclose(acklog); }
int web_access_allowed(char *username, char *hostname, char *testname, web_access_type_t acc) { void *hinfo; char *pages, *onepg, *key; hinfo = hostinfo(hostname); if (!hinfo || !acctree || !username) return 0; /* Check for "root" access first */ key = (char *)malloc(strlen(username) + 6); sprintf(key, "root %s", username); if (xtreeFind(acctree, key) != xtreeEnd(acctree)) { xfree(key); return 1; } xfree(key); pages = strdup(xmh_item(hinfo, XMH_ALLPAGEPATHS)); onepg = strtok(pages, ","); while (onepg) { char *p; p = strchr(onepg, '/'); if (p) *p = '\0'; /* Will only look at the top-level path element */ key = (char *)malloc(strlen(onepg) + strlen(username) + 2); sprintf(key, "%s %s", onepg, username); if (xtreeFind(acctree, key) != xtreeEnd(acctree)) { xfree(key); xfree(pages); return 1; } xfree(key); onepg = strtok(NULL, ","); } xfree(pages); if (hostname) { /* See if user is a member of a group named by the hostname */ key = (char *)malloc(strlen(hostname) + strlen(username) + 2); sprintf(key, "%s %s", hostname, username); if (xtreeFind(acctree, key) != xtreeEnd(acctree)) { xfree(key); return 1; } xfree(key); } if (testname) { /* See if user is a member of a group named by the testname */ key = (char *)malloc(strlen(testname) + strlen(username) + 2); sprintf(key, "%s %s", testname, username); if (xtreeFind(acctree, key) != xtreeEnd(acctree)) { xfree(key); return 1; } xfree(key); } return 0; }
int main(int argc, char *argv[]) { int argi; namelist_t *h; char *val; load_hostnames(argv[1], NULL, get_fqdn()); for (argi = 2; (argi < argc); argi++) { char s[1024]; char *p; char *hname; char hostip[IP_ADDR_STRLEN]; handlehost: hname = knownhost(argv[argi], hostip, 1); if (hname == NULL) { printf("Unknown host '%s'\n", argv[argi]); continue; } if (strcmp(hname, argv[argi])) { printf("Using canonical name '%s'\n", hname); } h = hostinfo(hname); if (h == NULL) { printf("Host %s not found\n", argv[argi]); continue; } val = bbh_item_walk(h); printf("Entry for host %s\n", h->bbhostname); while (val) { printf("\t%s\n", val); val = bbh_item_walk(NULL); } do { *s = '\0'; printf("Pick item:"); fflush(stdout); fgets(s, sizeof(s), stdin); p = strchr(s, '\n'); if (p) *p = '\0'; if (*s == '!') { load_hostnames(argv[1], NULL, get_fqdn()); /* Must restart! The "h" handle is no longer valid. */ goto handlehost; } else if (*s == '>') { val = bbh_item_multi(h, BBH_PAGEPATH); while (val) { printf("\t%s value is: '%s'\n", s, val); val = bbh_item_multi(NULL, BBH_PAGEPATH); } } else if (strncmp(s, "set ", 4) == 0) { bbh_set_item(h, BBH_DATA, strdup(s+4)); } else if (*s) { val = bbh_item_byname(h, s); if (val) printf("\t%s value is: '%s'\n", s, val); else printf("\t%s not found\n", s); } } while (*s); } return 0; }
void do_eventlog(FILE *output, int maxcount, int maxminutes, char *fromtime, char *totime, char *pageregex, char *expageregex, char *hostregex, char *exhostregex, char *testregex, char *extestregex, char *colrregex, int ignoredialups, f_hostcheck hostcheck, event_t **eventlist, countlist_t **hostcounts, countlist_t **servicecounts, countsummary_t counttype, eventsummary_t sumtype, char *periodstring) { FILE *eventlog; char eventlogfilename[PATH_MAX]; time_t firstevent = 0; time_t lastevent = getcurrenttime(NULL); event_t *eventhead = NULL; struct stat st; char l[MAX_LINE_LEN]; char title[200]; /* For the PCRE matching */ const char *errmsg = NULL; int errofs = 0; pcre *pageregexp = NULL; pcre *expageregexp = NULL; pcre *hostregexp = NULL; pcre *exhostregexp = NULL; pcre *testregexp = NULL; pcre *extestregexp = NULL; pcre *colrregexp = NULL; countlist_t *hostcounthead = NULL, *svccounthead = NULL; if (eventlist) *eventlist = NULL; if (hostcounts) *hostcounts = NULL; if (servicecounts) *servicecounts = NULL; havedoneeventlog = 1; if ((maxminutes > 0) && (fromtime || totime)) { fprintf(output, "<B>Only one time interval type is allowed!</B>"); return; } if (fromtime) { firstevent = eventreport_time(fromtime); if(firstevent < 0) { if (output) fprintf(output,"<B>Invalid 'from' time: %s</B>", htmlquoted(fromtime)); return; } } else if (maxminutes == -1) { /* Unlimited number of minutes */ firstevent = 0; } else if (maxminutes > 0) { firstevent = getcurrenttime(NULL) - maxminutes*60; } else { firstevent = getcurrenttime(NULL) - 86400; } if (totime) { lastevent = eventreport_time(totime); if (lastevent < 0) { if (output) fprintf(output,"<B>Invalid 'to' time: %s</B>", htmlquoted(totime)); return; } if (lastevent < firstevent) { if (output) fprintf(output,"<B>'to' time must be after 'from' time.</B>"); return; } } if (!maxcount) maxcount = 100; if (pageregex && *pageregex) pageregexp = pcre_compile(pageregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (expageregex && *expageregex) expageregexp = pcre_compile(expageregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (hostregex && *hostregex) hostregexp = pcre_compile(hostregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (exhostregex && *exhostregex) exhostregexp = pcre_compile(exhostregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (testregex && *testregex) testregexp = pcre_compile(testregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (extestregex && *extestregex) extestregexp = pcre_compile(extestregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (colrregex && *colrregex) colrregexp = pcre_compile(colrregex, PCRE_CASELESS, &errmsg, &errofs, NULL); sprintf(eventlogfilename, "%s/allevents", xgetenv("XYMONHISTDIR")); eventlog = fopen(eventlogfilename, "r"); if (eventlog && (stat(eventlogfilename, &st) == 0)) { time_t curtime; int done = 0; int unlimited = (maxcount == -1); if (unlimited) maxcount = 1000; do { /* Find a spot in the eventlog file close to where the firstevent time is */ fseeko(eventlog, 0, SEEK_END); do { /* Go back maxcount*80 bytes - one entry is ~80 bytes */ if (ftello(eventlog) > maxcount*80) { unsigned int uicurtime; fseeko(eventlog, -maxcount*80, SEEK_CUR); if (fgets(l, sizeof(l), eventlog) && /* Skip to start of line */ fgets(l, sizeof(l), eventlog)) { sscanf(l, "%*s %*s %u %*u %*u %*s %*s %*d", &uicurtime); curtime = uicurtime; done = (curtime < firstevent); if (unlimited && !done) maxcount += 1000; } else { if (output) fprintf(output,"Error reading eventlog file %s: %s\n", eventlogfilename, strerror(errno)); return; } } else { rewind(eventlog); curtime = 0; done = 1; } } while (!done); if (unlimited) unlimited = ((curtime > firstevent) && (ftello(eventlog) > 0)); } while (unlimited); } eventhead = NULL; while (eventlog && (fgets(l, sizeof(l), eventlog))) { time_t eventtime, changetime, duration; unsigned int uievt, uicht, uidur; char hostname[MAX_LINE_LEN], svcname[MAX_LINE_LEN], newcol[MAX_LINE_LEN], oldcol[MAX_LINE_LEN]; char *newcolname, *oldcolname; int state, itemsfound, colrmatch; event_t *newevent; void *eventhost; struct htnames_t *eventcolumn; int ovector[30]; eventcount_t *countrec; itemsfound = sscanf(l, "%s %s %u %u %u %s %s %d", hostname, svcname, &uievt, &uicht, &uidur, newcol, oldcol, &state); eventtime = uievt; changetime = uicht; duration = uidur; oldcolname = colorname(eventcolor(oldcol)); newcolname = colorname(eventcolor(newcol)); /* For DURATION counts, we must parse all events until now */ if ((counttype != XYMON_COUNT_DURATION) && (eventtime > lastevent)) break; eventhost = hostinfo(hostname); eventcolumn = getname(svcname, 1); if ( (itemsfound == 8) && (eventtime >= firstevent) && (eventhost && !xmh_item(eventhost, XMH_FLAG_NONONGREEN)) && (wanted_eventcolumn(svcname)) ) { if (eventfilter(eventhost, svcname, pageregexp, expageregexp, hostregexp, exhostregexp, testregexp, extestregexp, ignoredialups, hostcheck) == 0) continue; /* For duration counts, record all events. We'll filter out the colors later. */ if (colrregexp && (counttype != XYMON_COUNT_DURATION)) { colrmatch = ( (pcre_exec(colrregexp, NULL, newcolname, strlen(newcolname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0) || (pcre_exec(colrregexp, NULL, oldcolname, strlen(oldcolname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0) ); } else colrmatch = 1; if (!colrmatch) continue; newevent = (event_t *) malloc(sizeof(event_t)); newevent->host = eventhost; newevent->service = eventcolumn; newevent->eventtime = eventtime; newevent->changetime = changetime; newevent->duration = duration; newevent->newcolor = eventcolor(newcol); newevent->oldcolor = eventcolor(oldcol); newevent->next = eventhead; eventhead = newevent; if (counttype != XYMON_COUNT_DURATION) { countrec = (eventcount_t *)xmh_item(eventhost, XMH_DATA); while (countrec && (countrec->service != eventcolumn)) countrec = countrec->next; if (countrec == NULL) { countrec = (eventcount_t *)calloc(1, sizeof(eventcount_t)); countrec->service = eventcolumn; countrec->next = (eventcount_t *)xmh_item(eventhost, XMH_DATA); xmh_set_item(eventhost, XMH_DATA, (void *)countrec); } countrec->count++; } } } /* Count the state changes per host */ svccounthead = hostcounthead = NULL; switch (counttype) { case XYMON_COUNT_EVENTS: count_events(&hostcounthead, &svccounthead); break; case XYMON_COUNT_DURATION: count_duration(firstevent, lastevent, pageregexp, expageregexp, hostregexp, exhostregexp, testregexp, extestregexp, ignoredialups, hostcheck, eventhead, &hostcounthead, &svccounthead); break; default: break; } if (hostcounthead) hostcounthead = msort(hostcounthead, record_compare, record_getnext, record_setnext); if (svccounthead) svccounthead = msort(svccounthead, record_compare, record_getnext, record_setnext); if (eventhead && (output != NULL)) { char *bgcolors[2] = { "#000000", "#000033" }; int bgcolor = 0; struct event_t *ewalk, *lasttoshow = eventhead; countlist_t *cwalk; unsigned long totalcount = 0; if (periodstring) fprintf(output, "<p><font size=+1>%s</font></p>\n", htmlquoted(periodstring)); switch (sumtype) { case XYMON_S_HOST_BREAKDOWN: /* Request for a specific service, show breakdown by host */ for (cwalk = hostcounthead; (cwalk); cwalk = cwalk->next) totalcount += cwalk->total; fprintf(output, "<table summary=\"Breakdown by host\" border=0>\n"); fprintf(output, "<tr><th align=left>Host</th><th colspan=2>%s</th></tr>\n", (counttype == XYMON_COUNT_EVENTS) ? "State changes" : "Seconds red/yellow"); fprintf(output, "<tr><td colspan=3><hr width=\"100%%\"></td></tr>\n"); for (cwalk = hostcounthead; (cwalk && (cwalk->total > 0)); cwalk = cwalk->next) { fprintf(output, "<tr><td align=left>%s</td><td align=right>%lu</td><td align=right>(%6.2f %%)</tr>\n", xmh_item(cwalk->src, XMH_HOSTNAME), cwalk->total, ((100.0 * cwalk->total) / totalcount)); } fprintf(output, "</table>\n"); break; case XYMON_S_SERVICE_BREAKDOWN: /* Request for a specific host, show breakdown by service */ for (cwalk = svccounthead; (cwalk); cwalk = cwalk->next) totalcount += cwalk->total; fprintf(output, "<table summary=\"Breakdown by service\" border=0>\n"); fprintf(output, "<tr><th align=left>Service</th><th colspan=2>%s</th></tr>\n", (counttype == XYMON_COUNT_EVENTS) ? "State changes" : "Seconds red/yellow"); fprintf(output, "<tr><td colspan=3><hr width=\"100%%\"></td></tr>\n"); for (cwalk = svccounthead; (cwalk && (cwalk->total > 0)); cwalk = cwalk->next) { fprintf(output, "<tr><td align=left>%s</td><td align=right>%lu</td><td align=right>(%6.2f %%)</tr>\n", ((htnames_t *)cwalk->src)->name, cwalk->total, ((100.0 * cwalk->total) / totalcount)); } fprintf(output, "</table>\n"); break; case XYMON_S_NONE: break; } if (sumtype == XYMON_S_NONE) { int count; count=0; ewalk=eventhead; do { count++; lasttoshow = ewalk; ewalk = ewalk->next; } while (ewalk && (count<maxcount)); if (ewalk) ewalk->next = NULL; /* Terminate list if any items left */ if (maxminutes > 0) { sprintf(title, "%d events received in the past %u minutes", count, (unsigned int)((getcurrenttime(NULL) - lasttoshow->eventtime) / 60)); } else { sprintf(title, "%d events received.", count); } } else { strcpy(title, "Events in summary"); } fprintf(output, "<BR><BR>\n"); fprintf(output, "<TABLE SUMMARY=\"$EVENTSTITLE\" BORDER=0>\n"); fprintf(output, "<TR BGCOLOR=\"#333333\">\n"); fprintf(output, "<TD ALIGN=CENTER COLSPAN=6><FONT SIZE=-1 COLOR=\"#33ebf4\">%s</FONT></TD></TR>\n", htmlquoted(title)); for (ewalk=eventhead; (ewalk); ewalk=ewalk->next) { char *hostname = xmh_item(ewalk->host, XMH_HOSTNAME); if ( (counttype == XYMON_COUNT_DURATION) && (ewalk->oldcolor < COL_YELLOW) && (ewalk->newcolor < COL_YELLOW) ) continue; if ( (counttype == XYMON_COUNT_DURATION) && (ewalk->eventtime >= lastevent) ) continue; fprintf(output, "<TR BGCOLOR=%s>\n", bgcolors[bgcolor]); bgcolor = ((bgcolor + 1) % 2); fprintf(output, "<TD ALIGN=CENTER>%s</TD>\n", ctime(&ewalk->eventtime)); if (ewalk->newcolor == COL_CLEAR) { fprintf(output, "<TD ALIGN=CENTER BGCOLOR=black><FONT COLOR=white>%s</FONT></TD>\n", hostname); } else { fprintf(output, "<TD ALIGN=CENTER BGCOLOR=%s><FONT COLOR=black>%s</FONT></TD>\n", colorname(ewalk->newcolor), hostname); } fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", ewalk->service->name); fprintf(output, "<TD><A HREF=\"%s\">\n", histlogurl(hostname, ewalk->service->name, ewalk->changetime, NULL)); fprintf(output, "<IMG SRC=\"%s/%s\" HEIGHT=\"%s\" WIDTH=\"%s\" BORDER=0 ALT=\"%s\" TITLE=\"%s\"></A>\n", xgetenv("XYMONSKIN"), dotgiffilename(ewalk->oldcolor, 0, 0), xgetenv("DOTHEIGHT"), xgetenv("DOTWIDTH"), colorname(ewalk->oldcolor), colorname(ewalk->oldcolor)); fprintf(output, "<IMG SRC=\"%s/arrow.gif\" BORDER=0 ALT=\"From -> To\">\n", xgetenv("XYMONSKIN")); fprintf(output, "<TD><A HREF=\"%s\">\n", histlogurl(hostname, ewalk->service->name, ewalk->eventtime, NULL)); fprintf(output, "<IMG SRC=\"%s/%s\" HEIGHT=\"%s\" WIDTH=\"%s\" BORDER=0 ALT=\"%s\" TITLE=\"%s\"></A></TD>\n", xgetenv("XYMONSKIN"), dotgiffilename(ewalk->newcolor, 0, 0), xgetenv("DOTHEIGHT"), xgetenv("DOTWIDTH"), colorname(ewalk->newcolor), colorname(ewalk->newcolor)); fprintf(output, "</TR>\n"); } fprintf(output, "</TABLE>\n"); } else if (output != NULL) { /* No events during the past maxminutes */ if (eventlog) sprintf(title, "No events received in the last %d minutes", maxminutes); else strcpy(title, "No events logged"); fprintf(output, "<CENTER><BR>\n"); fprintf(output, "<TABLE SUMMARY=\"%s\" BORDER=0>\n", title); fprintf(output, "<TR BGCOLOR=\"#333333\">\n"); fprintf(output, "<TD ALIGN=CENTER COLSPAN=6><FONT SIZE=-1 COLOR=\"#33ebf4\">%s</FONT></TD>\n", htmlquoted(title)); fprintf(output, "</TR>\n"); fprintf(output, "</TABLE>\n"); fprintf(output, "</CENTER>\n"); } if (eventlog) fclose(eventlog); if (pageregexp) pcre_free(pageregexp); if (hostregexp) pcre_free(hostregexp); if (testregexp) pcre_free(testregexp); if (colrregexp) pcre_free(colrregexp); /* Return the event- and count-lists, if wanted - or clean them up */ if (eventlist) { *eventlist = eventhead; } else { event_t *zombie, *ewalk = eventhead; while (ewalk) { zombie = ewalk; ewalk = ewalk->next; xfree(zombie); } } if (hostcounts) { *hostcounts = hostcounthead; } else { countlist_t *zombie, *hwalk = hostcounthead; while (hwalk) { zombie = hwalk; hwalk = hwalk->next; xfree(zombie); } } if (servicecounts) { *servicecounts = svccounthead; } else { countlist_t *zombie, *swalk = svccounthead; while (swalk) { zombie = swalk; swalk = swalk->next; xfree(zombie); } } }
int loadstatus(int maxprio, time_t maxage, int mincolor, int wantacked) { int xymondresult; char *board = NULL; char *bol, *eol; time_t now; char msg[1024]; int i; sendreturn_t *sres; sprintf(msg, "xymondboard acklevel=%d fields=hostname,testname,color,lastchange,logtime,validtime,acklist color=%s", critacklevel,colorname(mincolor)); for (i=mincolor+1; (i < COL_COUNT); i++) sprintf(msg+strlen(msg), ",%s", colorname(i)); sres = newsendreturnbuf(1, NULL); xymondresult = sendmessage(msg, NULL, XYMON_TIMEOUT, sres); if (xymondresult != XYMONSEND_OK) { freesendreturnbuf(sres); errormsg("Unable to fetch current status\n"); return 1; } else { board = getsendreturnstr(sres, 1); freesendreturnbuf(sres); } now = getcurrenttime(NULL); rbstate = rbtNew(name_compare); bol = board; while (bol && (*bol)) { char *endkey; RbtStatus status; eol = strchr(bol, '\n'); if (eol) *eol = '\0'; /* Find the config entry */ endkey = strchr(bol, '|'); if (endkey) endkey = strchr(endkey+1, '|'); if (endkey) { critconf_t *cfg; char *ackstr, *ackrtimestr, *ackvtimestr, *acklevelstr, *ackbystr, *ackmsgstr; *endkey = '\0'; cfg = get_critconfig(bol, CRITCONF_TIMEFILTER, NULL); *endkey = '|'; if (cfg) { hstatus_t *newitem = (hstatus_t *)calloc(1, sizeof(hstatus_t)); newitem->config = cfg; newitem->hostname = gettok(bol, "|"); newitem->testname = gettok(NULL, "|"); newitem->color = parse_color(gettok(NULL, "|")); newitem->lastchange = atoi(gettok(NULL, "|")); newitem->logtime = atoi(gettok(NULL, "|")); newitem->validtime = atoi(gettok(NULL, "|")); ackstr = gettok(NULL, "|"); ackrtimestr = ackvtimestr = acklevelstr = ackbystr = ackmsgstr = NULL; if (ackstr) { nldecode(ackstr); ackrtimestr = strtok(ackstr, ":"); if (ackrtimestr) ackvtimestr = strtok(NULL, ":"); if (ackvtimestr) acklevelstr = strtok(NULL, ":"); if (acklevelstr) ackbystr = strtok(NULL, ":"); if (ackbystr) ackmsgstr = strtok(NULL, ":"); } if ( (hostinfo(newitem->hostname) == NULL) || (newitem->config->priority > maxprio) || ((now - newitem->lastchange) > maxage) || (newitem->color < mincolor) || (ackmsgstr && !wantacked) ) { xfree(newitem); } else { if (ackvtimestr && ackbystr && ackmsgstr) { newitem->acktime = atoi(ackvtimestr); newitem->ackedby = strdup(ackbystr); newitem->ackmsg = strdup(ackmsgstr); } newitem->key = (char *)malloc(strlen(newitem->hostname) + strlen(newitem->testname) + 2); sprintf(newitem->key, "%s|%s", newitem->hostname, newitem->testname); status = rbtInsert(rbstate, newitem->key, newitem); } } } bol = (eol ? (eol+1) : NULL); } return 0; }
void send_alert(activealerts_t *alert, FILE *logfd) { recip_t *recip; int first = 1; int alertcount = 0; time_t now = getcurrenttime(NULL); /* A_PAGING, A_NORECIP, A_ACKED, A_RECOVERED, A_DISABLED, A_NOTIFY, A_DEAD */ char *alerttxt[A_DEAD+1] = { "Paging", "Norecip", "Acked", "Recovered", "Disabled", "Notify", "Dead" }; dbgprintf("send_alert %s:%s state %d\n", alert->hostname, alert->testname, (int)alert->state); traceprintf("send_alert %s:%s state %s\n", alert->hostname, alert->testname, alerttxt[alert->state]); stoprulefound = 0; while (!stoprulefound && ((recip = next_recipient(alert, &first, NULL, NULL)) != NULL)) { /* If this is an "UNMATCHED" rule, ignore it if we have already sent out some alert */ if (recip->unmatchedonly && (alertcount != 0)) { traceprintf("Recipient '%s' dropped, not unmatched (count=%d)\n", recip->recipient, alertcount); continue; } if (recip->noalerts && ((alert->state == A_PAGING) || (alert->state == A_RECOVERED) || (alert->state == A_DISABLED))) { traceprintf("Recipient '%s' dropped (NOALERT)\n", recip->recipient); continue; } if (recip->method == M_IGNORE) { traceprintf("IGNORE rule found\n"); continue; } if (alert->state == A_PAGING) { repeat_t *rpt = NULL; /* * This runs in a child-process context, so the record we * might create here is NOT used later on. */ rpt = find_repeatinfo(alert, recip, 1); if (!rpt) continue; /* Happens for e.g. M_IGNORE recipients */ dbgprintf(" repeat %s at %d\n", rpt->recipid, rpt->nextalert); if (rpt->nextalert > now) { traceprintf("Recipient '%s' dropped, next alert due at %ld > %ld\n", rpt->recipid, (long)rpt->nextalert, (long)now); continue; } alertcount++; } else if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) { /* RECOVERED messages require that we've sent out an alert before */ repeat_t *rpt = NULL; rpt = find_repeatinfo(alert, recip, 0); if (!rpt) continue; alertcount++; } dbgprintf(" Alert for %s:%s to %s\n", alert->hostname, alert->testname, recip->recipient); switch (recip->method) { case M_IGNORE: break; case M_MAIL: { char cmd[32768]; char *mailsubj; char *mailrecip; FILE *mailpipe; MEMDEFINE(cmd); mailsubj = message_subject(alert, recip); mailrecip = message_recipient(recip->recipient, alert->hostname, alert->testname, colorname(alert->color)); if (mailsubj) { if (xgetenv("MAIL")) sprintf(cmd, "%s \"%s\" ", xgetenv("MAIL"), mailsubj); else if (xgetenv("MAILC")) sprintf(cmd, "%s -s \"%s\" ", xgetenv("MAILC"), mailsubj); else sprintf(cmd, "mail -s \"%s\" ", mailsubj); } else { if (xgetenv("MAILC")) sprintf(cmd, "%s ", xgetenv("MAILC")); else sprintf(cmd, "mail "); } strcat(cmd, mailrecip); traceprintf("Mail alert with command '%s'\n", cmd); if (testonly) { MEMUNDEFINE(cmd); break; } mailpipe = popen(cmd, "w"); if (mailpipe) { fprintf(mailpipe, "%s", message_text(alert, recip)); pclose(mailpipe); if (logfd) { init_timestamp(); fprintf(logfd, "%s %s.%s (%s) %s[%d] %ld %d", timestamp, alert->hostname, alert->testname, alert->ip, mailrecip, recip->cfid, (long)now, servicecode(alert->testname)); if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) { fprintf(logfd, " %ld\n", (long)(now - alert->eventstart)); } else { fprintf(logfd, "\n"); } fflush(logfd); } } else { errprintf("ERROR: Cannot open command pipe for '%s' - alert lost!\n", cmd); traceprintf("Mail pipe failed - alert lost\n"); } MEMUNDEFINE(cmd); } break; case M_SCRIPT: { pid_t scriptpid; char *scriptrecip; traceprintf("Script alert with command '%s' and recipient %s\n", recip->scriptname, recip->recipient); if (testonly) break; scriptrecip = message_recipient(recip->recipient, alert->hostname, alert->testname, colorname(alert->color)); scriptpid = fork(); if (scriptpid == 0) { /* Setup all of the environment for a paging script */ void *hinfo; char *p; int ip1=0, ip2=0, ip3=0, ip4=0; char *bbalphamsg, *ackcode, *rcpt, *bbhostname, *bbhostsvc, *bbhostsvccommas, *bbnumeric, *machip, *bbsvcname, *bbsvcnum, *bbcolorlevel, *recovered, *downsecs, *eventtstamp, *downsecsmsg, *cfidtxt; char *alertid, *alertidenv; int msglen; cfidtxt = (char *)malloc(strlen("CFID=") + 10); sprintf(cfidtxt, "CFID=%d", recip->cfid); putenv(cfidtxt); p = message_text(alert, recip); msglen = strlen(p); if (msglen > MAX_ALERTMSG_SCRIPTS) { dbgprintf("Cropping large alert message from %d to %d bytes\n", msglen, MAX_ALERTMSG_SCRIPTS); msglen = MAX_ALERTMSG_SCRIPTS; } msglen += strlen("BBALPHAMSG="); bbalphamsg = (char *)malloc(msglen + 1); snprintf(bbalphamsg, msglen+1, "BBALPHAMSG=%s", p); putenv(bbalphamsg); ackcode = (char *)malloc(strlen("ACKCODE=") + 10); sprintf(ackcode, "ACKCODE=%d", alert->cookie); putenv(ackcode); rcpt = (char *)malloc(strlen("RCPT=") + strlen(scriptrecip) + 1); sprintf(rcpt, "RCPT=%s", scriptrecip); putenv(rcpt); bbhostname = (char *)malloc(strlen("BBHOSTNAME=") + strlen(alert->hostname) + 1); sprintf(bbhostname, "BBHOSTNAME=%s", alert->hostname); putenv(bbhostname); bbhostsvc = (char *)malloc(strlen("BBHOSTSVC=") + strlen(alert->hostname) + 1 + strlen(alert->testname) + 1); sprintf(bbhostsvc, "BBHOSTSVC=%s.%s", alert->hostname, alert->testname); putenv(bbhostsvc); bbhostsvccommas = (char *)malloc(strlen("BBHOSTSVCCOMMAS=") + strlen(alert->hostname) + 1 + strlen(alert->testname) + 1); sprintf(bbhostsvccommas, "BBHOSTSVCCOMMAS=%s.%s", commafy(alert->hostname), alert->testname); putenv(bbhostsvccommas); bbnumeric = (char *)malloc(strlen("BBNUMERIC=") + 22 + 1); p = bbnumeric; p += sprintf(p, "BBNUMERIC="); p += sprintf(p, "%03d", servicecode(alert->testname)); sscanf(alert->ip, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4); p += sprintf(p, "%03d%03d%03d%03d", ip1, ip2, ip3, ip4); p += sprintf(p, "%d", alert->cookie); putenv(bbnumeric); machip = (char *)malloc(strlen("MACHIP=") + 13); sprintf(machip, "MACHIP=%03d%03d%03d%03d", ip1, ip2, ip3, ip4); putenv(machip); bbsvcname = (char *)malloc(strlen("BBSVCNAME=") + strlen(alert->testname) + 1); sprintf(bbsvcname, "BBSVCNAME=%s", alert->testname); putenv(bbsvcname); bbsvcnum = (char *)malloc(strlen("BBSVCNUM=") + 10); sprintf(bbsvcnum, "BBSVCNUM=%d", servicecode(alert->testname)); putenv(bbsvcnum); bbcolorlevel = (char *)malloc(strlen("BBCOLORLEVEL=") + strlen(colorname(alert->color)) + 1); sprintf(bbcolorlevel, "BBCOLORLEVEL=%s", colorname(alert->color)); putenv(bbcolorlevel); recovered = (char *)malloc(strlen("RECOVERED=") + 2); switch (alert->state) { case A_RECOVERED: strcpy(recovered, "RECOVERED=1"); break; case A_DISABLED: strcpy(recovered, "RECOVERED=2"); break; default: strcpy(recovered, "RECOVERED=0"); break; } putenv(recovered); downsecs = (char *)malloc(strlen("DOWNSECS=") + 20); sprintf(downsecs, "DOWNSECS=%ld", (long)(getcurrenttime(NULL) - alert->eventstart)); putenv(downsecs); eventtstamp = (char *)malloc(strlen("EVENTSTART=") + 20); sprintf(eventtstamp, "EVENTSTART=%ld", (long)alert->eventstart); putenv(eventtstamp); if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) { downsecsmsg = (char *)malloc(strlen("DOWNSECSMSG=Event duration :") + 20); sprintf(downsecsmsg, "DOWNSECSMSG=Event duration : %ld", (long)(getcurrenttime(NULL) - alert->eventstart)); } else { downsecsmsg = strdup("DOWNSECSMSG="); } putenv(downsecsmsg); alertid = make_alertid(alert->hostname, alert->testname, alert->eventstart); alertidenv = (char *)malloc(strlen("ALERTID=") + strlen(alertid) + 10); sprintf(alertidenv, "ALERTID=%s", alertid); putenv(alertidenv); hinfo = hostinfo(alert->hostname); if (hinfo) { enum xmh_item_t walk; char *itm, *id, *bbhenv; for (walk = 0; (walk < XMH_LAST); walk++) { itm = xmh_item(hinfo, walk); id = xmh_item_id(walk); if (itm && id) { bbhenv = (char *)malloc(strlen(id) + strlen(itm) + 2); sprintf(bbhenv, "%s=%s", id, itm); putenv(bbhenv); } } } /* The child starts the script */ execlp(recip->scriptname, recip->scriptname, NULL); errprintf("Could not launch paging script %s: %s\n", recip->scriptname, strerror(errno)); exit(0); } else if (scriptpid > 0) { /* Parent waits for child to complete */ int childstat; wait(&childstat); if (WIFEXITED(childstat) && (WEXITSTATUS(childstat) != 0)) { errprintf("Paging script %s terminated with status %d\n", recip->scriptname, WEXITSTATUS(childstat)); } else if (WIFSIGNALED(childstat)) { errprintf("Paging script %s terminated by signal %d\n", recip->scriptname, WTERMSIG(childstat)); } if (logfd) { init_timestamp(); fprintf(logfd, "%s %s.%s (%s) %s %ld %d", timestamp, alert->hostname, alert->testname, alert->ip, scriptrecip, (long)now, servicecode(alert->testname)); if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) { fprintf(logfd, " %ld\n", (long)(now - alert->eventstart)); } else { fprintf(logfd, "\n"); } fflush(logfd); } } else { errprintf("ERROR: Fork failed to launch script '%s' - alert lost\n", recip->scriptname); traceprintf("Script fork failed - alert lost\n"); } } break; } } }
static void count_duration(time_t fromtime, time_t totime, pcre *pageregexp, pcre *expageregexp, pcre *hostregexp, pcre *exhostregexp, pcre *testregexp, pcre *extestregexp, int ignoredialups, f_hostcheck hostcheck, event_t *eventhead, countlist_t **hostcounthead, countlist_t **svccounthead) { void *hwalk; elist_t *lwalk; event_t *ewalk; ed_t *ed; sendreturn_t *bdata; /* * Restructure the event-list so we have a tree instead: * * HostRecord * | *Data ----> EventList * | | *Service * | | *EventHead --> Event --> Event --> Event * | | *EventTail --------------------------^ * | | * | v * | * v * */ for (ewalk = eventhead; (ewalk); ewalk = ewalk->next) { lwalk = (elist_t *)xmh_item(ewalk->host, XMH_DATA); while (lwalk && (lwalk->svc != ewalk->service)) lwalk = lwalk->next; if (lwalk == NULL) { lwalk = (elist_t *)calloc(1, sizeof(elist_t)); lwalk->svc = ewalk->service; lwalk->next = (elist_t *)xmh_item(ewalk->host, XMH_DATA); xmh_set_item(ewalk->host, XMH_DATA, (void *)lwalk); } ed = (ed_t *)calloc(1, sizeof(ed_t)); ed->event = ewalk; ed->next = lwalk->head; if (lwalk->head == NULL) lwalk->tail = ed; lwalk->head = ed; } if (debug) { printf("\n\nEventtree before fixups\n\n"); dump_eventtree(); } /* * Next, we must add a pseudo record for the current state. * This is for those statuses that haven't changed since the * start of our data-collection period - they won't have any events * so we cannot tell what color they are. By grabbing the current * color we can add a pseudo-event that lets us determine what the * color has been since the start of the event-period. */ bdata = newsendreturnbuf(1, NULL); if (sendmessage("xymondboard fields=hostname,testname,color,lastchange", NULL, XYMON_TIMEOUT, bdata) == XYMONSEND_OK) { char *bol, *eol; char *hname, *tname; int color; time_t lastchange; void *hrec; htnames_t *srec; char *icname = xgetenv("INFOCOLUMN"); char *tcname = xgetenv("TRENDSCOLUMN"); bol = getsendreturnstr(bdata, 0); while (bol) { eol = strchr(bol, '\n'); if (eol) *eol = '\0'; hname = strtok(bol, "|"); tname = (hname ? strtok(NULL, "|") : NULL); color = (tname ? parse_color(strtok(NULL, "|")) : -1); lastchange = ((color != -1) ? atol(strtok(NULL, "\n")) : totime+1); if (hname && tname && (color != -1) && (strcmp(tname, icname) != 0) && (strcmp(tname, tcname) != 0)) { hrec = hostinfo(hname); srec = getname(tname, 1); if (eventfilter(hrec, tname, pageregexp, expageregexp, hostregexp, exhostregexp, testregexp, extestregexp, ignoredialups, hostcheck) == 0) goto nextrecord; lwalk = (elist_t *)xmh_item(hrec, XMH_DATA); while (lwalk && (lwalk->svc != srec)) lwalk = lwalk->next; if (lwalk == NULL) { lwalk = (elist_t *)calloc(1, sizeof(elist_t)); lwalk->svc = srec; lwalk->next = (elist_t *)xmh_item(hrec, XMH_DATA); xmh_set_item(hrec, XMH_DATA, (void *)lwalk); } /* See if we already have an event past the "totime" value */ if (lwalk->head) { ed = lwalk->head; while (ed && (ed->event->eventtime < totime)) ed = ed->next; if (ed) { ed->next = NULL; lwalk->tail = ed; } else { ed = (ed_t *)calloc(1, sizeof(ed_t)); ed->event = (event_t *)calloc(1, sizeof(event_t)); lwalk->tail->next = ed; ed->event->host = hrec; ed->event->service = srec; ed->event->eventtime = totime; ed->event->changetime = lwalk->tail->event->eventtime; ed->event->duration = (totime - lwalk->tail->event->eventtime); ed->event->newcolor = -1; ed->event->oldcolor = lwalk->tail->event->newcolor; ed->event->next = NULL; ed->next = NULL; lwalk->tail = ed; } } else if (lastchange < totime) { ed = (ed_t *)calloc(1, sizeof(ed_t)); ed->event = (event_t *)calloc(1, sizeof(event_t)); ed->event->host = hrec; ed->event->service = srec; ed->event->eventtime = totime; ed->event->changetime = (lwalk->tail ? lwalk->tail->event->eventtime : fromtime); ed->event->duration = (totime - ed->event->changetime); ed->event->newcolor = color; ed->event->oldcolor = (lwalk->tail ? lwalk->tail->event->newcolor : color); ed->event->next = NULL; ed->next = NULL; lwalk->head = lwalk->tail = ed; } } nextrecord: bol = (eol ? eol+1 : NULL); } freesendreturnbuf(bdata); } else { errprintf("Cannot get the current state\n"); freesendreturnbuf(bdata); return; } if (debug) { printf("\n\nEventtree after pseudo-events\n\n"); dump_eventtree(); } /* * Fixup the beginning-time (and duration) of the first events recorded. * This is to handle events that begin BEFORE our event-logging period. * Fixup the end-time (and duration) of the last events recorded. * This is to handle events that end AFTER our event-logging period. */ for (hwalk = first_host(); (hwalk); hwalk = next_host(hwalk, 0)) { elist_t *lwalk; event_t *erec; ed_t *ewalk; lwalk = (elist_t *)xmh_item(hwalk, XMH_DATA); while (lwalk) { if (lwalk->head) { erec = lwalk->head->event; if (erec->changetime > totime) { /* First event is after our start-time. Drop the events */ lwalk->head = lwalk->tail = NULL; } else if (erec->changetime < fromtime) { /* First event is before our start-time. Adjust to starttime. */ erec->changetime = fromtime; erec->duration = (erec->eventtime - fromtime); } ewalk = lwalk->head; while (ewalk && (ewalk->event->eventtime < totime)) ewalk = ewalk->next; if (ewalk) { lwalk->tail = ewalk; lwalk->tail->next = 0; } if (lwalk->tail) { erec = lwalk->tail->event; if (erec->eventtime > totime) { /* Last event is after our end-time. Adjust to end-time */ erec->eventtime = totime; erec->duration = (totime - erec->changetime); } } } lwalk = lwalk->next; } } if (debug) { printf("\n\nEventtree after fixups\n\n"); dump_eventtree(); } for (hwalk = first_host(); (hwalk); hwalk = next_host(hwalk, 0)) { countlist_t *hrec, *srec; hrec = (countlist_t *)malloc(sizeof(countlist_t)); hrec->src = hwalk; hrec->total = 0; hrec->next = *hostcounthead; *hostcounthead = hrec; lwalk = (elist_t *)xmh_item(hwalk, XMH_DATA); while (lwalk) { for (srec = *svccounthead; (srec && (srec->src != (void *)lwalk->svc)); srec = srec->next) ; if (!srec) { srec = (countlist_t *)malloc(sizeof(countlist_t)); srec->src = (void *)lwalk->svc; srec->total = 0; srec->next = *svccounthead; *svccounthead = srec; } if (lwalk->head) { ed_t *ewalk = lwalk->head; while (ewalk) { if (ewalk->event->oldcolor >= COL_YELLOW) { hrec->total += ewalk->event->duration; srec->total += ewalk->event->duration; } ewalk = ewalk->next; } } lwalk = lwalk->next; } } if (debug) dump_countlists(*hostcounthead, *svccounthead); }
void do_acknowledgementslog(FILE *output, int maxcount, int maxminutes, char *fromtime, char *totime, char *pageregex, char *expageregex, char *hostregex, char *exhostregex, char *testregex, char *extestregex, char *rcptregex, char *exrcptregex) { FILE *acknowledgementslog; char acknowledgementslogfilename[PATH_MAX]; time_t firstevent = 0; time_t lastevent = getcurrenttime(NULL); acknowledgements_t *head, *walk; struct stat st; char l[MAX_LINE_LEN]; char title[200]; /* For the PCRE matching */ const char *errmsg = NULL; int errofs = 0; pcre *pageregexp = NULL; pcre *expageregexp = NULL; pcre *hostregexp = NULL; pcre *exhostregexp = NULL; pcre *testregexp = NULL; pcre *extestregexp = NULL; pcre *rcptregexp = NULL; pcre *exrcptregexp = NULL; if (maxminutes && (fromtime || totime)) { fprintf(output, "<B>Only one time interval type is allowed!</B>"); return; } if (fromtime) { firstevent = convert_time(fromtime); if(firstevent < 0) { fprintf(output,"<B>Invalid 'from' time: %s</B>", htmlquoted(fromtime)); return; } } else if (maxminutes) { firstevent = getcurrenttime(NULL) - maxminutes*60; } else { firstevent = getcurrenttime(NULL) - 86400; } if (totime) { lastevent = convert_time(totime); if (lastevent < 0) { fprintf(output,"<B>Invalid 'to' time: %s</B>", htmlquoted(totime)); return; } if (lastevent < firstevent) { fprintf(output,"<B>'to' time must be after 'from' time.</B>"); return; } } if (!maxcount) maxcount = 100; if (pageregex && *pageregex) pageregexp = pcre_compile(pageregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (expageregex && *expageregex) expageregexp = pcre_compile(expageregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (hostregex && *hostregex) hostregexp = pcre_compile(hostregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (exhostregex && *exhostregex) exhostregexp = pcre_compile(exhostregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (testregex && *testregex) testregexp = pcre_compile(testregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (extestregex && *extestregex) extestregexp = pcre_compile(extestregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (rcptregex && *rcptregex) rcptregexp = pcre_compile(rcptregex, PCRE_CASELESS, &errmsg, &errofs, NULL); if (exrcptregex && *exrcptregex) exrcptregexp = pcre_compile(exrcptregex, PCRE_CASELESS, &errmsg, &errofs, NULL); sprintf(acknowledgementslogfilename, "%s/acknowledge.log", xgetenv("XYMONSERVERLOGS")); acknowledgementslog = fopen(acknowledgementslogfilename, "r"); if (acknowledgementslog && (stat(acknowledgementslogfilename, &st) == 0)) { time_t curtime; int done = 0; /* Find a spot in the acknowledgements log file close to where the firstevent time is */ fseeko(acknowledgementslog, 0, SEEK_END); do { /* Go back maxcount*80 bytes - one entry is ~80 bytes */ if (ftello(acknowledgementslog) > maxcount*80) { unsigned int uicurtime; fseeko(acknowledgementslog, -maxcount*80, SEEK_CUR); if (fgets(l, sizeof(l), acknowledgementslog) && /* Skip to start of line */ fgets(l, sizeof(l), acknowledgementslog)) { /* 2015-03-07 18:17:03 myserver disk andy 1 1425724570 1425752223 1425838623 testing message */ if ( sscanf(l, "%*u-%*u-%*u %*u:%*u:%*u %*s %*s %*s %*u %*u %u %*u %*s", &uicurtime) == 0 ) { /* that didnt work - try the old format 1430040985 630949 30 630949 np_filename_not_used myserver.procs red testing log format \nAcked by: andy (127.0.0.1) */ sscanf(l, "%u\t%*u\t%*u\t%*u\tnp_filename_not_used\t%*s\t%*s\t%*s", &uicurtime); } curtime = uicurtime; done = (curtime < firstevent); } else { fprintf(output, "Error reading logfile %s: %s\n", acknowledgementslogfilename, strerror(errno)); return; } } else { rewind(acknowledgementslog); done = 1; } } while (!done); } head = NULL; while (acknowledgementslog && (fgets(l, sizeof(l), acknowledgementslog))) { unsigned int etim; unsigned int valid; int duration; time_t eventtime; time_t validity; char host[MAX_LINE_LEN]; char svc[MAX_LINE_LEN]; char recipient[MAX_LINE_LEN]; char message[MAX_LINE_LEN]; char *hostname, *svcname, *p; int itemsfound, pagematch, hostmatch, testmatch, rcptmatch; acknowledgements_t *newrec; void *eventhost; struct htnames_t *eventcolumn; int ovector[30]; /* 2015-03-07 18:17:03 myserver disk andy 1 1425724570 1425752223 1425838623 testing message */ itemsfound = sscanf(l, "%*u-%*u-%*u %*u:%*u:%*u %s %s %s %*u %*u %u %u %[^\t\n]", host, svc, recipient, &etim, &valid, message); if (itemsfound != 6) { /* 1430040985 630949 30 630949 np_filename_not_used myserver.procs red testing log format \nAcked by: andy (127.0.0.1) */ itemsfound = sscanf(l, "%u\t%*u\t%d\t%*u\tnp_filename_not_used\t%s\t%*s\t%[^\n]", &etim, &duration, host, message); if (itemsfound != 4) continue; p = strrchr(host, '.'); if (p) { *p = '\0'; strcpy(svc,p+1); } /* Xymon uses \n in the ack message, for the "acked by" data. Cut it off. */ p = strstr(message, "\\nAcked by:"); if (p) { strcpy(recipient,p+12); *(p-1) = '\0'; } else { strcpy(recipient,"UnknownUser"); } p = strchr(recipient, '('); if (p) *(p-1) = '\0'; } eventtime = etim; if (eventtime < firstevent) continue; if (eventtime > lastevent) break; validity = duration ? (etim + duration * 60) : valid; hostname = host; svcname = svc; eventhost = hostinfo(hostname); if (!eventhost) continue; /* Dont report hosts that no longer exist */ eventcolumn = getname(svcname, 1); p = strchr(recipient, '['); if (p) *p = '\0'; if (pageregexp) { char *pagename; pagename = xmh_item_multi(eventhost, XMH_PAGEPATH); pagematch = 0; while (!pagematch && pagename) { pagematch = (pcre_exec(pageregexp, NULL, pagename, strlen(pagename), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); pagename = xmh_item_multi(NULL, XMH_PAGEPATH); } } else pagematch = 1; if (!pagematch) continue; if (expageregexp) { char *pagename; pagename = xmh_item_multi(eventhost, XMH_PAGEPATH); pagematch = 0; while (!pagematch && pagename) { pagematch = (pcre_exec(expageregexp, NULL, pagename, strlen(pagename), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); pagename = xmh_item_multi(NULL, XMH_PAGEPATH); } } else pagematch = 0; if (pagematch) continue; if (hostregexp) hostmatch = (pcre_exec(hostregexp, NULL, hostname, strlen(hostname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else hostmatch = 1; if (!hostmatch) continue; if (exhostregexp) hostmatch = (pcre_exec(exhostregexp, NULL, hostname, strlen(hostname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else hostmatch = 0; if (hostmatch) continue; if (testregexp) testmatch = (pcre_exec(testregexp, NULL, svcname, strlen(svcname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else testmatch = 1; if (!testmatch) continue; if (extestregexp) testmatch = (pcre_exec(extestregexp, NULL, svcname, strlen(svcname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else testmatch = 0; if (testmatch) continue; if (rcptregexp) rcptmatch = (pcre_exec(rcptregexp, NULL, recipient, strlen(recipient), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else rcptmatch = 1; if (!rcptmatch) continue; if (exrcptregexp) rcptmatch = (pcre_exec(exrcptregexp, NULL, recipient, strlen(recipient), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); else rcptmatch = 0; if (rcptmatch) continue; newrec = (acknowledgements_t *) malloc(sizeof(acknowledgements_t)); newrec->host = eventhost; newrec->service = eventcolumn; newrec->eventtime = eventtime; newrec->validity = validity; newrec->recipient = strdup(recipient); newrec->message = strdup(message); newrec->next = head; head = newrec; } if (head) { char *bgcolors[2] = { "#000000", "#000066" }; int bgcolor = 0; int count; struct acknowledgements_t *lasttoshow = head; count=0; walk=head; do { count++; lasttoshow = walk; walk = walk->next; } while (walk && (count<maxcount)); if (maxminutes) { sprintf(title, "%d acknowledgements in the past %u minutes", count, (unsigned int)((getcurrenttime(NULL) - lasttoshow->eventtime) / 60)); } else { sprintf(title, "%d events acknowledged.", count); } fprintf(output, "<BR><BR>\n"); fprintf(output, "<TABLE SUMMARY=\"Acknowledgements log\" BORDER=0>\n"); fprintf(output, "<TR BGCOLOR=\"#333333\">\n"); fprintf(output, "<TD ALIGN=CENTER COLSPAN=6><FONT SIZE=-1 COLOR=\"#33ebf4\">%s</FONT></TD></TR>\n", htmlquoted(title)); fprintf(output, "<TR BGCOLOR=\"#333333\"><TH>Time</TH><TH>Valid Until</TH><TH>Host</TH><TH>Service</TH><TH>Acknowledged By</TH><TH>Message</TH></TR>\n"); for (walk=head; (walk != lasttoshow->next); walk=walk->next) { char *hostname = xmh_item(walk->host, XMH_HOSTNAME); fprintf(output, "<TR BGCOLOR=%s>\n", bgcolors[bgcolor]); bgcolor = ((bgcolor + 1) % 2); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", ctime(&walk->eventtime)); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", ctime(&walk->validity)); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", hostname); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", walk->service->name); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", walk->recipient); fprintf(output, "<TD ALIGN=LEFT>%s</TD>\n", walk->message); } fprintf(output, "</TABLE>\n"); /* Clean up */ walk = head; do { struct acknowledgements_t *tmp = walk; walk = walk->next; xfree(tmp->recipient); xfree(tmp->message); xfree(tmp); } while (walk); } else { /* No acknowledgements during the past maxminutes */ if (acknowledgementslog) sprintf(title, "No events acknowledged in the last %d minutes", maxminutes); else strcpy(title, "No acknowledgements logged"); fprintf(output, "<CENTER><BR>\n"); fprintf(output, "<TABLE SUMMARY=\"%s\" BORDER=0>\n", title); fprintf(output, "<TR BGCOLOR=\"#333333\">\n"); fprintf(output, "<TD ALIGN=CENTER COLSPAN=6><FONT SIZE=-1 COLOR=\"#33ebf4\">%s</FONT></TD>\n", htmlquoted(title)); fprintf(output, "</TR>\n"); fprintf(output, "</TABLE>\n"); fprintf(output, "</CENTER>\n"); } if (acknowledgementslog) fclose(acknowledgementslog); if (pageregexp) pcre_free(pageregexp); if (expageregexp) pcre_free(expageregexp); if (hostregexp) pcre_free(hostregexp); if (exhostregexp) pcre_free(exhostregexp); if (testregexp) pcre_free(testregexp); if (extestregexp) pcre_free(extestregexp); if (rcptregexp) pcre_free(rcptregexp); if (exrcptregexp) pcre_free(exrcptregexp); }
static void print_host(hostlist_t *host, htnames_t *testnames[], int testcount) { int testi, rowcount, netcount; void *hinfo = hostinfo(host->hostname); char *dispname = NULL, *clientalias = NULL, *comment = NULL, *description = NULL, *pagepathtitle = NULL; char *net = NULL, *nkalerts = NULL; char *nktime = NULL, *downtime = NULL, *reporttime = NULL; char *itm; tag_t *taghead = NULL; int contidx = 0, haveping = 0; char contcol[1024]; activealerts_t *alert; strbuffer_t *buf = newstrbuffer(0); fprintf(stdout, "<p style=\"page-break-before: always\">\n"); fprintf(stdout, "<table width=\"100%%\" border=1 summary=\"%s configuration\">\n", host->hostname); pagepathtitle = bbh_item(hinfo, BBH_PAGEPATHTITLE); if (!pagepathtitle || (strlen(pagepathtitle) == 0)) pagepathtitle = "Top page"; dispname = bbh_item(hinfo, BBH_DISPLAYNAME); if (dispname && (strcmp(dispname, host->hostname) == 0)) dispname = NULL; clientalias = bbh_item(hinfo, BBH_CLIENTALIAS); if (clientalias && (strcmp(clientalias, host->hostname) == 0)) clientalias = NULL; comment = bbh_item(hinfo, BBH_COMMENT); description = bbh_item(hinfo, BBH_DESCRIPTION); net = bbh_item(hinfo, BBH_NET); nkalerts = bbh_item(hinfo, BBH_NK); nktime = bbh_item(hinfo, BBH_NKTIME); if (!nktime) nktime = "24x7"; else nktime = strdup(timespec_text(nktime)); downtime = bbh_item(hinfo, BBH_DOWNTIME); if (downtime) downtime = strdup(timespec_text(downtime)); reporttime = bbh_item(hinfo, BBH_REPORTTIME); if (!reporttime) reporttime = "24x7"; else reporttime = strdup(timespec_text(reporttime)); rowcount = 1; if (pagepathtitle) rowcount++; if (dispname || clientalias) rowcount++; if (comment) rowcount++; if (description) rowcount++; if (!newnkconfig && nktime) rowcount++; if (downtime) rowcount++; if (reporttime) rowcount++; fprintf(stdout, "<tr>\n"); fprintf(stdout, "<th rowspan=%d align=left width=\"25%%\" valign=top>Basics</th>\n", rowcount); fprintf(stdout, "<th align=center>%s (%s)</th>\n", (dispname ? dispname : host->hostname), bbh_item(hinfo, BBH_IP)); fprintf(stdout, "</tr>\n"); if (dispname || clientalias) { fprintf(stdout, "<tr><td>Aliases:"); if (dispname) fprintf(stdout, " %s", dispname); if (clientalias) fprintf(stdout, " %s", clientalias); fprintf(stdout, "</td></tr>\n"); } if (pagepathtitle) fprintf(stdout, "<tr><td>Monitoring location: %s</td></tr>\n", pagepathtitle); if (comment) fprintf(stdout, "<tr><td>Comment: %s</td></tr>\n", comment); if (description) fprintf(stdout, "<tr><td>Description: %s</td></tr>\n", description); if (!newnkconfig && nktime) fprintf(stdout, "<tr><td>NK monitoring period: %s</td></tr>\n", nktime); if (downtime) fprintf(stdout, "<tr><td>Planned downtime: %s</td></tr>\n", downtime); if (reporttime) fprintf(stdout, "<tr><td>SLA Reporting Period: %s</td></tr>\n", reporttime); /* Build a list of the network tests */ itm = bbh_item_walk(hinfo); while (itm) { char *visdata = NULL, *colname = NULL, *expdata = NULL; bburl_t bu; int dialuptest = 0, reversetest = 0, alwaystruetest = 0, httpextra = 0; if (*itm == '?') { dialuptest=1; itm++; } if (*itm == '!') { reversetest=1; itm++; } if (*itm == '~') { alwaystruetest=1; itm++; } if ( argnmatch(itm, "http") || argnmatch(itm, "content=http") || argnmatch(itm, "cont;http") || argnmatch(itm, "cont=") || argnmatch(itm, "nocont;http") || argnmatch(itm, "nocont=") || argnmatch(itm, "post;http") || argnmatch(itm, "post=") || argnmatch(itm, "nopost;http") || argnmatch(itm, "nopost=") || argnmatch(itm, "type;http") || argnmatch(itm, "type=") ) { visdata = decode_url(itm, &bu); colname = bu.columnname; if (!colname) { if (bu.expdata) { httpextra = 1; if (contidx == 0) { colname = "content"; contidx++; } else { sprintf(contcol, "content%d", contidx); colname = contcol; contidx++; } } else { colname = "http"; } } expdata = bu.expdata; } else if (strncmp(itm, "rpc=", 4) == 0) { colname = "rpc"; visdata = strdup(itm+4); } else if (strncmp(itm, "dns=", 4) == 0) { colname = "dns"; visdata = strdup(itm+4); } else if (strncmp(itm, "dig=", 4) == 0) { colname = "dns"; visdata = strdup(itm+4); } else if (strncmp(itm, pingplus, strlen(pingplus)) == 0) { haveping = 1; colname = pingcolumn; visdata = strdup(itm+strlen(pingplus)); } else if (is_net_test(itm)) { colname = strdup(itm); } if (colname) { tag_t *newitem; addtolist: for (newitem = taghead; (newitem && strcmp(newitem->columnname, colname)); newitem = newitem->next); if (!newitem) { newitem = (tag_t *)calloc(1, sizeof(tag_t)); newitem->columnname = strdup(colname); newitem->visualdata = (visdata ? strdup(visdata) : NULL); newitem->expdata = (expdata ? strdup(expdata) : NULL); newitem->next = taghead; taghead = newitem; } else { /* Multiple tags for one column - must be http */ newitem->visualdata = (char *)realloc(newitem->visualdata, strlen(newitem->visualdata) + strlen(visdata) + 5); strcat(newitem->visualdata, "<br>"); strcat(newitem->visualdata, visdata); } if (httpextra) { httpextra = 0; colname = "http"; expdata = NULL; goto addtolist; } } itm = bbh_item_walk(NULL); } if (!haveping && !bbh_item(hinfo, BBH_FLAG_NOCONN)) { for (testi = 0; (testi < testcount); testi++) { if (strcmp(testnames[testi]->name, pingcolumn) == 0) { tag_t *newitem = (tag_t *)calloc(1, sizeof(tag_t)); newitem->columnname = strdup(pingcolumn); newitem->next = taghead; taghead = newitem; } } } /* Add the "badFOO" settings */ itm = bbh_item_walk(hinfo); while (itm) { if (strncmp(itm, "bad", 3) == 0) { char *tname, *p; int b1, b2, b3, n = -1; tag_t *tag = NULL; tname = itm+3; p = strchr(tname, ':'); if (p) { *p = '\0'; n = sscanf(p+1, "%d:%d:%d", &b1, &b2, &b3); for (tag = taghead; (tag && strcmp(tag->columnname, tname)); tag = tag->next); *p = ':'; } if (tag && (n == 3)) { tag->b1 = b1; tag->b2 = b2; tag->b3 = b3; } } itm = bbh_item_walk(NULL); } if (taghead) { fprintf(stdout, "<tr>\n"); fprintf(stdout, "<th align=left valign=top>Network tests"); if (net) fprintf(stdout, "<br>(from %s)", net); fprintf(stdout, "</th>\n"); fprintf(stdout, "<td><table border=0 cellpadding=\"3\" cellspacing=\"5\" summary=\"%s network tests\">\n", host->hostname); fprintf(stdout, "<tr><th align=left valign=top>Service</th><th align=left valign=top>NK</th><th align=left valign=top>C/Y/R limits</th><th align=left valign=top>Specifics</th></tr>\n"); } for (testi = 0, netcount = 0; (testi < testcount); testi++) { tag_t *twalk; for (twalk = taghead; (twalk && strcasecmp(twalk->columnname, testnames[testi]->name)); twalk = twalk->next); if (!twalk) continue; use_columndoc(testnames[testi]->name); fprintf(stdout, "<tr>"); fprintf(stdout, "<td valign=top>%s</td>", testnames[testi]->name); fprintf(stdout, "<td valign=top>%s</td>", nkval(host->hostname, testnames[testi]->name, nkalerts)); fprintf(stdout, "<td valign=top>"); if (twalk->b1 || twalk->b2 || twalk->b3) { fprintf(stdout, "%d/%d/%d", twalk->b1, twalk->b2, twalk->b3); } else { fprintf(stdout, "-/-/-"); } fprintf(stdout, "</td>"); fprintf(stdout, "<td valign=top>"); fprintf(stdout, "<i>%s</i>", (twalk->visualdata ? twalk->visualdata : " ")); if (twalk->expdata) fprintf(stdout, " must return <i>'%s'</i>", twalk->expdata); fprintf(stdout, "</td>"); fprintf(stdout, "</tr>"); netcount++; } if (taghead) { fprintf(stdout, "</table></td>\n"); fprintf(stdout, "</tr>\n"); } if (netcount != testcount) { fprintf(stdout, "<tr>\n"); fprintf(stdout, "<th align=left valign=top>Local tests</th>\n"); fprintf(stdout, "<td><table border=0 cellpadding=\"3\" cellspacing=\"5\" summary=\"%s local tests\">\n", host->hostname); fprintf(stdout, "<tr><th align=left valign=top>Service</th><th align=left valign=top>NK</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"); } for (testi = 0; (testi < testcount); testi++) { tag_t *twalk; for (twalk = taghead; (twalk && strcasecmp(twalk->columnname, testnames[testi]->name)); twalk = twalk->next); if (twalk) continue; use_columndoc(testnames[testi]->name); fprintf(stdout, "<tr>"); fprintf(stdout, "<td valign=top>%s</td>", testnames[testi]->name); fprintf(stdout, "<td valign=top>%s</td>", nkval(host->hostname, testnames[testi]->name, nkalerts)); fprintf(stdout, "<td valign=top>-/-/-</td>"); /* Make up some default configuration data */ fprintf(stdout, "<td valign=top>"); if (strcmp(testnames[testi]->name, "cpu") == 0) { fprintf(stdout, "UNIX - Yellow: Load average > 1.5, Red: Load average > 3.0<br>"); fprintf(stdout, "Windows - Yellow: CPU utilisation > 80%%, Red: CPU utilisation > 95%%"); } else if (strcmp(testnames[testi]->name, "disk") == 0) { fprintf(stdout, "Default limits: Yellow 90%% full, Red 95%% full<br>\n"); print_disklist(host->hostname); } else if (strcmp(testnames[testi]->name, "memory") == 0) { fprintf(stdout, "Yellow: swap/pagefile use > 80%%, Red: swap/pagefile use > 90%%"); } else if (strcmp(testnames[testi]->name, "procs") == 0) { htnames_t *walk; if (!host->procs) fprintf(stdout, "No processes monitored<br>\n"); for (walk = host->procs; (walk); walk = walk->next) { fprintf(stdout, "%s<br>\n", walk->name); } } else if (strcmp(testnames[testi]->name, "svcs") == 0) { htnames_t *walk; if (!host->svcs) fprintf(stdout, "No services monitored<br>\n"); for (walk = host->svcs; (walk); walk = walk->next) { fprintf(stdout, "%s<br>\n", walk->name); } } else { fprintf(stdout, " "); } fprintf(stdout, "</td>"); fprintf(stdout, "</tr>"); } if (netcount != testcount) { fprintf(stdout, "</table></td>\n"); fprintf(stdout, "</tr>\n"); } /* Do the alerts */ alert = (activealerts_t *)calloc(1, sizeof(activealerts_t)); alert->hostname = host->hostname; alert->location = bbh_item(hinfo, BBH_ALLPAGEPATHS); strcpy(alert->ip, "127.0.0.1"); alert->color = COL_RED; alert->pagemessage = ""; alert->state = A_PAGING; alert->cookie = 12345; alert_printmode(2); for (testi = 0; (testi < testcount); testi++) { alert->testname = testnames[testi]->name; if (have_recipient(alert, NULL)) print_alert_recipients(alert, buf); } xfree(alert); if (STRBUFLEN(buf) > 0) { fprintf(stdout, "<tr>\n"); fprintf(stdout, "<th align=left valign=top>Alerts</th>\n"); fprintf(stdout, "<td><table border=0 cellpadding=\"3\" cellspacing=\"5\" summary=\"%s alerts\">\n", host->hostname); 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"); fprintf(stdout, "%s", STRBUF(buf)); fprintf(stdout, "</table></td>\n"); fprintf(stdout, "</tr>\n"); } /* Finish off this host */ fprintf(stdout, "</table>\n"); freestrbuffer(buf); }
int main(int argc, char *argv[]) { char histlogfn[PATH_MAX]; FILE *fd; char textrepfullfn[PATH_MAX], textrepfn[1024], textrepurl[PATH_MAX]; FILE *textrep; reportinfo_t repinfo; int argi; char *envarea = NULL; void *hinfo; for (argi=1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--env=")) { char *p = strchr(argv[argi], '='); loadenv(p+1, envarea); } else if (argnmatch(argv[argi], "--area=")) { char *p = strchr(argv[argi], '='); envarea = strdup(p+1); } } redirect_cgilog("reportlog"); cgidata = cgi_request(); parse_query(); load_hostnames(xgetenv("HOSTSCFG"), NULL, get_fqdn()); if ((hinfo = hostinfo(hostname)) == NULL) { errormsg("No such host"); return 1; } ip = xmh_item(hinfo, XMH_IP); displayname = xmh_item(hinfo, XMH_DISPLAYNAME); if (!displayname) displayname = hostname; sprintf(histlogfn, "%s/%s.%s", xgetenv("XYMONHISTDIR"), commafy(hostname), service); fd = fopen(histlogfn, "r"); if (fd == NULL) { errormsg("Cannot open history file"); } color = parse_historyfile(fd, &repinfo, hostname, service, st, end, 0, reportwarnlevel, reportgreenlevel, reportwarnstops, reporttime); fclose(fd); sprintf(textrepfn, "avail-%s-%s-%u-%u.txt", hostname, service, (unsigned int)getcurrenttime(NULL), (int)getpid()); sprintf(textrepfullfn, "%s/%s", xgetenv("XYMONREPDIR"), textrepfn); sprintf(textrepurl, "%s/%s", xgetenv("XYMONREPURL"), textrepfn); textrep = fopen(textrepfullfn, "w"); /* Now generate the webpage */ printf("Content-Type: %s\n\n", xgetenv("HTMLCONTENTTYPE")); generate_replog(stdout, textrep, textrepurl, hostname, service, color, style, ip, displayname, st, end, reportwarnlevel, reportgreenlevel, reportwarnstops, &repinfo); if (textrep) fclose(textrep); return 0; }
void add_http_test(testitem_t *t) { http_data_t *httptest; char *dnsip = NULL; ssloptions_t *sslopt = NULL; char *sslopt_ciphers = NULL; int sslopt_version = SSLVERSION_DEFAULT; char *sslopt_clientcert = NULL; int httpversion = HTTPVER_11; cookielist_t *ck = NULL; int firstcookie = 1; char *decodedurl; strbuffer_t *httprequest = newstrbuffer(0); /* Allocate the private data and initialize it */ httptest = (http_data_t *) calloc(1, sizeof(http_data_t)); t->privdata = (void *) httptest; decodedurl = decode_url(t->testspec, &httptest->weburl); if (!decodedurl) { errprintf("Invalid URL for http check: %s\n", t->testspec); return; } httptest->url = strdup(decodedurl); httptest->contlen = -1; httptest->parsestatus = (httptest->weburl.proxyurl ? httptest->weburl.proxyurl->parseerror : httptest->weburl.desturl->parseerror); /* If there was a parse error in the URL, dont run the test */ if (httptest->parsestatus) return; if (httptest->weburl.proxyurl && (httptest->weburl.proxyurl->ip == NULL)) { dnsip = dnsresolve(httptest->weburl.proxyurl->host); if (dnsip) { httptest->weburl.proxyurl->ip = strdup(dnsip); } else { dbgprintf("Could not resolve URL hostname '%s'\n", httptest->weburl.proxyurl->host); } } else if (httptest->weburl.desturl->ip == NULL) { dnsip = dnsresolve(httptest->weburl.desturl->host); if (dnsip) { httptest->weburl.desturl->ip = strdup(dnsip); } else { dbgprintf("Could not resolve URL hostname '%s'\n", httptest->weburl.desturl->host); } } switch (httptest->weburl.testtype) { case WEBTEST_PLAIN: case WEBTEST_STATUS: httptest->contentcheck = CONTENTCHECK_NONE; break; case WEBTEST_CONTENT: { FILE *contentfd; char contentfn[PATH_MAX]; sprintf(contentfn, "%s/content/%s.substring", xgetenv("XYMONHOME"), commafy(t->host->hostname)); contentfd = fopen(contentfn, "r"); if (contentfd) { char l[MAX_LINE_LEN]; char *p; if (fgets(l, sizeof(l), contentfd)) { p = strchr(l, '\n'); if (p) { *p = '\0'; }; httptest->weburl.expdata = strdup(l); } else { httptest->contstatus = STATUS_CONTENTMATCH_NOFILE; } fclose(contentfd); } else { httptest->contstatus = STATUS_CONTENTMATCH_NOFILE; } httptest->contentcheck = CONTENTCHECK_REGEX; } break; case WEBTEST_CONT: httptest->contentcheck = ((*httptest->weburl.expdata == '#') ? CONTENTCHECK_DIGEST : CONTENTCHECK_REGEX); break; case WEBTEST_NOCONT: httptest->contentcheck = CONTENTCHECK_NOREGEX; break; case WEBTEST_POST: case WEBTEST_SOAP: if (httptest->weburl.expdata == NULL) { httptest->contentcheck = CONTENTCHECK_NONE; } else { httptest->contentcheck = ((*httptest->weburl.expdata == '#') ? CONTENTCHECK_DIGEST : CONTENTCHECK_REGEX); } break; case WEBTEST_NOPOST: case WEBTEST_NOSOAP: if (httptest->weburl.expdata == NULL) { httptest->contentcheck = CONTENTCHECK_NONE; } else { httptest->contentcheck = CONTENTCHECK_NOREGEX; } break; case WEBTEST_TYPE: httptest->contentcheck = CONTENTCHECK_CONTENTTYPE; break; } /* Compile the hashes and regex's for those tests that use it */ switch (httptest->contentcheck) { case CONTENTCHECK_DIGEST: { char *hashfunc; httptest->exp = (void *) strdup(httptest->weburl.expdata+1); hashfunc = strchr(httptest->exp, ':'); if (hashfunc) { *hashfunc = '\0'; httptest->digestctx = digest_init(httptest->exp); *hashfunc = ':'; } } break; case CONTENTCHECK_REGEX: case CONTENTCHECK_NOREGEX: { int status; httptest->exp = (void *) malloc(sizeof(regex_t)); status = regcomp((regex_t *)httptest->exp, httptest->weburl.expdata, REG_EXTENDED|REG_NOSUB); if (status) { errprintf("Failed to compile regexp '%s' for URL %s\n", httptest->weburl.expdata, httptest->url); httptest->contstatus = STATUS_CONTENTMATCH_BADREGEX; } } break; case CONTENTCHECK_CONTENTTYPE: httptest->exp = httptest->weburl.expdata; break; } if (httptest->weburl.desturl->schemeopts) { if (strstr(httptest->weburl.desturl->schemeopts, "3")) sslopt_version = SSLVERSION_V3; else if (strstr(httptest->weburl.desturl->schemeopts, "2")) sslopt_version = SSLVERSION_V2; if (strstr(httptest->weburl.desturl->schemeopts, "h")) sslopt_ciphers = ciphershigh; else if (strstr(httptest->weburl.desturl->schemeopts, "m")) sslopt_ciphers = ciphersmedium; if (strstr(httptest->weburl.desturl->schemeopts, "10")) httpversion = HTTPVER_10; else if (strstr(httptest->weburl.desturl->schemeopts, "11")) httpversion = HTTPVER_11; } /* Get any cookies */ load_cookies(); /* Generate the request */ addtobuffer(httprequest, (httptest->weburl.postdata ? "POST " : "GET ")); switch (httpversion) { case HTTPVER_10: addtobuffer(httprequest, (httptest->weburl.proxyurl ? httptest->url : httptest->weburl.desturl->relurl)); addtobuffer(httprequest, " HTTP/1.0\r\n"); break; case HTTPVER_11: /* * Experience shows that even though HTTP/1.1 says you should send the * full URL, some servers (e.g. SunOne App server 7) choke on it. * So just send the good-old relative URL unless we're proxying. */ addtobuffer(httprequest, (httptest->weburl.proxyurl ? httptest->url : httptest->weburl.desturl->relurl)); addtobuffer(httprequest, " HTTP/1.1\r\n"); addtobuffer(httprequest, "Connection: close\r\n"); break; } addtobuffer(httprequest, "Host: "); addtobuffer(httprequest, httptest->weburl.desturl->host); if ((httptest->weburl.desturl->port != 80) && (httptest->weburl.desturl->port != 443)) { char hostporthdr[20]; sprintf(hostporthdr, ":%d", httptest->weburl.desturl->port); addtobuffer(httprequest, hostporthdr); } addtobuffer(httprequest, "\r\n"); if (httptest->weburl.postdata) { char hdr[100]; int contlen = strlen(httptest->weburl.postdata); if (strncmp(httptest->weburl.postdata, "file:", 5) == 0) { /* Load the POST data from a file */ FILE *pf = fopen(httptest->weburl.postdata+5, "r"); if (pf == NULL) { errprintf("Cannot open POST data file %s\n", httptest->weburl.postdata+5); xfree(httptest->weburl.postdata); httptest->weburl.postdata = strdup(""); contlen = 0; } else { struct stat st; if (fstat(fileno(pf), &st) == 0) { int n; xfree(httptest->weburl.postdata); httptest->weburl.postdata = (char *)malloc(st.st_size + 1); *(httptest->weburl.postdata) = '\0'; n = fread(httptest->weburl.postdata, 1, st.st_size, pf); if (n == st.st_size) { *(httptest->weburl.postdata+n) = '\0'; contlen = n; } else { errprintf("Cannot read file %s: %s\n", httptest->weburl.postdata+5, strerror(errno)); contlen = 0; } } else { errprintf("Cannot stat file %s\n", httptest->weburl.postdata+5); httptest->weburl.postdata = strdup(""); contlen = 0; } fclose(pf); } } addtobuffer(httprequest, "Content-type: "); if (httptest->weburl.postcontenttype) addtobuffer(httprequest, httptest->weburl.postcontenttype); else if ((httptest->weburl.testtype == WEBTEST_SOAP) || (httptest->weburl.testtype == WEBTEST_NOSOAP)) addtobuffer(httprequest, "application/soap+xml; charset=utf-8"); else addtobuffer(httprequest, "application/x-www-form-urlencoded"); addtobuffer(httprequest, "\r\n"); sprintf(hdr, "Content-Length: %d\r\n", contlen); addtobuffer(httprequest, hdr); } { char useragent[100]; void *hinfo; char *browser = NULL; hinfo = hostinfo(t->host->hostname); if (hinfo) browser = xmh_item(hinfo, XMH_BROWSER); if (browser) { sprintf(useragent, "User-Agent: %s\r\n", browser); } else { sprintf(useragent, "User-Agent: Xymon xymonnet/%s\r\n", VERSION); } addtobuffer(httprequest, useragent); } if (httptest->weburl.desturl->auth) { if (strncmp(httptest->weburl.desturl->auth, "CERT:", 5) == 0) { sslopt_clientcert = httptest->weburl.desturl->auth+5; } else { addtobuffer(httprequest, "Authorization: Basic "); addtobuffer(httprequest, base64encode(httptest->weburl.desturl->auth)); addtobuffer(httprequest, "\r\n"); } } if (httptest->weburl.proxyurl && httptest->weburl.proxyurl->auth) { addtobuffer(httprequest, "Proxy-Authorization: Basic "); addtobuffer(httprequest, base64encode(httptest->weburl.proxyurl->auth)); addtobuffer(httprequest, "\r\n"); } for (ck = cookiehead; (ck); ck = ck->next) { int useit = 0; if (ck->tailmatch) { int startpos = strlen(httptest->weburl.desturl->host) - strlen(ck->host); if (startpos > 0) useit = (strcmp(httptest->weburl.desturl->host+startpos, ck->host) == 0); } else useit = (strcmp(httptest->weburl.desturl->host, ck->host) == 0); if (useit) useit = (strncmp(ck->path, httptest->weburl.desturl->relurl, strlen(ck->path)) == 0); if (useit) { if (firstcookie) { addtobuffer(httprequest, "Cookie: "); firstcookie = 0; } addtobuffer(httprequest, ck->name); addtobuffer(httprequest, "="); addtobuffer(httprequest, ck->value); addtobuffer(httprequest, "\r\n"); } } /* Some standard stuff */ addtobuffer(httprequest, "Accept: */*\r\n"); addtobuffer(httprequest, "Pragma: no-cache\r\n"); if ((httptest->weburl.testtype == WEBTEST_SOAP) || (httptest->weburl.testtype == WEBTEST_NOSOAP)) { /* Must provide a SOAPAction header */ addtobuffer(httprequest, "SOAPAction: "); addtobuffer(httprequest, httptest->url); addtobuffer(httprequest, "\r\n"); } /* The final blank line terminates the headers */ addtobuffer(httprequest, "\r\n"); /* Post data goes last */ if (httptest->weburl.postdata) addtobuffer(httprequest, httptest->weburl.postdata); /* Pickup any SSL options the user wants */ if (sslopt_ciphers || (sslopt_version != SSLVERSION_DEFAULT) || sslopt_clientcert){ sslopt = (ssloptions_t *) malloc(sizeof(ssloptions_t)); sslopt->cipherlist = sslopt_ciphers; sslopt->sslversion = sslopt_version; sslopt->clientcert = sslopt_clientcert; } /* Add to TCP test queue */ if (httptest->weburl.proxyurl == NULL) { httptest->tcptest = add_tcp_test(httptest->weburl.desturl->ip, httptest->weburl.desturl->port, httptest->weburl.desturl->scheme, sslopt, t->srcip, t->testspec, t->silenttest, grabstrbuffer(httprequest), httptest, tcp_http_data_callback, tcp_http_final_callback); } else { httptest->tcptest = add_tcp_test(httptest->weburl.proxyurl->ip, httptest->weburl.proxyurl->port, httptest->weburl.proxyurl->scheme, sslopt, t->srcip, t->testspec, t->silenttest, grabstrbuffer(httprequest), httptest, tcp_http_data_callback, tcp_http_final_callback); } }
static int criteriamatch(activealerts_t *alert, criteria_t *crit, criteria_t *rulecrit, int *anymatch, time_t *nexttime) { /* * See if the "crit" matches the "alert". * Match on pagespec, dgspec, hostspec, svcspec, classspec, groupspec, colors, timespec, minduration, maxduration, sendrecovered */ static char *pgnames = NULL; int pgmatchres, pgexclres; time_t duration = (getcurrenttime(NULL) - alert->eventstart); int result, cfid = 0; char *pgtok, *cfline = NULL; void *hinfo = hostinfo(alert->hostname); /* The top-level page needs a name - cannot match against an empty string */ if (pgnames) xfree(pgnames); pgnames = strdup((*alert->location == '\0') ? "/" : alert->location); if (crit) { cfid = crit->cfid; cfline = crit->cfline; } if (!cfid && rulecrit) cfid = rulecrit->cfid; if (!cfline && rulecrit) cfline = rulecrit->cfline; if (!cfline) cfline = "<undefined>"; traceprintf("Matching host:service:dgroup:page '%s:%s:%s:%s' against rule line %d\n", alert->hostname, alert->testname, xmh_item(hinfo, XMH_DGNAME), alert->location, cfid); if (alert->state == A_PAGING) { /* Check max-duration now - it's fast and easy. */ if (crit && crit->maxduration && (duration > crit->maxduration)) { traceprintf("Failed '%s' (max. duration %d>%d)\n", cfline, duration, crit->maxduration); if (!printmode) return 0; } } if (crit && crit->classspec && !namematch(alert->classname, crit->classspec, crit->classspecre)) { traceprintf("Failed '%s' (class not in include list)\n", cfline); return 0; } if (crit && crit->exclassspec && namematch(alert->classname, crit->exclassspec, crit->exclassspecre)) { traceprintf("Failed '%s' (class excluded)\n", cfline); return 0; } /* alert->groups is a comma-separated list of groups, so it needs some special handling */ /* * NB: Dont check groups when RECOVERED - the group list for recovery messages is always empty. * It doesn't matter if we match a recipient who was not in the group that originally * got the alert - we will later check who has received the alert, and only those that * have will get the recovery message. */ if (crit && (crit->groupspec || crit->exgroupspec) && (alert->state != A_RECOVERED)) { char *grouplist; char *tokptr; grouplist = (alert->groups && (*(alert->groups))) ? strdup(alert->groups) : NULL; if (crit->groupspec) { char *onegroup; int iswanted = 0; if (grouplist) { /* There is a group label on the alert, so it must match */ onegroup = strtok_r(grouplist, ",", &tokptr); while (onegroup && !iswanted) { iswanted = (namematch(onegroup, crit->groupspec, crit->groupspecre)); onegroup = strtok_r(NULL, ",", &tokptr); } } if (!iswanted) { /* * Either the alert had a group list that didn't match, or * there was no group list and the rule listed one. * In both cases, it's a failed match. */ traceprintf("Failed '%s' (group not in include list)\n", cfline); if (grouplist) xfree(grouplist); return 0; } } if (crit->exgroupspec && grouplist) { char *onegroup; /* Excluded groups are only handled when the alert does have a group list */ strcpy(grouplist, alert->groups); /* Might have been used in the include list */ onegroup = strtok_r(grouplist, ",", &tokptr); while (onegroup) { if (namematch(onegroup, crit->exgroupspec, crit->exgroupspecre)) { traceprintf("Failed '%s' (group excluded)\n", cfline); xfree(grouplist); return 0; } onegroup = strtok_r(NULL, ",", &tokptr); } } if (grouplist) xfree(grouplist); } pgmatchres = pgexclres = -1; pgtok = strtok(pgnames, ","); while (pgtok) { if (crit && crit->pagespec && (pgmatchres != 1)) pgmatchres = (namematch(pgtok, crit->pagespec, crit->pagespecre) ? 1 : 0); if (crit && crit->expagespec && (pgexclres != 1)) pgexclres = (namematch(pgtok, crit->expagespec, crit->expagespecre) ? 1 : 0); pgtok = strtok(NULL, ","); } if (pgexclres == 1) { traceprintf("Failed '%s' (pagename excluded)\n", cfline); return 0; } if (pgmatchres == 0) { traceprintf("Failed '%s' (pagename not in include list)\n", cfline); return 0; } if (crit && crit->dgspec && !namematch(xmh_item(hinfo, XMH_DGNAME), crit->dgspec, crit->dgspecre)) { traceprintf("Failed '%s' (displaygroup not in include list)\n", cfline); return 0; } if (crit && crit->exdgspec && namematch(xmh_item(hinfo, XMH_DGNAME), crit->exdgspec, crit->exdgspecre)) { traceprintf("Failed '%s' (displaygroup excluded)\n", cfline); return 0; } if (crit && crit->hostspec && !namematch(alert->hostname, crit->hostspec, crit->hostspecre)) { traceprintf("Failed '%s' (hostname not in include list)\n", cfline); return 0; } if (crit && crit->exhostspec && namematch(alert->hostname, crit->exhostspec, crit->exhostspecre)) { traceprintf("Failed '%s' (hostname excluded)\n", cfline); return 0; } if (crit && crit->svcspec && !namematch(alert->testname, crit->svcspec, crit->svcspecre)) { traceprintf("Failed '%s' (service not in include list)\n", cfline); return 0; } if (crit && crit->exsvcspec && namematch(alert->testname, crit->exsvcspec, crit->exsvcspecre)) { traceprintf("Failed '%s' (service excluded)\n", cfline); return 0; } if (alert->state == A_NOTIFY) { /* * Dont do the check until we are checking individual recipients (rulecrit is set). * You dont need to have NOTICE on the top-level rule, it's enough if a recipient * has it set. However, we do want to allow there to be a default defined in the * rule; but it doesn't take effect until we start checking the recipients. */ if (rulecrit) { int n = (crit ? crit->sendnotice : -1); traceprintf("Checking NOTICE setting %d (rule:%d)\n", n, rulecrit->sendnotice); if (crit && (crit->sendnotice == SR_NOTWANTED)) result = 0; /* Explicit NONOTICE */ else if (crit && (crit->sendnotice == SR_WANTED)) result = 1; /* Explicit NOTICE */ else result = (rulecrit->sendnotice == SR_WANTED); /* Not set, but rule has NOTICE */ } else { result = 1; } if (!result) traceprintf("Failed '%s' (notice not wanted)\n", cfline); return result; } /* At this point, we know the configuration may result in an alert. */ if (anymatch) (*anymatch)++; /* * Duration checks should be done on real paging messages only. * Not on recovery- or notify-messages. */ if (alert->state == A_PAGING) { if (crit && crit->minduration && (duration < crit->minduration)) { if (nexttime) { time_t mynext = alert->eventstart + crit->minduration; if ((*nexttime == -1) || (*nexttime > mynext)) *nexttime = mynext; } traceprintf("Failed '%s' (min. duration %d<%d)\n", cfline, duration, crit->minduration); if (!printmode) return 0; } } /* * Time restrictions apply to ALL messages. * Before 4.2, these were only applied to ALERT messages, * not RECOVERED and NOTIFY messages. This caused some * unfortunate alerts in the middle of the night because * some random system recovered ... not good. So apply * this check to all messages. */ if (crit && crit->timespec && !timematch(xmh_item(hinfo, XMH_HOLIDAYS), crit->timespec)) { traceprintf("Failed '%s' (time criteria)\n", cfline); if (!printmode) return 0; } /* Check color. For RECOVERED messages, this holds the color of the alert, not the recovery state */ if (crit && crit->colors) { result = (((1 << alert->color) & crit->colors) != 0); if (printmode) return 1; } else { result = (((1 << alert->color) & defaultcolors) != 0); if (printmode) return 1; } if (!result) { traceprintf("Failed '%s' (color)\n", cfline); return result; } if ((alert->state == A_RECOVERED) || (alert->state == A_DISABLED)) { /* * Dont do the check until we are checking individual recipients (rulecrit is set). * You dont need to have RECOVERED on the top-level rule, it's enough if a recipient * has it set. However, we do want to allow there to be a default defined in the * rule; but it doesn't take effect until we start checking the recipients. */ if (rulecrit) { int n = (crit ? crit->sendrecovered : -1); traceprintf("Checking recovered setting %d (rule:%d)\n", n, rulecrit->sendrecovered); if (crit && (crit->sendrecovered == SR_NOTWANTED)) result = 0; /* Explicit NORECOVERED */ else if (crit && (crit->sendrecovered == SR_WANTED)) result = 1; /* Explicit RECOVERED */ else result = (rulecrit->sendrecovered == SR_WANTED); /* Not set, but rule has RECOVERED */ } else { result = 1; } if (printmode) return result; } if (result) { traceprintf("*** Match with '%s' ***\n", cfline); } return result; }