int main(int argc, char *argv[]) { char *pagedir; bbgen_page_t *p; dispsummary_t *s; int i; char *pageset = NULL; char *nssidebarfilename = NULL; char *egocolumn = NULL; char *csvfile = NULL; char csvdelim = ','; int embedded = 0; int hobbitddump = 0; char *envarea = NULL; int do_normal_pages = 1; /* Setup standard header+footer (might be modified by option pageset) */ select_headers_and_footers("bb"); bb_color = bb2_color = bbnk_color = -1; pagedir = NULL; init_timestamp(); fqdn = get_fqdn(); /* Setup values from env. vars that may be overridden via commandline options */ if (xgetenv("MKBB2COLREPEAT")) { int i = atoi(xgetenv("MKBB2COLREPEAT")); if (i > 0) maxrowsbeforeheading = i; } for (i = 1; (i < argc); i++) { if ( (strcmp(argv[i], "--hobbitd") == 0) || (argnmatch(argv[i], "--purplelifetime=")) || (strcmp(argv[i], "--nopurple") == 0) ) { /* Deprecated */ } else if (argnmatch(argv[i], "--env=")) { char *lp = strchr(argv[i], '='); loadenv(lp+1, envarea); } else if (argnmatch(argv[i], "--area=")) { char *lp = strchr(argv[i], '='); envarea = strdup(lp+1); } else if (argnmatch(argv[i], "--hobbitddump")) { hobbitddump = 1; } else if (argnmatch(argv[i], "--ignorecolumns=")) { char *lp = strchr(argv[i], '='); ignorecolumns = (char *) malloc(strlen(lp)+2); sprintf(ignorecolumns, ",%s,", (lp+1)); } else if (argnmatch(argv[i], "--nk-reds-only")) { nkonlyreds = 1; } else if (argnmatch(argv[i], "--bb2-ignorecolumns=")) { char *lp = strchr(argv[i], '='); bb2ignorecolumns = (char *) malloc(strlen(lp)+2); sprintf(bb2ignorecolumns, ",%s,", (lp+1)); } else if (argnmatch(argv[i], "--bb2-colors=")) { char *lp = strchr(argv[i], '=') + 1; bb2colors = colorset(lp, (1 << COL_GREEN)); } else if (argnmatch(argv[i], "--bb2-ignorepurples")) { bb2colors = (bb2colors & ~(1 << COL_PURPLE)); } else if (argnmatch(argv[i], "--bb2-ignoredialups")) { bb2nodialups = 1; } else if (argnmatch(argv[i], "--includecolumns=")) { char *lp = strchr(argv[i], '='); includecolumns = (char *) malloc(strlen(lp)+2); sprintf(includecolumns, ",%s,", (lp+1)); } else if (argnmatch(argv[i], "--eventignore=")) { char *lp = strchr(argv[i], '='); eventignorecolumns = (char *) malloc(strlen(lp)+2); sprintf(eventignorecolumns, ",%s,", (lp+1)); } else if (argnmatch(argv[i], "--doccgi=")) { char *lp = strchr(argv[i], '='); char *url = (char *)malloc(strlen(xgetenv("CGIBINURL"))+strlen(lp+1)+2); sprintf(url, "%s/%s", xgetenv("CGIBINURL"), lp+1); setdocurl(url); xfree(url); } else if (argnmatch(argv[i], "--docurl=")) { char *lp = strchr(argv[i], '='); setdocurl(lp+1); } else if (argnmatch(argv[i], "--no-doc-window")) { /* This is a no-op now */ } else if (argnmatch(argv[i], "--doc-window")) { setdocurl("TARGET=\"_blank\""); } else if (argnmatch(argv[i], "--htmlextension=")) { char *lp = strchr(argv[i], '='); htmlextension = strdup(lp+1); } else if (argnmatch(argv[i], "--htaccess")) { char *lp = strchr(argv[i], '='); if (lp) htaccess = strdup(lp+1); else htaccess = ".htaccess"; } else if ((strcmp(argv[i], "--wml") == 0) || argnmatch(argv[i], "--wml=")) { char *lp = strchr(argv[i], '='); if (lp) { wapcolumns = (char *) malloc(strlen(lp)+2); sprintf(wapcolumns, ",%s,", (lp+1)); } enable_wmlgen = 1; } else if (argnmatch(argv[i], "--nstab=")) { char *lp = strchr(argv[i], '='); if (strlen(lp+1) > 0) { nssidebarfilename = strdup(lp+1); } else errprintf("--nstab requires a filename\n"); } else if (argnmatch(argv[i], "--nslimit=")) { char *lp = strchr(argv[i], '='); nssidebarcolorlimit = parse_color(lp+1); } else if (argnmatch(argv[i], "--rssversion=")) { char *lp = strchr(argv[i], '='); rssversion = strdup(lp+1); } else if (argnmatch(argv[i], "--rsslimit=")) { char *lp = strchr(argv[i], '='); rsscolorlimit = parse_color(lp+1); } else if (argnmatch(argv[i], "--rss")) { wantrss = 1; } else if (argnmatch(argv[i], "--rssextension=")) { char *lp = strchr(argv[i], '='); rssextension = strdup(lp+1); } else if (argnmatch(argv[i], "--reportopts=")) { char style[MAX_LINE_LEN]; unsigned int rstart, rend; int count = sscanf(argv[i], "--reportopts=%u:%u:%d:%s", &rstart, &rend, &dynamicreport, style); reportstart = rstart; reportend = rend; if (count < 2) { errprintf("Invalid --reportopts option: Must have start- and end-times\n"); return 1; } if (count < 3) dynamicreport = 1; if (count == 4) { if (strcmp(style, stylenames[STYLE_CRIT]) == 0) reportstyle = STYLE_CRIT; else if (strcmp(style, stylenames[STYLE_NONGR]) == 0) reportstyle = STYLE_NONGR; else reportstyle = STYLE_OTHER; } if (reportstart < 788918400) reportstart = 788918400; if (reportend > time(NULL)) reportend = time(NULL); if (xgetenv("BBREPWARN")) reportwarnlevel = atof(xgetenv("BBREPWARN")); if (xgetenv("BBREPGREEN")) reportgreenlevel = atof(xgetenv("BBREPGREEN")); if ((reportwarnlevel < 0.0) || (reportwarnlevel > 100.0)) reportwarnlevel = 97.0; if ((reportgreenlevel < 0.0) || (reportgreenlevel > 100.0)) reportgreenlevel = 99.995; select_headers_and_footers("bbrep"); sethostenv_report(reportstart, reportend, reportwarnlevel, reportgreenlevel); } else if (argnmatch(argv[i], "--csv=")) { char *lp = strchr(argv[i], '='); csvfile = strdup(lp+1); } else if (argnmatch(argv[i], "--csvdelim=")) { char *lp = strchr(argv[i], '='); csvdelim = *(lp+1); } else if (argnmatch(argv[i], "--snapshot=")) { char *lp = strchr(argv[i], '='); snapshot = atol(lp+1); select_headers_and_footers("bbsnap"); sethostenv_snapshot(snapshot); } else if (strcmp(argv[i], "--pages-first") == 0) { hostsbeforepages = 0; } else if (strcmp(argv[i], "--pages-last") == 0) { hostsbeforepages = 1; } else if (argnmatch(argv[i], "--subpagecolumns=")) { char *lp = strchr(argv[i], '='); subpagecolumns = atoi(lp+1); if (subpagecolumns < 1) subpagecolumns=1; } else if (argnmatch(argv[i], "--maxrows=")) { char *lp = strchr(argv[i], '='); maxrowsbeforeheading = atoi(lp+1); if (maxrowsbeforeheading < 0) maxrowsbeforeheading=0; } else if (strcmp(argv[i], "--recentgifs") == 0) { use_recentgifs = 1; } else if (argnmatch(argv[i], "--recentgifs=")) { char *lp = strchr(argv[i], '='); use_recentgifs = 1; recentgif_limit = 60*durationvalue(lp+1); } else if (strcmp(argv[i], "--sort-group-only-items") == 0) { sort_grouponly_items = 1; } else if (argnmatch(argv[i], "--page-title=")) { char *lp = strchr(argv[i], '='); defaultpagetitle = strdup(lp+1); } else if (argnmatch(argv[i], "--dialupskin=")) { char *lp = strchr(argv[i], '='); dialupskin = strdup(lp+1); } else if (argnmatch(argv[i], "--reverseskin=")) { char *lp = strchr(argv[i], '='); reverseskin = strdup(lp+1); } else if (strcmp(argv[i], "--pagetitle-links") == 0) { pagetitlelinks = 1; } else if (strcmp(argv[i], "--pagetext-headings") == 0) { pagetextheadings = 1; } else if (strcmp(argv[i], "--underline-headings") == 0) { underlineheadings = 1; } else if (strcmp(argv[i], "--no-underline-headings") == 0) { underlineheadings = 0; } else if (strcmp(argv[i], "--no-eventlog") == 0) { bb2eventlog = 0; } else if (argnmatch(argv[i], "--max-eventcount=")) { char *lp = strchr(argv[i], '='); bb2eventlogmaxcount = atoi(lp+1); } else if (argnmatch(argv[i], "--max-eventtime=")) { char *lp = strchr(argv[i], '='); bb2eventlogmaxtime = atoi(lp+1); } else if (argnmatch(argv[i], "--max-ackcount=")) { char *lp = strchr(argv[i], '='); bb2acklogmaxcount = atoi(lp+1); } else if (argnmatch(argv[i], "--max-acktime=")) { char *lp = strchr(argv[i], '='); bb2acklogmaxtime = atoi(lp+1); } else if (strcmp(argv[i], "--no-acklog") == 0) { bb2acklog = 0; } else if (strcmp(argv[i], "--no-pages") == 0) { do_normal_pages = 0; } else if (argnmatch(argv[i], "--noprop=")) { char *lp = strchr(argv[i], '='); nopropyellowdefault = (char *) malloc(strlen(lp)+2); sprintf(nopropyellowdefault, ",%s,", (lp+1)); errprintf("--noprop is deprecated - use --nopropyellow instead\n"); } else if (argnmatch(argv[i], "--nopropyellow=")) { char *lp = strchr(argv[i], '='); nopropyellowdefault = (char *) malloc(strlen(lp)+2); sprintf(nopropyellowdefault, ",%s,", (lp+1)); } else if (argnmatch(argv[i], "--nopropred=")) { char *lp = strchr(argv[i], '='); nopropreddefault = (char *) malloc(strlen(lp)+2); sprintf(nopropreddefault, ",%s,", (lp+1)); } else if (argnmatch(argv[i], "--noproppurple=")) { char *lp = strchr(argv[i], '='); noproppurpledefault = (char *) malloc(strlen(lp)+2); sprintf(noproppurpledefault, ",%s,", (lp+1)); } else if (argnmatch(argv[i], "--nopropack=")) { char *lp = strchr(argv[i], '='); nopropackdefault = (char *) malloc(strlen(lp)+2); sprintf(nopropackdefault, ",%s,", (lp+1)); } else if (strcmp(argv[i], "--bbpageONLY") == 0) { /* Deprecated */ errprintf("--bbpageONLY is deprecated - use --pageset=NAME to generate pagesets\n"); } else if (strcmp(argv[i], "--embedded") == 0) { embedded = 1; } else if (argnmatch(argv[i], "--pageset=")) { char *lp = strchr(argv[i], '='); pageset = strdup(lp+1); } else if (argnmatch(argv[i], "--template=")) { char *lp = strchr(argv[i], '='); lp++; select_headers_and_footers(lp); } else if (argnmatch(argv[i], "--purplelog=")) { char *lp = strchr(argv[i], '='); if (*(lp+1) == '/') purplelogfn = strdup(lp+1); else { purplelogfn = (char *) malloc(strlen(xgetenv("BBHOME"))+1+strlen(lp+1)+1); sprintf(purplelogfn, "%s/%s", xgetenv("BBHOME"), (lp+1)); } } else if (argnmatch(argv[i], "--report=") || (strcmp(argv[i], "--report") == 0)) { char *lp = strchr(argv[i], '='); if (lp) { egocolumn = strdup(lp+1); } else egocolumn = "bbgen"; timing = 1; } else if (argnmatch(argv[i], "--nklog=") || (strcmp(argv[i], "--nklog") == 0)) { char *lp = strchr(argv[i], '='); if (lp) { lognkstatus = strdup(lp+1); } else lognkstatus = "nk"; } else if (strcmp(argv[i], "--timing") == 0) { timing = 1; } else if (strcmp(argv[i], "--debug") == 0) { debug = 1; } else if (strcmp(argv[i], "--no-update") == 0) { dontsendmessages = 1; } else if (strcmp(argv[i], "--version") == 0) { printf("bbgen version %s\n", VERSION); printf("\n"); exit(0); } else if ((strcmp(argv[i], "--help") == 0) || (strcmp(argv[i], "-?") == 0)) { printf("bbgen for Hobbit version %s\n\n", VERSION); printf("Usage: %s [options] [WebpageDirectory]\n", argv[0]); printf("Options:\n"); printf(" --ignorecolumns=test[,test] : Completely ignore these columns\n"); printf(" --nk-reds-only : Only show red statuses on the NK page\n"); printf(" --bb2-ignorecolumns=test[,test]: Ignore these columns for the BB2 page\n"); printf(" --bb2-ignorepurples : Ignore all-purple hosts on BB2 page\n"); printf(" --includecolumns=test[,test]: Always include these columns on BB2 page\n"); printf(" --max-eventcount=N : Max number of events to include in eventlog\n"); printf(" --max-eventtime=N : Show events that occurred within the last N minutes\n"); printf(" --eventignore=test[,test] : Columns to ignore in bb2 event-log display\n"); printf(" --no-eventlog : Do not generate the bb2 eventlog display\n"); printf(" --no-acklog : Do not generate the bb2 ack-log display\n"); printf(" --no-pages : Generate only the bb2 and bbnk pages\n"); printf(" --docurl=documentation-URL : Hostnames link to a general (dynamic) web page for docs\n"); printf(" --no-doc-window : Open doc-links in same window\n"); printf(" --htmlextension=.EXT : Sets filename extension for generated file (default: .html\n"); printf(" --report[=COLUMNNAME] : Send a status report about the running of bbgen\n"); printf(" --reportopts=ST:END:DYN:STL : Run in Hobbit Reporting mode\n"); printf(" --csv=FILENAME : For Hobbit Reporting, output CSV file\n"); printf(" --csvdelim=CHARACTER : Delimiter in CSV file output (default: comma)\n"); printf(" --snapshot=TIME : Snapshot mode\n"); printf("\nPage layout options:\n"); printf(" --pages-first : Put page- and subpage-links before hosts (default)\n"); printf(" --pages-last : Put page- and subpage-links after hosts\n"); printf(" --subpagecolumns=N : Number of columns for links to pages and subpages\n"); printf(" --maxrows=N : Repeat column headings for every N hosts shown\n"); printf(" --recentgifs : Use xxx-recent.gif icons for newly changed tests\n"); printf(" --sort-group-only-items : Display group-only items in alphabetical order\n"); printf(" --page-title=TITLE : Set a default page title for all pages\n"); printf(" --dialupskin=URL : Use a different icon skin for dialup tests\n"); printf(" --reverseskin=URL : Use a different icon skin for reverse tests\n"); printf(" --pagetitle-links : Make page- and subpage-titles act as links\n"); printf(" --pagetext-headings : Use page texts as headings\n"); printf(" --no-underline-headings : Do not underline the page headings\n"); printf("\nStatus propagation control options:\n"); printf(" --noprop=test[,test] : Disable upwards status propagation when YELLOW\n"); printf(" --nopropred=test[,test] : Disable upwards status propagation when RED or YELLOW\n"); printf(" --noproppurple=test[,test] : Disable upwards status propagation when PURPLE\n"); printf("\nAlternate pageset generation support:\n"); printf(" --pageset=SETNAME : Generate non-standard pageset with tag SETNAME\n"); printf(" --template=TEMPLATE : template for header and footer files\n"); printf("\nAlternate output formats:\n"); printf(" --wml[=test1,test2,...] : Generate a small (bb2-style) WML page\n"); printf(" --nstab=FILENAME : Generate a Netscape Sidebar feed\n"); printf(" --nslimit=COLOR : Minimum color to include on Netscape sidebar\n"); printf(" --rss : Generate a RSS/RDF feed of alerts\n"); printf(" --rssextension=.EXT : Sets filename extension for RSS files (default: .rss\n"); printf(" --rssversion={0.91|0.92|1.0|2.0} : Specify RSS/RDF version (default: 0.91)\n"); printf(" --rsslimit=COLOR : Minimum color to include on RSS feed\n"); printf("\nDebugging/troubleshooting options:\n"); printf(" --timing : Collect timing information\n"); printf(" --debug : Debugging information\n"); printf(" --version : Show version information\n"); printf(" --purplelog=FILENAME : Create a log of purple hosts and tests\n"); exit(0); } else if (argnmatch(argv[i], "-")) { errprintf("Unknown option : %s\n", argv[i]); } else { /* Last argument is pagedir */ pagedir = strdup(argv[i]); } } /* In case they changed the name of our column ... */ if (egocolumn) setup_signalhandler(egocolumn); if (debug) { int i; printf("Command: bbgen"); for (i=1; (i<argc); i++) printf(" '%s'", argv[i]); printf("\n"); printf("Environment BBHOSTS='%s'\n", textornull(xgetenv("BBHOSTS"))); printf("\n"); } add_timestamp("Startup"); /* Check that all needed environment vars are defined */ envcheck(reqenv); /* Catch a SEGV fault */ setup_signalhandler("bbgen"); /* Set umask to 0022 so that the generated HTML pages have world-read access */ umask(0022); if (pagedir == NULL) { if (xgetenv("BBWWW")) { pagedir = strdup(xgetenv("BBWWW")); } else { pagedir = (char *) malloc(strlen(xgetenv("BBHOME"))+5); sprintf(pagedir, "%s/www", xgetenv("BBHOME")); } } if (xgetenv("BBHTACCESS")) bbhtaccess = strdup(xgetenv("BBHTACCESS")); if (xgetenv("BBPAGEHTACCESS")) bbpagehtaccess = strdup(xgetenv("BBPAGEHTACCESS")); if (xgetenv("BBSUBPAGEHTACCESS")) bbsubpagehtaccess = strdup(xgetenv("BBSUBPAGEHTACCESS")); /* * When doing alternate pagesets, disable some stuff: * No WML or RSS pages. */ if (pageset || embedded || snapshot) enable_wmlgen = wantrss = 0; if (embedded) { egocolumn = htaccess = NULL; /* * Need to have default SIGPIPE handling when doing embedded stuff. * We are probably run from a CGI script or something similar. */ signal(SIGPIPE, SIG_DFL); } /* Load all data from the various files */ load_all_links(); add_timestamp("Load links done"); pagehead = load_bbhosts(pageset); add_timestamp("Load bbhosts done"); if (!embedded) { /* Remove old acknowledgements */ delete_old_acks(); add_timestamp("ACK removal done"); } statehead = load_state(&dispsums); if (embedded || snapshot) dispsums = NULL; add_timestamp("Load STATE done"); if (hobbitddump) { dump_hobbitdchk(); return 0; } /* Calculate colors of hosts and pages */ calc_hostcolors(bb2ignorecolumns); calc_pagecolors(pagehead); /* Topmost page (background color for bb.html) */ for (p=pagehead; (p); p = p->next) { if (p->color > pagehead->color) pagehead->color = p->color; } bb_color = pagehead->color; if (xgetenv("SUMMARY_SET_BKG") && (strcmp(xgetenv("SUMMARY_SET_BKG"), "TRUE") == 0)) { /* * Displayed summaries affect the BB page only, * but should not go into the color we report to * others. */ for (s=dispsums; (s); s = s->next) { if (s->color > pagehead->color) pagehead->color = s->color; } } add_timestamp("Color calculation done"); if (debug) dumpall(pagehead); /* Generate pages */ if (chdir(pagedir) != 0) { errprintf("Cannot change to webpage directory %s\n", pagedir); exit(1); } if (embedded) { /* Just generate that one page */ do_one_page(pagehead, NULL, 1); return 0; } /* The main page - bb.html and pages/subpages thereunder */ add_timestamp("Hobbit pagegen start"); if (reportstart && csvfile) { csv_availability(csvfile, csvdelim); } else if (do_normal_pages) { do_page_with_subs(pagehead, dispsums); } add_timestamp("Hobbit pagegen done"); if (reportstart) { /* Reports end here */ return 0; } /* The full summary page - bb2.html */ bb2_color = do_bb2_page(nssidebarfilename, PAGE_BB2); add_timestamp("BB2 generation done"); /* Reduced summary (alerts) page - bbnk.html */ bbnk_color = do_bb2_page(NULL, PAGE_NK); add_timestamp("BBNK generation done"); if (snapshot) { /* Snapshots end here */ return 0; } /* Send summary notices - only once, so not on pagesets */ if (pageset == NULL) { send_summaries(sumhead); add_timestamp("Summary transmission done"); } /* Generate WML cards */ if (enable_wmlgen) { do_wml_cards(pagedir); add_timestamp("WML generation done"); } /* Need to do this before sending in our report */ add_timestamp("Run completed"); /* Tell about us */ if (egocolumn) { char msgline[4096]; char *timestamps; long bbsleep = (xgetenv("BBSLEEP") ? atol(xgetenv("BBSLEEP")) : 300); int color; /* Go yellow if it runs for too long */ if (total_runtime() > bbsleep) { errprintf("WARNING: Runtime %ld longer than BBSLEEP (%ld)\n", total_runtime(), bbsleep); } color = (errbuf ? COL_YELLOW : COL_GREEN); combo_start(); init_status(color); sprintf(msgline, "status %s.%s %s %s\n\n", xgetenv("MACHINE"), egocolumn, colorname(color), timestamp); addtostatus(msgline); sprintf(msgline, "bbgen for Hobbit version %s\n", VERSION); addtostatus(msgline); sprintf(msgline, "\nStatistics:\n Hosts : %5d\n Status messages : %5d\n Purple messages : %5d\n Pages : %5d\n", hostcount, statuscount, purplecount, pagecount); addtostatus(msgline); if (errbuf) { addtostatus("\n\nError output:\n"); addtostatus(errbuf); } show_timestamps(×tamps); addtostatus(timestamps); finish_status(); combo_end(); } else show_timestamps(NULL); return 0; }
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; }
int main(int argc, char *argv[]) { strbuffer_t *inbuf; char *ackbuf; char *subjectline = NULL; char *returnpathline = NULL; char *fromline = NULL; char *firsttxtline = NULL; int inheaders = 1; char *p; pcre *subjexp; const char *errmsg; int errofs, result; int ovector[30]; char cookie[10]; int duration = 0; int argi; char *envarea = NULL; for (argi=1; (argi < argc); argi++) { if (strcmp(argv[argi], "--debug") == 0) { debug = 1; } else 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); } } initfgets(stdin); inbuf = newstrbuffer(0); while (unlimfgets(inbuf, stdin)) { sanitize_input(inbuf, 0, 0); if (!inheaders) { /* We're in the message body. Look for a "delay=N" line here. */ if ((strncasecmp(STRBUF(inbuf), "delay=", 6) == 0) || (strncasecmp(STRBUF(inbuf), "delay ", 6) == 0)) { duration = durationvalue(STRBUF(inbuf)+6); continue; } else if ((strncasecmp(STRBUF(inbuf), "ack=", 4) == 0) || (strncasecmp(STRBUF(inbuf), "ack ", 4) == 0)) { /* Some systems cannot generate a subject. Allow them to ack * via text in the message body. */ subjectline = (char *)malloc(STRBUFLEN(inbuf) + 1024); sprintf(subjectline, "Subject: Xymon [%s]", STRBUF(inbuf)+4); } else if (*STRBUF(inbuf) && !firsttxtline) { /* Save the first line of the message body, but ignore blank lines */ firsttxtline = strdup(STRBUF(inbuf)); } continue; /* We don't care about the rest of the message body */ } /* See if we're at the end of the mail headers */ if (inheaders && (STRBUFLEN(inbuf) == 0)) { inheaders = 0; continue; } /* Is it one of those we want to keep ? */ if (strncasecmp(STRBUF(inbuf), "return-path:", 12) == 0) returnpathline = strdup(skipwhitespace(STRBUF(inbuf)+12)); else if (strncasecmp(STRBUF(inbuf), "from:", 5) == 0) fromline = strdup(skipwhitespace(STRBUF(inbuf)+5)); else if (strncasecmp(STRBUF(inbuf), "subject:", 8) == 0) subjectline = strdup(skipwhitespace(STRBUF(inbuf)+8)); } freestrbuffer(inbuf); /* No subject ? No deal */ if (subjectline == NULL) { dbgprintf("Subject-line not found\n"); return 1; } /* Get the alert cookie */ subjexp = pcre_compile(".*(Xymon|Hobbit|BB)[ -]* \\[*(-*[0-9]+)[\\]!]*", PCRE_CASELESS, &errmsg, &errofs, NULL); if (subjexp == NULL) { dbgprintf("pcre compile failed - 1\n"); return 2; } result = pcre_exec(subjexp, NULL, subjectline, strlen(subjectline), 0, 0, ovector, (sizeof(ovector)/sizeof(int))); if (result < 0) { dbgprintf("Subject line did not match pattern\n"); return 3; /* Subject did not match what we expected */ } if (pcre_copy_substring(subjectline, ovector, result, 2, cookie, sizeof(cookie)) <= 0) { dbgprintf("Could not find cookie value\n"); return 4; /* No cookie */ } pcre_free(subjexp); /* See if there's a "DELAY=" delay-value also */ subjexp = pcre_compile(".*DELAY[ =]+([0-9]+[mhdw]*)", PCRE_CASELESS, &errmsg, &errofs, NULL); if (subjexp == NULL) { dbgprintf("pcre compile failed - 2\n"); return 2; } result = pcre_exec(subjexp, NULL, subjectline, strlen(subjectline), 0, 0, ovector, (sizeof(ovector)/sizeof(int))); if (result >= 0) { char delaytxt[4096]; if (pcre_copy_substring(subjectline, ovector, result, 1, delaytxt, sizeof(delaytxt)) > 0) { duration = durationvalue(delaytxt); } } pcre_free(subjexp); /* See if there's a "msg" text also */ subjexp = pcre_compile(".*MSG[ =]+(.*)", PCRE_CASELESS, &errmsg, &errofs, NULL); if (subjexp == NULL) { dbgprintf("pcre compile failed - 3\n"); return 2; } result = pcre_exec(subjexp, NULL, subjectline, strlen(subjectline), 0, 0, ovector, (sizeof(ovector)/sizeof(int))); if (result >= 0) { char msgtxt[4096]; if (pcre_copy_substring(subjectline, ovector, result, 1, msgtxt, sizeof(msgtxt)) > 0) { firsttxtline = strdup(msgtxt); } } pcre_free(subjexp); /* Use the "return-path:" header if we didn't see a From: line */ if ((fromline == NULL) && returnpathline) fromline = returnpathline; if (fromline) { /* Remove '<' and '>' from the fromline - they mess up HTML */ while ((p = strchr(fromline, '<')) != NULL) *p = ' '; while ((p = strchr(fromline, '>')) != NULL) *p = ' '; } /* Setup the acknowledge message */ if (duration == 0) duration = 60; /* Default: Ack for 60 minutes */ if (firsttxtline == NULL) firsttxtline = "<No cause specified>"; ackbuf = (char *)malloc(4096 + strlen(firsttxtline) + (fromline ? strlen(fromline) : 0)); p = ackbuf; p += sprintf(p, "xymondack %s %d %s", cookie, duration, firsttxtline); if (fromline) { p += sprintf(p, "\nAcked by: %s", fromline); } if (debug) { printf("%s\n", ackbuf); return 0; } sendmessage(ackbuf, NULL, XYMON_TIMEOUT, NULL); return 0; }
static void parse_query(void) { cgidata_t *cwalk; /* See what kind of request this is */ for (cwalk=cgidata; (cwalk); cwalk = cwalk->next) { if (nopin && (strcmp(cwalk->name, "Send_all") == 0)) { /* User pushed the "Send all" button */ reqtype = ACK_MANY; } else if (nopin && (strncmp(cwalk->name, "Send_", 5) == 0)) { /* User pushed a specific "Send" button */ sendnum = atoi(cwalk->name+5); reqtype = ACK_ONE; } else if (!nopin && (strcmp(cwalk->name, "Send") == 0)) { /* Old style request */ reqtype = ACK_OLDSTYLE; } } for (cwalk=cgidata; (cwalk); cwalk = cwalk->next) { /* * cwalk->name points to the name of the setting. * cwalk->value points to the value (may be an empty string). */ int id = 0; char *acknum = NULL, *validity = NULL, *ackmsg = NULL, *period = NULL; char *hostname = NULL, *testname = NULL, *checked = NULL; char *delim; if (strncasecmp(cwalk->name, "NUMBER", 6) == 0) { if (*cwalk->value) acknum = cwalk->value; delim = strchr(cwalk->name, '_'); if (delim) id = atoi(delim+1); } else if (strcasecmp(cwalk->name, "DELAY_all") == 0) { if (*cwalk->value) validityall = cwalk->value; } else if (strcasecmp(cwalk->name, "PERIOD_all") == 0) { if (*cwalk->value) periodall = cwalk->value; } else if (strcasecmp(cwalk->name, "MESSAGE_all") == 0) { if (*cwalk->value) ackmsgall = cwalk->value; } else if (strncasecmp(cwalk->name, "DELAY", 5) == 0) { if (*cwalk->value) validity = cwalk->value; delim = strchr(cwalk->name, '_'); if (delim) id = atoi(delim+1); } else if (strncasecmp(cwalk->name, "PERIOD", 5) == 0) { if (*cwalk->value) period = cwalk->value; delim = strchr(cwalk->name, '_'); if (delim) id = atoi(delim+1); } else if (strncasecmp(cwalk->name, "MESSAGE", 7) == 0) { if (*cwalk->value) ackmsg = cwalk->value; delim = strchr(cwalk->name, '_'); if (delim) id = atoi(delim+1); } else if (strncasecmp(cwalk->name, "HOSTNAME", 8) == 0) { if (*cwalk->value) hostname = cwalk->value; delim = strchr(cwalk->name, '_'); if (delim) id = atoi(delim+1); } else if (strncasecmp(cwalk->name, "TESTNAME", 8) == 0) { if (*cwalk->value) testname = cwalk->value; delim = strchr(cwalk->name, '_'); if (delim) id = atoi(delim+1); } else if (strncasecmp(cwalk->name, "CHECKED", 7) == 0) { if (*cwalk->value) checked = cwalk->value; delim = strchr(cwalk->name, '_'); if (delim) id = atoi(delim+1); } switch (reqtype) { case ACK_UNKNOWN: break; case ACK_OLDSTYLE: id = 1; /* Fall through */ case ACK_ONE: if ((id == sendnum) || (reqtype == ACK_OLDSTYLE)) checked = "checked"; /* Fall through */ case ACK_MANY: if (id) { acklist_t *awalk; awalk = ackhead; while (awalk && (awalk->id != id)) awalk = awalk->next; if (!awalk) { awalk = (acklist_t *)calloc(1, sizeof(acklist_t)); awalk->id = id; awalk->next = NULL; if (!ackhead) ackhead = acktail = awalk; else { acktail->next = awalk; acktail = awalk; } } if (acknum) awalk->acknum = atoi(acknum); if (validity) awalk->validity = durationvalue(validity); if (ackmsg) awalk->ackmsg = strdup(ackmsg); if (hostname) awalk->hostname = strdup(hostname); if (testname) awalk->testname = strdup(testname); if (period) awalk->period = strdup(period); if (checked) awalk->checked = 1; } break; } } }
int main(int argc, char *argv[]) { int argi; char *envarea = NULL; int obeycookies = 1; char *accessfn = NULL; 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 (strcmp(argv[argi], "--no-pin") == 0) { nopin = 1; } else if (strcmp(argv[argi], "--no-cookies") == 0) { obeycookies = 0; } else if (argnmatch(argv[argi], "--access=")) { char *p = strchr(argv[argi], '='); accessfn = strdup(p+1); } } redirect_cgilog("ack"); cgidata = cgi_request(); if ( (nopin && (cgi_method == CGI_GET)) || (!nopin && (cgidata == NULL)) ) { /* Present the query form */ sethostenv("", "", "", colorname(COL_RED), NULL); printf("Content-Type: %s\n\n", xgetenv("HTMLCONTENTTYPE")); if (!nopin) { showform(stdout, "acknowledge", "acknowledge_form", COL_RED, getcurrenttime(NULL), NULL, NULL); } else { char *cmd; char *respbuf = NULL; char *hostname, *pagename; int gotfilter = 0, filtererror = 0; sendreturn_t *sres = NULL; int col, firstcolor = 1, alertcolors = colorset(xgetenv("ALERTCOLORS"), ((1 << COL_GREEN) | (1 << COL_BLUE))); headfoot(stdout, "acknowledge", "", "header", COL_RED); cmd = (char *)malloc(1024); strcpy(cmd, "xymondboard fields=hostname,testname,cookie color="); for (col = 0; (col < COL_COUNT); col++) { if ((1 << col) & alertcolors) { if (!firstcolor) strcat(cmd, ","); strcat(cmd, colorname(col)); firstcolor = 0; } } // printf("<!-- cmd = %s -->\n", cmd); if (obeycookies && !gotfilter && ((hostname = get_cookie("host")) != NULL)) { if (*hostname) { pcre *dummy; char *re; re = (char *)malloc(3+strlen(hostname)); sprintf(re, "^%s$", hostname); dummy = compileregex(re); if (dummy) { /* Valid expression */ freeregex(dummy); cmd = (char *)realloc(cmd, 1024 + strlen(cmd) + strlen(re)); sprintf(cmd + strlen(cmd), " host=%s", re); gotfilter = 1; } else { filtererror = 1; printf("<p align=\"center\">Invalid hostname filter</p>\n"); } } } if (obeycookies && !gotfilter && ((pagename = get_cookie("pagepath")) != NULL)) { if (*pagename) { pcre *dummy; char *re; re = (char *)malloc(8 + strlen(pagename)*2); sprintf(re, "%s$|^%s/.+", pagename, pagename); dummy = compileregex(re); if (dummy) { /* Valid expression */ freeregex(dummy); cmd = (char *)realloc(cmd, 1024 + strlen(cmd) + strlen(re)); sprintf(cmd + strlen(cmd), " page=%s", re); gotfilter = 1; } else { filtererror = 1; printf("<p align=\"center\">Invalid pagename filter</p>\n"); } } } sres = newsendreturnbuf(1, NULL); if (!filtererror && (sendmessage(cmd, NULL, XYMON_TIMEOUT, sres) == XYMONSEND_OK)) { char *bol, *eoln; int first = 1; respbuf = getsendreturnstr(sres, 1); bol = respbuf; while (bol) { char *hname, *tname, *ackcode; eoln = strchr(bol, '\n'); if (eoln) *eoln = '\0'; hname = tname = ackcode = NULL; hname = strtok(bol, "|"); if (hname) tname = strtok(NULL, "|"); if (tname) ackcode = strtok(NULL, "|"); if (hname && tname && ackcode && (strcmp(hname, "summary") != 0)) { if (first) { fprintf(stdout, "<form method=\"POST\" ACTION=\"%s\">\n", getenv("SCRIPT_NAME")); fprintf(stdout, "<center><table cellpadding=5 summary=\"Ack data\">\n"); fprintf(stdout, "<tr><th align=left>Host</th><th align=left>Test</th><th align=left>Duration</th><th align=left>Cause</th><th>Ack</th><th>Ack Multiple</tr>\n"); first = 0; } generate_ackline(stdout, hname, tname, ackcode); } if (eoln) bol = eoln+1; else bol = NULL; } if (first) { fprintf(stdout, "<center><font size=\"+1\"><b>No active alerts</b></font></center>\n"); } else { generate_ackline(stdout, NULL, NULL, NULL); fprintf(stdout, "</table></center>\n"); fprintf(stdout, "</form>\n"); } } freesendreturnbuf(sres); headfoot(stdout, "acknowledge", "", "footer", COL_RED); } } else if ( (nopin && (cgi_method == CGI_POST)) || (!nopin && (cgidata != NULL)) ) { char *xymonmsg; char *acking_user = ""; acklist_t *awalk; strbuffer_t *response = newstrbuffer(0); int count = 0; /* We only want to accept posts from certain pages */ { char cgisource[1024]; char *p; p = csp_header("acknowledge"); if (p) fprintf(stdout, "%s", p); snprintf(cgisource, sizeof(cgisource), "%s/%s", xgetenv("SECURECGIBINURL"), "acknowledge"); if (!cgi_refererok(cgisource)) { fprintf(stdout, "Location: %s.sh?\n\n", cgisource); return 0; } } parse_query(); if (getenv("REMOTE_USER")) { char *remaddr = getenv("REMOTE_ADDR"); acking_user = (char *)malloc(1024 + strlen(getenv("REMOTE_USER")) + (remaddr ? strlen(remaddr) : 0)); sprintf(acking_user, "\nAcked by: %s", getenv("REMOTE_USER")); if (remaddr) sprintf(acking_user + strlen(acking_user), " (%s)", remaddr); } /* Load the host data (for access control) */ if (accessfn) { load_hostnames(xgetenv("HOSTSCFG"), NULL, get_fqdn()); load_web_access_config(accessfn); } addtobuffer(response, "<center>\n"); for (awalk = ackhead; (awalk); awalk = awalk->next) { char *msgline = (char *)malloc(1024 + (awalk->hostname ? strlen(awalk->hostname) : 0) + (awalk->testname ? strlen(awalk->testname) : 0)); if (!awalk->checked) continue; if (accessfn && (!web_access_allowed(getenv("REMOTE_USER"), awalk->hostname, awalk->testname, WEB_ACCESS_CONTROL))) continue; if ((reqtype == ACK_ONE) && (awalk->id != sendnum)) continue; if (reqtype == ACK_MANY) { if (!awalk->ackmsg) awalk->ackmsg = ackmsgall; if (!awalk->validity && validityall) awalk->validity = durationvalue(validityall); if (periodall) awalk->period = periodall; } if (strncmp(awalk->period, "hour", 4) == 0) awalk->validity *= 60; else if (strncmp(awalk->period, "day", 4) == 0) awalk->validity *= 60*24; count++; if (!awalk->ackmsg || !awalk->validity || !awalk->acknum) { if (awalk->hostname && awalk->testname) { sprintf(msgline, "<b>NO ACK</b> sent for host %s / test %s", htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); } else { sprintf(msgline, "<b>NO ACK</b> sent for item %d", awalk->id); } addtobuffer(response, msgline); addtobuffer(response, ": Duration or message not set<br>\n"); continue; } xymonmsg = (char *)malloc(1024 + strlen(awalk->ackmsg) + strlen(acking_user)); sprintf(xymonmsg, "xymondack %d %d %s %s", awalk->acknum, awalk->validity, awalk->ackmsg, acking_user); if (sendmessage(xymonmsg, NULL, XYMON_TIMEOUT, NULL) == XYMONSEND_OK) { if (awalk->hostname && awalk->testname) { sprintf(msgline, "Acknowledge sent for host %s / test %s<br>\n", htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); } else { sprintf(msgline, "Acknowledge sent for code %d<br>\n", awalk->acknum); } } else { if (awalk->hostname && awalk->testname) { sprintf(msgline, "Failed to send acknowledge for host %s / test %s<br>\n", htmlquoted(awalk->hostname), htmlquoted(awalk->testname)); } else { sprintf(msgline, "Failed to send acknowledge for code %d<br>\n", awalk->acknum); } } addtobuffer(response, msgline); xfree(xymonmsg); } if (count == 0) addtobuffer(response, "<b>No acks requested</b>\n"); addtobuffer(response, "</center>\n"); fprintf(stdout, "Content-type: %s\n\n", xgetenv("HTMLCONTENTTYPE")); headfoot(stdout, "acknowledge", "", "header", COL_RED); fprintf(stdout, "%s", STRBUF(response)); headfoot(stdout, "acknowledge", "", "footer", COL_RED); } return 0; }
int load_alertconfig(char *configfn, int defcolors, int defaultinterval) { /* (Re)load the configuration file without leaking memory */ static void *configfiles = NULL; char fn[PATH_MAX]; FILE *fd; strbuffer_t *inbuf; char *p; rule_t *currule = NULL; recip_t *currcp = NULL, *rcptail = NULL; MEMDEFINE(fn); if (configfn) strcpy(fn, configfn); else sprintf(fn, "%s/etc/alerts.cfg", xgetenv("XYMONHOME")); /* First check if there were no modifications at all */ if (configfiles) { if (!stackfmodified(configfiles)){ dbgprintf("No files modified, skipping reload of %s\n", fn); MEMUNDEFINE(fn); return 0; } else { stackfclist(&configfiles); configfiles = NULL; } } fd = stackfopen(fn, "r", &configfiles); if (!fd) { errprintf("Cannot open configuration file %s: %s\n", fn, strerror(errno)); MEMUNDEFINE(fn); return 0; } /* First, clean out the old rule set */ while (rulehead) { rule_t *trule; if (rulehead->criteria) { free_criteria(rulehead->criteria); xfree(rulehead->criteria); } while (rulehead->recipients) { recip_t *trecip = rulehead->recipients; if (trecip->criteria) { recip_t *rwalk; /* Clear out the duplicate criteria that may exist, to avoid double-free'ing them */ for (rwalk = trecip->next; (rwalk); rwalk = rwalk->next) { if (rwalk->criteria == trecip->criteria) rwalk->criteria = NULL; } free_criteria(trecip->criteria); xfree(trecip->criteria); } if (trecip->recipient) xfree(trecip->recipient); if (trecip->scriptname) xfree(trecip->scriptname); rulehead->recipients = rulehead->recipients->next; xfree(trecip); } trule = rulehead; rulehead = rulehead->next; xfree(trule); } while (tokhead) { token_t *ttok; if (tokhead->name) xfree(tokhead->name); if (tokhead->value) xfree(tokhead->value); ttok = tokhead; tokhead = tokhead->next; xfree(ttok); } defaultcolors = defcolors; MEMDEFINE(cfline); cfid = 0; inbuf = newstrbuffer(0); while (stackfgets(inbuf, NULL)) { int firsttoken = 1; int mailcmdactive = 0, scriptcmdactive = 0; recip_t *curlinerecips = NULL; cfid++; sanitize_input(inbuf, 1, 0); /* Skip empty lines */ if (STRBUFLEN(inbuf) == 0) continue; if ((*STRBUF(inbuf) == '$') && strchr(STRBUF(inbuf), '=')) { /* Define a macro */ token_t *newtok = (token_t *) malloc(sizeof(token_t)); char *delim; delim = strchr(STRBUF(inbuf), '='); *delim = '\0'; newtok->name = strdup(STRBUF(inbuf)+1); /* Skip the '$' */ newtok->value = strdup(preprocess(delim+1)); newtok->next = tokhead; tokhead = newtok; continue; } strncpy(cfline, STRBUF(inbuf), (sizeof(cfline)-1)); cfline[sizeof(cfline)-1] = '\0'; /* Expand macros inside the line before parsing */ p = strtok(preprocess(STRBUF(inbuf)), " \t"); while (p) { if ((strncasecmp(p, "PAGE=", 5) == 0) || (strncasecmp(p, "PAGES=", 6) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->pagespec = strdup(val); if (*(crit->pagespec) == '%') crit->pagespecre = compileregex(crit->pagespec+1); firsttoken = 0; } else if ((strncasecmp(p, "EXPAGE=", 7) == 0) || (strncasecmp(p, "EXPAGES=", 8) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->expagespec = strdup(val); if (*(crit->expagespec) == '%') crit->expagespecre = compileregex(crit->expagespec+1); firsttoken = 0; } else if ((strncasecmp(p, "DISPLAYGROUP=", 13) == 0) || (strncasecmp(p, "DISPLAYGROUPS=", 14) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->dgspec = strdup(val); if (*(crit->dgspec) == '%') crit->dgspecre = compileregex(crit->dgspec+1); firsttoken = 0; } else if ((strncasecmp(p, "EXDISPLAYGROUP=", 15) == 0) || (strncasecmp(p, "EXDISPLAYGROUPS=", 16) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->exdgspec = strdup(val); if (*(crit->exdgspec) == '%') crit->exdgspecre = compileregex(crit->exdgspec+1); firsttoken = 0; } else if ((strncasecmp(p, "HOST=", 5) == 0) || (strncasecmp(p, "HOSTS=", 6) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->hostspec = strdup(val); if (*(crit->hostspec) == '%') crit->hostspecre = compileregex(crit->hostspec+1); firsttoken = 0; } else if ((strncasecmp(p, "EXHOST=", 7) == 0) || (strncasecmp(p, "EXHOSTS=", 8) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->exhostspec = strdup(val); if (*(crit->exhostspec) == '%') crit->exhostspecre = compileregex(crit->exhostspec+1); firsttoken = 0; } else if ((strncasecmp(p, "SERVICE=", 8) == 0) || (strncasecmp(p, "SERVICES=", 9) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->svcspec = strdup(val); if (*(crit->svcspec) == '%') crit->svcspecre = compileregex(crit->svcspec+1); firsttoken = 0; } else if ((strncasecmp(p, "EXSERVICE=", 10) == 0) || (strncasecmp(p, "EXSERVICES=", 11) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->exsvcspec = strdup(val); if (*(crit->exsvcspec) == '%') crit->exsvcspecre = compileregex(crit->exsvcspec+1); firsttoken = 0; } else if (strncasecmp(p, "CLASS=", 6) == 0) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->classspec = strdup(val); if (*(crit->classspec) == '%') crit->classspecre = compileregex(crit->classspec+1); firsttoken = 0; } else if (strncasecmp(p, "EXCLASS=", 8) == 0) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->exclassspec = strdup(val); if (*(crit->exclassspec) == '%') crit->exclassspecre = compileregex(crit->exclassspec+1); firsttoken = 0; } else if (strncasecmp(p, "GROUP=", 6) == 0) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->groupspec = strdup(val); if (*(crit->groupspec) == '%') crit->groupspecre = compileregex(crit->groupspec+1); firsttoken = 0; } else if (strncasecmp(p, "EXGROUP=", 8) == 0) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->exgroupspec = strdup(val); if (*(crit->exgroupspec) == '%') crit->exgroupspecre = compileregex(crit->exgroupspec+1); firsttoken = 0; } else if ((strncasecmp(p, "COLOR=", 6) == 0) || (strncasecmp(p, "COLORS=", 7) == 0)) { criteria_t *crit; char *c1, *c2; int cval, reverse = 0; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } crit = setup_criteria(&currule, &currcp); /* Put a value in crit->colors so we know there is an explicit color setting */ crit->colors = (1 << 30); c1 = strchr(p, '=')+1; /* * If the first colorspec is "!color", then apply the default colors and * subtract colors from that. */ if (*c1 == '!') crit->colors |= defaultcolors; do { c2 = strchr(c1, ','); if (c2) *c2 = '\0'; if (*c1 == '!') { reverse=1; c1++; } cval = (1 << parse_color(c1)); if (reverse) crit->colors &= (~cval); else crit->colors |= cval; if (c2) c1 = (c2+1); else c1 = NULL; } while (c1); firsttoken = 0; } else if ((strncasecmp(p, "TIME=", 5) == 0) || (strncasecmp(p, "TIMES=", 6) == 0)) { char *val; criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } val = strchr(p, '=')+1; crit = setup_criteria(&currule, &currcp); crit->timespec = strdup(val); firsttoken = 0; } else if (strncasecmp(p, "DURATION", 8) == 0) { criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } crit = setup_criteria(&currule, &currcp); if (*(p+8) == '>') crit->minduration = 60*durationvalue(p+9); else if (*(p+8) == '<') crit->maxduration = 60*durationvalue(p+9); else errprintf("Ignoring invalid DURATION at line %d: %s\n",cfid, p); firsttoken = 0; } else if (strncasecmp(p, "RECOVERED", 9) == 0) { criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } crit = setup_criteria(&currule, &currcp); crit->sendrecovered = SR_WANTED; firsttoken = 0; } else if (strncasecmp(p, "NORECOVERED", 11) == 0) { criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } crit = setup_criteria(&currule, &currcp); crit->sendrecovered = SR_NOTWANTED; firsttoken = 0; } else if (strncasecmp(p, "NOTICE", 6) == 0) { criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } crit = setup_criteria(&currule, &currcp); crit->sendnotice = SR_WANTED; firsttoken = 0; } else if (strncasecmp(p, "NONOTICE", 8) == 0) { criteria_t *crit; if (firsttoken) { flush_rule(currule); currule = NULL; currcp = NULL; pstate = P_NONE; } crit = setup_criteria(&currule, &currcp); crit->sendnotice = SR_NOTWANTED; firsttoken = 0; } else if ((pstate == P_RECIP) && (strncasecmp(p, "FORMAT=", 7) == 0)) { if (!currcp) errprintf("FORMAT used without a recipient (line %d), ignored\n", cfid); else if (strcasecmp(p+7, "TEXT") == 0) currcp->format = ALERTFORM_TEXT; else if (strcasecmp(p+7, "PLAIN") == 0) currcp->format = ALERTFORM_PLAIN; else if (strcasecmp(p+7, "SMS") == 0) currcp->format = ALERTFORM_SMS; else if (strcasecmp(p+7, "PAGER") == 0) currcp->format = ALERTFORM_PAGER; else if (strcasecmp(p+7, "SCRIPT") == 0) currcp->format = ALERTFORM_SCRIPT; else errprintf("Unknown FORMAT setting '%s' ignored\n", p); firsttoken = 0; } else if ((pstate == P_RECIP) && (strncasecmp(p, "REPEAT=", 7) == 0)) { if (!currcp) errprintf("REPEAT used without a recipient (line %d), ignored\n", cfid); else currcp->interval = 60*durationvalue(p+7); firsttoken = 0; } else if ((pstate == P_RECIP) && (strcasecmp(p, "STOP") == 0)) { if (!currcp) errprintf("STOP used without a recipient (line %d), ignored\n", cfid); else currcp->stoprule = 1; firsttoken = 0; } else if ((pstate == P_RECIP) && (strcasecmp(p, "UNMATCHED") == 0)) { if (!currcp) errprintf("UNMATCHED used without a recipient (line %d), ignored\n", cfid); else currcp->unmatchedonly = 1; firsttoken = 0; } else if ((pstate == P_RECIP) && (strncasecmp(p, "NOALERT", 7) == 0)) { if (!currcp) errprintf("NOALERT used without a recipient (line %d), ignored\n", cfid); else currcp->noalerts = 1; firsttoken = 0; } else if (currule && ((strncasecmp(p, "MAIL", 4) == 0) || mailcmdactive) ) { recip_t *newrcp; mailcmdactive = 1; newrcp = (recip_t *)calloc(1, sizeof(recip_t)); newrcp->cfid = cfid; newrcp->method = M_MAIL; newrcp->format = ALERTFORM_TEXT; if (strncasecmp(p, "MAIL=", 5) == 0) { p += 5; } else if (strcasecmp(p, "MAIL") == 0) { p = strtok(NULL, " \t"); } else { /* Second recipient on a rule - do nothing */ } if (p) { newrcp->recipient = strdup(p); newrcp->interval = defaultinterval; currcp = newrcp; if (curlinerecips == NULL) curlinerecips = newrcp; pstate = P_RECIP; if (currule->recipients == NULL) currule->recipients = rcptail = newrcp; else { rcptail->next = newrcp; rcptail = newrcp; } } else { errprintf("Ignoring MAIL with no recipient at line %d\n", cfid); xfree(newrcp); } firsttoken = 0; } else if (currule && ((strncasecmp(p, "SCRIPT", 6) == 0) || scriptcmdactive)) { recip_t *newrcp; scriptcmdactive = 1; newrcp = (recip_t *)calloc(1, sizeof(recip_t)); newrcp->cfid = cfid; newrcp->method = M_SCRIPT; newrcp->format = ALERTFORM_SCRIPT; if (strncasecmp(p, "SCRIPT=", 7) == 0) { p += 7; newrcp->scriptname = strdup(p); p = strtok(NULL, " \t"); } else if (strcasecmp(p, "SCRIPT") == 0) { p = strtok(NULL, " \t"); if (p) { newrcp->scriptname = strdup(p); p = strtok(NULL, " \t"); } else { errprintf("Invalid SCRIPT command at line %d\n", cfid); } } else { /* A second recipient for the same script as the previous one */ newrcp->scriptname = strdup(currcp->scriptname); } if (p) { newrcp->recipient = strdup(p); newrcp->interval = defaultinterval; currcp = newrcp; if (curlinerecips == NULL) curlinerecips = newrcp; pstate = P_RECIP; if (currule->recipients == NULL) currule->recipients = rcptail = newrcp; else { rcptail->next = newrcp; rcptail = newrcp; } } else { errprintf("Ignoring SCRIPT with no recipient at line %d\n", cfid); if (newrcp->scriptname) xfree(newrcp->scriptname); xfree(newrcp); } firsttoken = 0; } else if (currule && (strncasecmp(p, "IGNORE", 6) == 0)) { recip_t *newrcp; newrcp = (recip_t *)calloc(1, sizeof(recip_t)); newrcp->cfid = cfid; newrcp->method = M_IGNORE; newrcp->format = ALERTFORM_NONE; newrcp->interval = defaultinterval; newrcp->stoprule = 1; currcp = newrcp; if (curlinerecips == NULL) curlinerecips = newrcp; pstate = P_RECIP; if (currule->recipients == NULL) currule->recipients = rcptail = newrcp; else { rcptail->next = newrcp; rcptail = newrcp; } firsttoken = 0; } else { errprintf("Ignored unknown/unexpected token '%s' at line %d\n", p, cfid); } if (p) p = strtok(NULL, " \t"); } if (curlinerecips && currcp && (curlinerecips != currcp)) { /* We have multiple recipients on one line. Make sure criteria etc. get copied */ recip_t *rwalk; /* All criteria etc. have been set on the last recipient (currcp) */ for (rwalk = curlinerecips; (rwalk != currcp); rwalk = rwalk->next) { rwalk->format = currcp->format; rwalk->interval = currcp->interval; rwalk->criteria = currcp->criteria; rwalk->noalerts = currcp->noalerts; } } } flush_rule(currule); stackfclose(fd); freestrbuffer(inbuf); MEMUNDEFINE(cfline); MEMUNDEFINE(fn); return 1; }