isc_result_t perf_datafile_next(perf_datafile_t *dfile, isc_buffer_t *lines, isc_boolean_t is_update) { const char *current; isc_result_t result; LOCK(&dfile->lock); if (dfile->maxruns > 0 && dfile->maxruns == dfile->nruns) { result = ISC_R_EOF; goto done; } result = read_one_line(dfile, lines); if (result == ISC_R_EOF) { if (!dfile->read_any) { result = ISC_R_INVALIDFILE; goto done; } if (dfile->maxruns != dfile->nruns) { reopen_file(dfile); result = read_one_line(dfile, lines); } } if (result != ISC_R_SUCCESS) { goto done; } dfile->read_any = ISC_TRUE; if (is_update) { while (ISC_TRUE) { current = isc_buffer_used(lines); result = read_one_line(dfile, lines); if (result == ISC_R_EOF && dfile->maxruns != dfile->nruns) { reopen_file(dfile); } if (result != ISC_R_SUCCESS || strcasecmp(current, "send") == 0) break; }; } result = ISC_R_SUCCESS; done: UNLOCK(&dfile->lock); return (result); }
void sigmisc_handler(int signum) { switch (signum) { case SIGTERM: errprintf("Caught TERM signal, terminating\n"); keeprunning = 0; break; case SIGHUP: if (logfile) { reopen_file(logfile, "a", stdout); reopen_file(logfile, "a", stderr); errprintf("Caught SIGHUP, reopening logfile\n"); } break; } }
/************************************************************************ * * * mmap_reopen_file() - Reopen memory mapped input or output file. * * * * Inputs: dip = The device information pointer. * * oflags = The device/file open flags. * * * * Return Value: * * Returns 0 / -1 = SUCESS / FAILURE. * * * ************************************************************************/ int mmap_reopen_file (struct dinfo *dip, int oflags) { /* * For memory mapped files, remove the mappings before closing * the file. */ if (mmap_flag) { if (munmap ((caddr_t)mmap_buffer, data_limit) == FAILURE) { report_error ("munmap", TRUE); terminate (errno); } mmap_bufptr = mmap_buffer = (u_char *) 0; } return (reopen_file (dip, oflags)); }
void main_event_loop() { fgbg=(_app?FG:BG); while(!quit) { if(closed_acc) { evnt_timer(1000,0); #ifdef DEBUG form_alert(1,"[1][ACC reopened][Ok]"); #endif fg_init(&windforms[WIND_CTRL]); if(file_was_open) fd=reopen_file(); closed_acc=0; } if(fgbg==FG) fg_event_loop(); else if(fgbg==BG) bg_event_loop(); } }
int main(int argc, char *argv[]) { int daemonize = 1; int listenq = 10; char *pidfile = "msgcache.pid"; int lsocket; struct sockaddr_in laddr; struct sigaction sa; int opt; /* Dont save the output from errprintf() */ save_errbuf = 0; memset(&laddr, 0, sizeof(laddr)); inet_aton("0.0.0.0", (struct in_addr *) &laddr.sin_addr.s_addr); laddr.sin_port = htons(1984); laddr.sin_family = AF_INET; for (opt=1; (opt < argc); opt++) { if (argnmatch(argv[opt], "--listen=")) { char *locaddr, *p; int locport; locaddr = strchr(argv[opt], '=')+1; p = strchr(locaddr, ':'); if (p) { locport = atoi(p+1); *p = '\0'; } else locport = 1984; memset(&laddr, 0, sizeof(laddr)); laddr.sin_port = htons(locport); laddr.sin_family = AF_INET; if (inet_aton(locaddr, (struct in_addr *) &laddr.sin_addr.s_addr) == 0) { errprintf("Invalid listen address %s\n", locaddr); return 1; } } else if (argnmatch(argv[opt], "--server=")) { /* Who is allowed to fetch cached messages */ char *p = strchr(argv[opt], '='); serverlist = getsenderlist(p+1); } else if (argnmatch(argv[opt], "--max-age=")) { char *p = strchr(argv[opt], '='); maxage = atoi(p+1); } else if (argnmatch(argv[opt], "--lqueue=")) { char *p = strchr(argv[opt], '='); listenq = atoi(p+1); } else if (strcmp(argv[opt], "--daemon") == 0) { daemonize = 1; } else if (strcmp(argv[opt], "--no-daemon") == 0) { daemonize = 0; } else if (argnmatch(argv[opt], "--pidfile=")) { char *p = strchr(argv[opt], '='); pidfile = strdup(p+1); } else if (argnmatch(argv[opt], "--logfile=")) { char *p = strchr(argv[opt], '='); logfile = strdup(p+1); } else if (strcmp(argv[opt], "--debug") == 0) { debug = 1; } else if (strcmp(argv[opt], "--version") == 0) { printf("xymonproxy version %s\n", VERSION); return 0; } } /* Set up a socket to listen for new connections */ lsocket = socket(AF_INET, SOCK_STREAM, 0); if (lsocket == -1) { errprintf("Cannot create listen socket (%s)\n", strerror(errno)); return 1; } opt = 1; setsockopt(lsocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); fcntl(lsocket, F_SETFL, O_NONBLOCK); if (bind(lsocket, (struct sockaddr *)&laddr, sizeof(laddr)) == -1) { errprintf("Cannot bind to listen socket (%s)\n", strerror(errno)); return 1; } if (listen(lsocket, listenq) == -1) { errprintf("Cannot listen (%s)\n", strerror(errno)); return 1; } /* Redirect logging to the logfile, if requested */ if (logfile) { reopen_file(logfile, "a", stdout); reopen_file(logfile, "a", stderr); } errprintf("Xymon msgcache version %s starting\n", VERSION); errprintf("Listening on %s:%d\n", inet_ntoa(laddr.sin_addr), ntohs(laddr.sin_port)); if (daemonize) { pid_t childpid; reopen_file("/dev/null", "r", stdin); /* Become a daemon */ childpid = fork(); if (childpid < 0) { /* Fork failed */ errprintf("Could not fork\n"); exit(1); } else if (childpid > 0) { /* Parent - save PID and exit */ FILE *fd = fopen(pidfile, "w"); if (fd) { fprintf(fd, "%d\n", (int)childpid); fclose(fd); } exit(0); } /* Child (daemon) continues here */ setsid(); } setup_signalhandler("msgcache"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigmisc_handler; sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); do { fd_set fdread, fdwrite; int maxfd; int n; conn_t *cwalk, *cprev; msgqueue_t *qwalk, *qprev; time_t mintstamp; /* Remove any finished connections */ cwalk = chead; cprev = NULL; while (cwalk) { conn_t *zombie; if (cwalk->action != C_DONE) { cprev = cwalk; cwalk = cwalk->next; continue; } /* Close the socket */ close(cwalk->sockfd); zombie = cwalk; if (cprev == NULL) { chead = zombie->next; cwalk = chead; cprev = NULL; } else { cprev->next = zombie->next; cwalk = zombie->next; } freestrbuffer(zombie->msgbuf); xfree(zombie); } ctail = chead; if (ctail) { while (ctail->next) ctail = ctail->next; } /* Remove expired messages */ qwalk = qhead; qprev = NULL; mintstamp = getcurrenttime(NULL) - maxage; while (qwalk) { msgqueue_t *zombie; if (qwalk->tstamp > mintstamp) { /* Hasn't expired yet */ qprev = qwalk; qwalk = qwalk->next; continue; } zombie = qwalk; if (qprev == NULL) { qhead = zombie->next; qwalk = qhead; qprev = NULL; } else { qprev->next = zombie->next; qwalk = zombie->next; } freestrbuffer(zombie->msgbuf); xfree(zombie); } qtail = qhead; if (qtail) { while (qtail->next) qtail = qtail->next; } /* Now we're ready to handle some data */ FD_ZERO(&fdread); FD_ZERO(&fdwrite); /* Add the listen socket */ FD_SET(lsocket, &fdread); maxfd = lsocket; for (cwalk = chead; (cwalk); cwalk = cwalk->next) { switch (cwalk->action) { case C_READING: FD_SET(cwalk->sockfd, &fdread); if (cwalk->sockfd > maxfd) maxfd = cwalk->sockfd; break; case C_WRITING: FD_SET(cwalk->sockfd, &fdwrite); if (cwalk->sockfd > maxfd) maxfd = cwalk->sockfd; break; case C_DONE: break; } } n = select(maxfd+1, &fdread, &fdwrite, NULL, NULL); if (n < 0) { if (errno == EINTR) continue; errprintf("select failed: %s\n", strerror(errno)); return 0; } if (n == 0) continue; /* Timeout */ for (cwalk = chead; (cwalk); cwalk = cwalk->next) { switch (cwalk->action) { case C_READING: if (FD_ISSET(cwalk->sockfd, &fdread)) grabdata(cwalk); break; case C_WRITING: if (FD_ISSET(cwalk->sockfd, &fdwrite)) senddata(cwalk); break; case C_DONE: break; } } if (FD_ISSET(lsocket, &fdread)) { /* New incoming connection */ conn_t *newconn; int caddrsize; dbgprintf("New connection\n"); newconn = calloc(1, sizeof(conn_t)); caddrsize = sizeof(newconn->caddr); newconn->sockfd = accept(lsocket, (struct sockaddr *)&newconn->caddr, &caddrsize); if (newconn->sockfd == -1) { /* accept() failure. Yes, it does happen! */ dbgprintf("accept failure, ignoring connection (%s)\n", strerror(errno)); xfree(newconn); newconn = NULL; } else { fcntl(newconn->sockfd, F_SETFL, O_NONBLOCK); newconn->action = C_READING; newconn->msgbuf = newstrbuffer(0); newconn->tstamp = getcurrenttime(NULL); } if (newconn) { if (ctail) { ctail->next = newconn; ctail = newconn; } else chead = ctail = newconn; } } } while (keeprunning); if (pidfile) unlink(pidfile); return 0; }
int main(int argc, char *argv[]) { int daemonize = 0; int lsocket; struct sockaddr_in laddr; struct sigaction sa; int argi, opt; libxymon_init(argv[0]); /* Dont save the output from errprintf() */ save_errbuf = 0; memset(&laddr, 0, sizeof(laddr)); laddr.sin_addr.s_addr = htonl(INADDR_ANY); laddr.sin_port = htons(1984); laddr.sin_family = AF_INET; for (argi=1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--listen=")) { char *locaddr, *p; int locport; locaddr = strchr(argv[argi], '=')+1; p = strchr(locaddr, ':'); if (p) { locport = atoi(p+1); *p = '\0'; } else locport = 1984; memset(&laddr, 0, sizeof(laddr)); laddr.sin_port = htons(locport); laddr.sin_family = AF_INET; if (inet_aton(locaddr, (struct in_addr *) &laddr.sin_addr.s_addr) == 0) { errprintf("Invalid listen address %s\n", locaddr); return 1; } } else if (strcmp(argv[argi], "--daemon") == 0) { daemonize = 1; } else if (strcmp(argv[argi], "--no-daemon") == 0) { daemonize = 0; } else if (standardoption(argv[argi])) { if (showhelp) return 0; } } /* Set up a socket to listen for new connections */ lsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (lsocket == -1) { errprintf("Cannot create listen socket (%s)\n", strerror(errno)); return 1; } opt = 1; setsockopt(lsocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); if (bind(lsocket, (struct sockaddr *)&laddr, sizeof(laddr)) == -1) { errprintf("Cannot bind to listener address (%s)\n", strerror(errno)); return 1; } /* Make it non-blocking */ fcntl(lsocket, F_SETFL, O_NONBLOCK); /* Redirect logging to the logfn, if requested */ if (logfn) { reopen_file(logfn, "a", stdout); reopen_file(logfn, "a", stderr); } errprintf("Xymon locator version %s starting\n", VERSION); errprintf("Listening on %s:%d\n", inet_ntoa(laddr.sin_addr), ntohs(laddr.sin_port)); if (daemonize) { pid_t childpid; reopen_file("/dev/null", "r", stdin); /* Become a daemon */ childpid = fork(); if (childpid < 0) { /* Fork failed */ errprintf("Could not fork\n"); exit(1); } else if (childpid > 0) { /* Parent - exit */ exit(0); } /* Child (daemon) continues here */ setsid(); } setup_signalhandler("xymond_locator"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sigmisc_handler; sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); tree_init(); load_state(); do { ssize_t n; struct sockaddr_in remaddr; socklen_t remaddrsz; char buf[32768]; fd_set fdread; /* Wait for a message */ FD_ZERO(&fdread); FD_SET(lsocket, &fdread); n = select(lsocket+1, &fdread, NULL, NULL, NULL); if (n == -1) { /* Select error */ errprintf("select error, aborting: %s\n", strerror(errno)); keeprunning = 0; continue; } /* We know there is some data */ remaddrsz = sizeof(remaddr); n = recvfrom(lsocket, buf, sizeof(buf), 0, (struct sockaddr *)&remaddr, &remaddrsz); if (n == -1) { /* We may get EAGAIN if there is not a full message yet */ if (errno != EAGAIN) { errprintf("Recv error: %s\n", strerror(errno)); } continue; } else if (n == 0) { continue; } buf[n] = '\0'; dbgprintf("Got message from %s:%d : '%s'\n", inet_ntoa(remaddr.sin_addr), ntohs(remaddr.sin_port), buf); handle_request(buf); n = sendto(lsocket, buf, strlen(buf)+1, 0, (struct sockaddr *)&remaddr, remaddrsz); if (n == -1) { if (errno == EAGAIN) { errprintf("Out-queue full to %s, dropping response\n", inet_ntoa(remaddr.sin_addr)); } else { errprintf("Send failure %s while sending to %s\n", strerror(errno), inet_ntoa(remaddr.sin_addr)); } } } while (keeprunning); save_state(); return 0; }
int handle_message(int pipe[8]) { static int first_open=0; int wnr,error; /* ,avmsg[8]; */ char *vamsg,*o; #ifdef DEBUG char tmp[128]; #endif switch (pipe[0]) { case AC_OPEN: if (pipe[4] == acc_id) { if(first_open) { if(windforms[WIND_CTRL].wind_open) wind_set(windforms[WIND_CTRL].whandle,WF_TOP); else fgbg=FG; } else { fg_init(&windforms[WIND_CTRL]); fgbg=FG; first_open=1; } } #ifdef DEBUG form_alert(1,"[1][Got AC_OPEN][Ok]"); #endif break; case AC_CLOSE: /* if (pipe[4] == acc_id) */ { #ifdef DEBUG sprintf(tmp,"[1][Got AC_CLOSE|ACC id: %d|pipe4: %d][Ok]",acc_id,pipe[4]); form_alert(1,tmp); #endif if(windforms[WIND_CTRL].wind_open) { wind_close(windforms[WIND_CTRL].whandle); wind_delete(windforms[WIND_CTRL].whandle); windforms[WIND_CTRL].wind_open=0; } if(windforms[WIND_INFO].wind_open) { wind_close(windforms[WIND_INFO].whandle); wind_delete(windforms[WIND_INFO].whandle); windforms[WIND_INFO].wind_open=0; } #ifdef DEBUG sprintf(tmp,"[1][Filepos: %ld][Ok]",filepos); form_alert(1,tmp); #endif file_was_open=file_open; if(file_open) close_file(fd); closed_acc=1; return 1; } /* break; */ case AP_TERM: quit=1; return 1; /* switch(pipe[5]) { case AP_RESCHG: printf("Got AP_RESCHG!\n"); break; case AP_TERM: printf("Got AP_TERM!"); break; default: printf("Got unknown AP_TERM!"); } */ /* break; */ case RESCHG_COMPLETED: /* printf("Got RESCHG_COMPLETED!"); */ break; case WM_REDRAW: if((wnr=find_windform(pipe[3]))>=0) update_objects(&windforms[wnr],windforms[wnr].firstobj, windforms[wnr].objdepth,pipe); break; case WM_MOVED: if((wnr=find_windform(pipe[3]))>=0) { wind_set(windforms[wnr].whandle,WF_CURRXYWH,pipe[4],pipe[5],pipe[6],pipe[7]); windforms[wnr].wind.x=pipe[4]; windforms[wnr].wind.y=pipe[5]; windforms[wnr].wind.w=pipe[6]; windforms[wnr].wind.h=pipe[7]; wind_calc(WC_WORK,windforms[wnr].windkind, windforms[wnr].wind.x,windforms[wnr].wind.y, windforms[wnr].wind.w,windforms[wnr].wind.h, &windforms[wnr].form.x,&windforms[wnr].form.y, &windforms[wnr].form.w,&windforms[wnr].form.h); windforms[wnr].formtree[windforms[wnr].firstobj].ob_x=windforms[wnr].form.x; windforms[wnr].formtree[windforms[wnr].firstobj].ob_y=windforms[wnr].form.y; windforms[wnr].formtree[windforms[wnr].firstobj].ob_width=windforms[wnr].form.w; windforms[wnr].formtree[windforms[wnr].firstobj].ob_height=windforms[wnr].form.h; if(replay) update_time(); } break; case WM_CLOSED: if((wnr=find_windform(pipe[3]))>=0) { wind_close(windforms[wnr].whandle); windforms[wnr].wind_open=0; if(wnr==WIND_CTRL) { if(windforms[WIND_INFO].wind_open) { wind_close(windforms[WIND_INFO].whandle); windforms[WIND_INFO].wind_open=0; } return 1; } else wind_delete(windforms[wnr].whandle); } break; case WM_TOPPED: if((wnr=find_windform(pipe[3]))>=0) wind_set(pipe[3],WF_TOP); break; case AP_DRAGDROP: if(wind_find(pipe[4],pipe[5]) == windforms[WIND_CTRL].whandle) { if(do_dragdrop(pipe,DD_OK)) { exit_replay(); if(windforms[WIND_CTRL].formtree[CTRL_FF].ob_state & SELECTED) toggle_object(&windforms[WIND_CTRL],CTRL_FF,SET_NORMAL); Dsp_Hf1(0); if(windforms[WIND_CTRL].formtree[CTRL_PAUSE].ob_state & SELECTED) toggle_object(&windforms[WIND_CTRL],CTRL_PAUSE,SET_NORMAL); replay_pause=0; filepos=0; fd=reopen_file(); filesize=Fseek(0L,fd,2); Fseek(0L,fd,0); if((error=getmp2info(fd))==MP2_NOERR) { update_time(); setfilename(filename); if(!(pipe[6] & K_ALT)) init_replay(); } else { exit_replay(); show_mp2_error(error); close_file(fd); strcpy(windforms[WIND_CTRL].wind_title,"MPEG"); wind_set(windforms[WIND_CTRL].whandle,WF_NAME, windforms[WIND_CTRL].wind_title); setfilename("MPEGFILE"); } } } else { do_dragdrop(pipe,DD_NAK); } break; case VA_START: vamsg=*((char **)&pipe[3]); strcpy(path,vamsg); /* This *should* be sent to the application which sent the VA_START msg, but it seems to hang Thing doing it. */ /* avmsg[0]=AV_STARTED; avmsg[1]=app_id; avmsg[2]=0; avmsg[3]=pipe[3]; avmsg[4]=pipe[4]; appl_write(pipe[1],5*2,avmsg); */ if((o=strchr(path,' '))!=NULL) o[0]='\0'; o=strrchr(path,'\\'); strcpy(filename,&o[1]); o=strrchr(path,'\\'); strncpy(o,"\\*.MP?",6); o[6] = '\0'; exit_replay(); if(windforms[WIND_CTRL].formtree[CTRL_FF].ob_state & SELECTED) toggle_object(&windforms[WIND_CTRL],CTRL_FF,SET_NORMAL); Dsp_Hf1(0); if(windforms[WIND_CTRL].formtree[CTRL_PAUSE].ob_state & SELECTED) toggle_object(&windforms[WIND_CTRL],CTRL_PAUSE,SET_NORMAL); replay_pause=0; filepos=0; fd=reopen_file(); filesize=Fseek(0L,fd,2); Fseek(0L,fd,0); if((error=getmp2info(fd))==MP2_NOERR) { update_time(); setfilename(filename); init_replay(); } else { exit_replay(); show_mp2_error(error); close_file(fd); strcpy(windforms[WIND_CTRL].wind_title,"MPEG"); wind_set(windforms[WIND_CTRL].whandle,WF_NAME, windforms[WIND_CTRL].wind_title); setfilename("MPEGFILE"); } break; default: #ifdef DEBUG sprintf(tmp,"[1][Unimplemented| message: %d][Ok]",pipe[0]); form_alert(1,tmp); #endif break; } 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; }
/*-------------------------------------------------------------------------------------------------------*/ void simulation (void) { char job[1024] = "Jobs/"; char buf[32]; double temp; double perc; int timesteps; int ret_thread; time_t init_time; time_t current_time; time_t rem_time; char* time_string; // create a file to which we will write user output sprintf(buf, "%d", sim_number); strncat(job, buf, 32); FILE *file = fopen(job, "w+"); if (file == NULL) { fprintf(stderr, "File \"%s\" could not be opened, program will terminate. \n", job); return; } // Initiate timestep-counter and continuation value timesteps = 0; cont = 1; // initialize file and write first time setup of the system if (create_file(outfile, N, max_timesteps/write_step) == EXIT_FAILURE) { // variable for storing the amount of data already written int written; if (reopen_file(position, displacement, max_timesteps/write_step, &written) == EXIT_FAILURE) exit(EXIT_FAILURE); // iterate what timestep we are at timesteps = write_step * written; fprintf(file, "Timestep: %d\n", timesteps); } else { write_data(timesteps, position, displacement); } // increase timestep counter timesteps ++; // compute borders of all threads for(int i=0; i<(thread_number); i++) { borders[i] = i*(int)(N/thread_number); numbers[i] = i; } borders[thread_number] = N; // Initiate Threads and barrier, catch problems, number of threads is given in config-file pthread_barrier_init(&barrier_main_one, NULL, thread_number+1); pthread_barrier_init(&barrier_main_two, NULL, thread_number+1); pthread_barrier_init(&barrier_internal, NULL, thread_number); for (int i=0; i<thread_number; i++) { ret_thread = pthread_create(&(threads[i]), NULL, (void*)&iteration, &(numbers[i])); if (ret_thread != 0) { fprintf(stderr, "Thread %d could not be created. \n", i); exit(EXIT_FAILURE); } } // save time at iteration start and output simulation start to user time(&init_time); time_string = ctime(&init_time); fprintf(file, "Starting simulation ID: %d at %s" "Parameters N: %d, m: %.2lf, Gamma: %.0lf, Shear: %.0lf, Steps: %d\n\n", sim_number, time_string, N, m, Gamma_A, v_s, max_timesteps); fflush(file); // iterate over all timesteps while (timesteps <= max_timesteps) { // Synchronize all threads pthread_barrier_wait(&barrier_main_one); // Save maximum displacement of two particles, this determines when to update the Verlet-list for (int i=0; i<2*thread_number; i++) { if ((temp = verlet_max[i]) > verlet_max_1) { verlet_max_2 = verlet_max_1; verlet_max_1 = temp; } else if (temp > verlet_max_2) { verlet_max_2 = temp; } } // adjust orientation of upper and lower box row for both particle species box_A += v_A*delta_t; box_B += v_B*delta_t; // readjust box_A orientation when necessary if ((box_A - box_B) > 0.5) box_A -= 1; // implement periodic boundary conditions box_A -= floor(box_B*Li)*L; box_B -= floor(box_B*Li)*L; // check if verlet list has to be updated if ((verlet_max_1+verlet_max_2) > d_cutoff_verlet) { update_verlet(); verlet_max_1 = 0; verlet_max_2 = 0; } // check whether parameters should be written to declared external file if ((timesteps%write_step) == 0) { write_data(timesteps, position, displacement); // compute percentage of program already completed perc = (100.*timesteps)/max_timesteps; // compute elapsed program time time(¤t_time); rem_time = current_time - init_time; // give user a coherent overview fprintf(file, "ID: %d, Progress: \t\t[", sim_number); for(int i=0; i<floor(perc); i++) { fprintf(file, "="); } if (perc != 100) fprintf(file, ">"); for (int i=floor(perc)+1; i<100; i++) { fprintf(file, "."); } fprintf(file, "] \t%.1lf%%\t\telapsed time: %d s\r", perc, (int)(rem_time)); fflush(file); } // increase timesteps and continue waiting threads timesteps++; pthread_barrier_wait(&barrier_main_two); } // terminate all threads, wait for every one to finish for (int i=0; i<thread_number; i++) { pthread_cancel(threads[i]); } sleep(1); // end of simulation, free all allocated memory space free(position); free(force); free(displacement); free(verlet); free(verlet_distance); free(verlet_max); free(threads); free(borders); free(numbers); // compute runtime, give information to user and leave program time(¤t_time); time_string = ctime(¤t_time); fprintf(file, "\n\nFinished simulation ID: %d at %s" "Parameters N: %d, m: %.2lf, Gamma: %.0lf, Shear: %.0lf, Steps: %d\n" "Elapsed time: %d seconds\n\n", sim_number, time_string, N, m, Gamma_A, v_s, max_timesteps, (int)(current_time - init_time)); fflush(file); fclose(file); }
int main(int argc, char *argv[]) { char *msg; int running; int argi, seq; char newmsg[4096]; /* Handle program options. */ for (argi = 1; (argi < argc); argi++) { if (strcmp(argv[argi], "--debug") == 0) { debug = 1; } else if (strncmp(argv[argi], "--peer=", 7) == 0) { char *ip = strchr(argv[argi], '=') + 1; if (!peers) { peercount = 1; peers = (char **)calloc((peercount + 1), sizeof(char *)); peers[peercount-1] = strdup(ip); peers[peercount] = NULL; } else { peercount++; peers = (char **)realloc(peers, (peercount + 1)*sizeof(char *)); peers[peercount-1] = strdup(ip); peers[peercount] = NULL; } } else if (strncmp(argv[argi], "--channel=", 10) == 0) { channelname = strdup(strchr(argv[argi], '=') + 1); } } if (!peers) { errprintf("No peers specified, aborting\n"); return 1; } save_errbuf = 0; signal(SIGCHLD, SIG_IGN); running = 1; while (running) { char *eoln, *p; char *metadata[MAX_META+1]; int metacount; *newmsg = '\0'; msg = get_xymond_message(C_LAST, argv[0], &seq, NULL); /* Split the message in the first line (with meta-data), and the rest. We're only interested in the first line. */ eoln = strchr(msg, '\n'); if (eoln) *eoln = '\0'; metacount = 0; memset(&metadata, 0, sizeof(metadata)); p = gettok(msg, "|"); while (p && (metacount < MAX_META)) { metadata[metacount++] = p; p = gettok(NULL, "|"); } metadata[metacount] = NULL; if ((msg == NULL) || (strncmp(metadata[0], "@@shutdown", 10) == 0)) { printf("Shutting down\n"); running = 0; 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); } continue; } else if ((metacount > 3) && (strncmp(metadata[0], "@@drophost", 10) == 0)) { snprintf(newmsg, sizeof(newmsg)-1, "drop %s", metadata[3]); } else if ((metacount > 4) && (strncmp(metadata[0], "@@droptest", 10) == 0)) { snprintf(newmsg, sizeof(newmsg)-1, "drop %s %s", metadata[3], metadata[4]); } else if ((metacount > 4) && (strncmp(metadata[0], "@@renamehost", 12) == 0)) { snprintf(newmsg, sizeof(newmsg)-1, "rename %s %s", metadata[3], metadata[4]); } else if ((metacount > 5) && (strncmp(metadata[0], "@@renametest", 12) == 0)) { snprintf(newmsg, sizeof(newmsg)-1, "rename %s %s %s", metadata[3], metadata[4], metadata[5]); } else if ((metacount > 5) && (strncmp(metadata[0], "@@enadis", 8) == 0)) { /* @@enadis|timestamp|sender|hostname|testname|expiretime|message */ if (strcmp(metadata[5], "0") == 0) { snprintf(newmsg, sizeof(newmsg)-1, "enable %s.%s", metadata[3], metadata[4]); } else { long int distime; /* Disable until OK has time -1; normal disables has a count of minutes */ distime = (strcmp(metadata[5], "-1") == 0) ? -1 : ((atol(metadata[5]) - time(NULL)) / 60); snprintf(newmsg, sizeof(newmsg)-1, "disable %s.%s %ld", metadata[3], metadata[4], distime); if (metadata[6] && strlen(metadata[6])) { nldecode(metadata[6]); sprintf(newmsg + strlen(newmsg), " %s", metadata[6]); } dbgprintf("Disable: %s\n", newmsg); } } if (strlen(newmsg) > 0) { int i; for (i = 0; (i < peercount); i++) sendmessage(newmsg, peers[i], XYMON_TIMEOUT, NULL); } } return 0; }
int main(int argc, char *argv[]) { char *msg; int running; int argi, seq; int recentperiod = 3600; int maxrecentcount = 5; int logdirfull = 0; int minlogspace = 5; struct sigaction sa; /* Handle program options. */ for (argi = 1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--logdir=")) { clientlogdir = strchr(argv[argi], '=')+1; } else if (argnmatch(argv[argi], "--recent-period=")) { char *p = strchr(argv[argi], '='); recentperiod = 60*atoi(p+1); } else if (argnmatch(argv[argi], "--recent-count=")) { char *p = strchr(argv[argi], '='); maxrecentcount = atoi(p+1); } else if (argnmatch(argv[argi], "--minimum-free=")) { minlogspace = atoi(strchr(argv[argi], '=')+1); } else if (strcmp(argv[argi], "--debug") == 0) { /* * A global "debug" variable is available. If * it is set, then "dbgprintf()" outputs debug messages. */ debug = 1; } else if (net_worker_option(argv[argi])) { /* Handled in the subroutine */ } } if (clientlogdir == NULL) clientlogdir = xgetenv("CLIENTLOGS"); if (clientlogdir == NULL) { clientlogdir = (char *)malloc(strlen(xgetenv("XYMONVAR")) + 10); sprintf(clientlogdir, "%s/hostdata", xgetenv("XYMONVAR")); } save_errbuf = 0; /* Do the network stuff if needed */ net_worker_run(ST_HOSTDATA, LOC_STICKY, update_locator_hostdata); setup_signalhandler("xymond_hostdata"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sig_handler; signal(SIGCHLD, SIG_IGN); sigaction(SIGHUP, &sa, NULL); signal(SIGPIPE, SIG_DFL); savetimes = xtreeNew(strcasecmp); running = 1; while (running) { char *eoln, *restofmsg, *p; char *metadata[MAX_META+1]; int metacount; msg = get_xymond_message(C_CLICHG, "xymond_hostdata", &seq, NULL); if (msg == NULL) { /* * get_xymond_message will return NULL if xymond_channel closes * the input pipe. We should shutdown when that happens. */ running = 0; continue; } if (nextfscheck < gettimer()) { logdirfull = (chkfreespace(clientlogdir, minlogspace, minlogspace) != 0); if (logdirfull) errprintf("Hostdata directory %s has less than %d%% free space - disabling save of data for 5 minutes\n", clientlogdir, minlogspace); nextfscheck = gettimer() + 300; } /* 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 = ""; } metacount = 0; memset(&metadata, 0, sizeof(metadata)); p = gettok(msg, "|"); while (p && (metacount < MAX_META)) { metadata[metacount++] = p; p = gettok(NULL, "|"); } metadata[metacount] = NULL; if (strncmp(metadata[0], "@@clichg", 8) == 0) { xtreePos_t handle; savetimes_t *itm; int i, recentcount; time_t now = gettimer(); char hostdir[PATH_MAX]; char fn[PATH_MAX]; FILE *fd; /* metadata[3] is the hostname */ handle = xtreeFind(savetimes, metadata[3]); if (handle != xtreeEnd(savetimes)) { itm = (savetimes_t *)xtreeData(savetimes, handle); } else { itm = (savetimes_t *)calloc(1, sizeof(savetimes_t)); itm->hostname = strdup(metadata[3]); xtreeAdd(savetimes, itm->hostname, itm); } /* See how many times we've saved the hostdata recently (within the past 'recentperiod' seconds) */ for (i=0, recentcount=0; ((i < 12) && (itm->tstamp[i] > (now - recentperiod))); i++) recentcount++; /* If it's been saved less than 'maxrecentcount' times, then save it. Otherwise just drop it */ if (!logdirfull && (recentcount < maxrecentcount)) { int written, closestatus, ok = 1; for (i = 10; (i > 0); i--) itm->tstamp[i+1] = itm->tstamp[i]; itm->tstamp[0] = now; sprintf(hostdir, "%s/%s", clientlogdir, metadata[3]); mkdir(hostdir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); sprintf(fn, "%s/%s", hostdir, metadata[4]); fd = fopen(fn, "w"); if (fd == NULL) { errprintf("Cannot create file %s: %s\n", fn, strerror(errno)); continue; } written = fwrite(restofmsg, 1, strlen(restofmsg), fd); if (written != strlen(restofmsg)) { errprintf("Cannot write hostdata file %s: %s\n", fn, strerror(errno)); closestatus = fclose(fd); /* Ignore any close errors */ ok = 0; } else { closestatus = fclose(fd); if (closestatus != 0) { errprintf("Cannot write hostdata file %s: %s\n", fn, strerror(errno)); ok = 0; } } if (!ok) remove(fn); } } /* * A "shutdown" message is sent when the master daemon * terminates. The child workers should shutdown also. */ else if (strncmp(metadata[0], "@@shutdown", 10) == 0) { running = 0; continue; } else if (strncmp(metadata[0], "@@idle", 6) == 0) { /* Ignored */ continue; } /* * A "logrotate" message is sent when the Xymon logs are * rotated. The child workers must re-open their logfiles, * typically stdin and stderr - the filename is always * provided in the XYMONCHANNEL_LOGFILENAME environment. */ 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); } continue; } else if ((metacount > 3) && (strncmp(metadata[0], "@@drophost", 10) == 0)) { /* @@drophost|timestamp|sender|hostname */ char hostdir[PATH_MAX]; snprintf(hostdir, sizeof(hostdir), "%s/%s", clientlogdir, basename(metadata[3])); dropdirectory(hostdir, 1); } else if ((metacount > 4) && (strncmp(metadata[0], "@@renamehost", 12) == 0)) { /* @@renamehost|timestamp|sender|hostname|newhostname */ char oldhostdir[PATH_MAX], newhostdir[PATH_MAX]; snprintf(oldhostdir, sizeof(oldhostdir), "%s/%s", clientlogdir, basename(metadata[3])); snprintf(newhostdir, sizeof(newhostdir), "%s/%s", clientlogdir, basename(metadata[4])); rename(oldhostdir, newhostdir); if (net_worker_locatorbased()) locator_rename_host(metadata[3], metadata[4], ST_HOSTDATA); } else if (strncmp(metadata[0], "@@reload", 8) == 0) { /* Do nothing */ } } return 0; }
int main(int argc, char *argv[]) { tasklist_t *twalk, *dwalk; grouplist_t *gwalk; int argi; int daemonize = 1; int verbose = 0; char *config = "/etc/tasks.cfg"; char *logfn = NULL; char *pidfn = NULL; pid_t cpid; int status; struct sigaction sa; char *envarea = NULL; for (argi=1; (argi < argc); argi++) { if (strcmp(argv[argi], "--debug") == 0) { debug = 1; } else if (strcmp(argv[argi], "--no-daemon") == 0) { daemonize = 0; } else if (strcmp(argv[argi], "--verbose") == 0) { verbose = 1; } else if (argnmatch(argv[argi], "--config=")) { char *p = strchr(argv[argi], '='); config = strdup(expand_env(p+1)); } else if (argnmatch(argv[argi], "--log=")) { char *p = strchr(argv[argi], '='); logfn = strdup(expand_env(p+1)); } else if (argnmatch(argv[argi], "--area=")) { char *p = strchr(argv[argi], '='); envarea = strdup(p+1); } else if (argnmatch(argv[argi], "--env=")) { char *p = strchr(argv[argi], '='); loadenv(p+1, envarea); } else if (argnmatch(argv[argi], "--pidfile=")) { char *p = strchr(argv[argi], '='); pidfn = strdup(expand_env(p+1)); } else if (strcmp(argv[argi], "--dump") == 0) { /* Dump configuration */ forcereload=1; load_config(config); forcereload=0; for (gwalk = grouphead; (gwalk); gwalk = gwalk->next) { if (gwalk->maxuse > 1) printf("GROUP %s %d\n", gwalk->groupname, gwalk->maxuse); } printf("\n"); for (twalk = taskhead; (twalk); twalk = twalk->next) { printf("[%s]\n", twalk->key); printf("\tCMD %s\n", twalk->cmd); if (twalk->disabled) printf("\tDISABLED\n"); if (twalk->group) printf("\tGROUP %s\n", twalk->group->groupname); if (twalk->depends) printf("\tNEEDS %s\n", twalk->depends->key); if (twalk->interval > 0) printf("\tINTERVAL %d\n", twalk->interval); if (twalk->cronstr) printf("\tCRONDATE %s\n", twalk->cronstr); if (twalk->maxruntime) printf("\tMAXTIME %d\n", twalk->maxruntime); if (twalk->logfile) printf("\tLOGFILE %s\n", twalk->logfile); if (twalk->envfile) printf("\tENVFILE %s\n", twalk->envfile); if (twalk->envarea) printf("\tENVAREA %s\n", twalk->envarea); if (twalk->onhostptn) printf("\tONHOST %s\n", twalk->onhostptn); printf("\n"); } fflush(stdout); return 0; } else { fprintf(stderr,"%s: Unsupported argument: %s\n",argv[0],argv[argi]); fflush(stderr); return 1; } } /* Go daemon */ if (daemonize) { pid_t childpid; /* Become a daemon */ childpid = fork(); if (childpid < 0) { /* Fork failed */ errprintf("Could not fork child\n"); exit(1); } else if (childpid > 0) { /* Parent exits */ if (pidfn) { FILE *pidfd = fopen(pidfn, "w"); if (pidfd) { fprintf(pidfd, "%d\n", (int)childpid); fclose(pidfd); } } exit(0); } /* Child (daemon) continues here */ setsid(); } /* If using a logfile, switch stdout and stderr to go there */ if (logfn) { /* Should we close stdin here ? No ... */ reopen_file("/dev/null", "r", stdin); reopen_file(logfn, "a", stdout); reopen_file(logfn, "a", stderr); } save_errbuf = 0; setup_signalhandler("xymonlaunch"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sig_handler; sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGCHLD, &sa, NULL); errprintf("xymonlaunch starting\n"); while (running) { time_t now = gettimer(); if (now >= nextcfgload) { load_config(config); nextcfgload = (now + 30); } if (logfn && dologswitch) { reopen_file(logfn, "a", stdout); reopen_file(logfn, "a", stderr); dologswitch = 0; } /* Pick up children that have terminated */ while ((cpid = wait3(&status, WNOHANG, NULL)) > 0) { for (twalk = taskhead; (twalk && (twalk->pid != cpid)); twalk = twalk->next); if (twalk) { twalk->pid = 0; twalk->beingkilled = 0; if (WIFEXITED(status)) { twalk->exitcode = WEXITSTATUS(status); if (twalk->exitcode) { errprintf("Task %s terminated, status %d\n", twalk->key, twalk->exitcode); twalk->failcount++; } else { twalk->failcount = 0; } } else if (WIFSIGNALED(status)) { twalk->exitcode = -WTERMSIG(status); twalk->failcount++; errprintf("Task %s terminated by signal %d\n", twalk->key, abs(twalk->exitcode)); } if (twalk->group) twalk->group->currentuse--; /* Tasks that depend on this task should be killed ... */ for (dwalk = taskhead; (dwalk); dwalk = dwalk->next) { if ((dwalk->depends == twalk) && (dwalk->pid > 0)) { dwalk->beingkilled = 1; kill(dwalk->pid, SIGTERM); } } } } /* See what new tasks need to get going */ dbgprintf("\n"); dbgprintf("Starting tasklist scan\n"); crongettime(); for (twalk = taskhead; (twalk); twalk = twalk->next) { if ( (twalk->pid == 0) && !twalk->disabled && ( ((twalk->interval >= 0) && (now >= (twalk->laststart + twalk->interval))) || /* xymon interval condition */ (twalk->crondate && ((twalk->laststart + 55) < now) && cronmatch(twalk->crondate)) /* cron date */ ) ) { if (twalk->depends && ((twalk->depends->pid == 0) || (twalk->depends->laststart > (now - 5)))) { dbgprintf("Postponing start of %s due to %s not yet running\n", twalk->key, twalk->depends->key); continue; } if (twalk->group && (twalk->group->currentuse >= twalk->group->maxuse)) { dbgprintf("Postponing start of %s due to group %s being busy\n", twalk->key, twalk->group->groupname); continue; } if ((twalk->failcount > MAX_FAILS) && ((twalk->laststart + 600) < now)) { dbgprintf("Releasing %s from failure hold\n", twalk->key); twalk->failcount = 0; } if (twalk->failcount > MAX_FAILS) { dbgprintf("Postponing start of %s due to multiple failures\n", twalk->key); continue; } if (twalk->laststart > (now - 5)) { dbgprintf("Postponing start of %s, will not try more than once in 5 seconds\n", twalk->key); continue; } dbgprintf("About to start task %s\n", twalk->key); twalk->laststart = now; twalk->pid = fork(); if (twalk->pid == 0) { /* Exec the task */ char *cmd; char **cmdargs = NULL; static char tasksleepenv[20],bbsleepenv[20]; /* Setup environment */ if (twalk->envfile) { dbgprintf("%s -> Loading environment from %s area %s\n", twalk->key, expand_env(twalk->envfile), (twalk->envarea ? twalk->envarea : "")); loadenv(expand_env(twalk->envfile), twalk->envarea); } /* Setup TASKSLEEP to match the interval */ sprintf(tasksleepenv, "TASKSLEEP=%d", twalk->interval); sprintf(bbsleepenv, "BBSLEEP=%d", twalk->interval); /* For compatibility */ putenv(tasksleepenv); putenv(bbsleepenv); /* Setup command line and arguments */ cmdargs = setup_commandargs(twalk->cmd, &cmd); /* Point stdout/stderr to a logfile, if requested */ if (twalk->logfile) { char *logfn = expand_env(twalk->logfile); dbgprintf("%s -> Assigning stdout/stderr to log '%s'\n", twalk->key, logfn); reopen_file(logfn, "a", stdout); reopen_file(logfn, "a", stderr); } /* Go! */ dbgprintf("%s -> Running '%s', XYMONHOME=%s\n", twalk->key, cmd, xgetenv("XYMONHOME")); execvp(cmd, cmdargs); /* Should never go here */ errprintf("Could not start task %s using command '%s': %s\n", twalk->key, cmd, strerror(errno)); exit(0); } else if (twalk->pid == -1) { /* Fork failed */ errprintf("Fork failed!\n"); twalk->pid = 0; } else { if (twalk->group) twalk->group->currentuse++; if (verbose) errprintf("Task %s started with PID %d\n", twalk->key, (int)twalk->pid); } } else if (twalk->pid > 0) { dbgprintf("Task %s active with PID %d\n", twalk->key, (int)twalk->pid); if (twalk->maxruntime && ((now - twalk->laststart) > twalk->maxruntime)) { errprintf("Killing hung task %s (PID %d) after %d seconds\n", twalk->key, (int)twalk->pid, (now - twalk->laststart)); kill(twalk->pid, (twalk->beingkilled ? SIGKILL : SIGTERM)); twalk->beingkilled = 1; /* Next time it's a real kill */ } } } sleep(5); } /* Shutdown running tasks */ for (twalk = taskhead; (twalk); twalk = twalk->next) { if (twalk->pid) kill(twalk->pid, SIGTERM); } if (pidfn) unlink(pidfn); return 0; }
int main(int argc, char *argv[]) { time_t starttime = gettimer(); char *histdir = NULL; char *histlogdir = NULL; char *msg; int argi, seq; int save_allevents = 1; int save_hostevents = 1; int save_statusevents = 1; int save_histlogs = 1, defaultsaveop = 1; FILE *alleventsfd = NULL; int running = 1; struct sigaction sa; char newcol2[3]; char oldcol2[3]; char alleventsfn[PATH_MAX]; char pidfn[PATH_MAX]; int logdirfull = 0; int minlogspace = 5; MEMDEFINE(pidfn); MEMDEFINE(alleventsfn); MEMDEFINE(newcol2); MEMDEFINE(oldcol2); /* Dont save the error buffer */ save_errbuf = 0; sprintf(pidfn, "%s/xymond_history.pid", xgetenv("XYMONSERVERLOGS")); if (xgetenv("XYMONALLHISTLOG")) save_allevents = (strcmp(xgetenv("XYMONALLHISTLOG"), "TRUE") == 0); if (xgetenv("XYMONHOSTHISTLOG")) save_hostevents = (strcmp(xgetenv("XYMONHOSTHISTLOG"), "TRUE") == 0); if (xgetenv("SAVESTATUSLOG")) save_histlogs = (strncmp(xgetenv("SAVESTATUSLOG"), "FALSE", 5) != 0); for (argi = 1; (argi < argc); argi++) { if (argnmatch(argv[argi], "--histdir=")) { histdir = strchr(argv[argi], '=')+1; } else if (argnmatch(argv[argi], "--histlogdir=")) { histlogdir = strchr(argv[argi], '=')+1; } else if (argnmatch(argv[argi], "--pidfile=")) { strcpy(pidfn, strchr(argv[argi], '=')+1); } else if (argnmatch(argv[argi], "--minimum-free=")) { minlogspace = atoi(strchr(argv[argi], '=')+1); } else if (argnmatch(argv[argi], "--debug")) { debug = 1; } } if (xgetenv("XYMONHISTDIR") && (histdir == NULL)) { histdir = strdup(xgetenv("XYMONHISTDIR")); } if (histdir == NULL) { errprintf("No history directory given, aborting\n"); return 1; } if (save_histlogs && (histlogdir == NULL) && xgetenv("XYMONHISTLOGS")) { histlogdir = strdup(xgetenv("XYMONHISTLOGS")); } if (save_histlogs && (histlogdir == NULL)) { errprintf("No history-log directory given, aborting\n"); return 1; } columndefs = xtreeNew(strcmp); { char *defaultsave, *tok; char *savelist; columndef_t *newrec; savelist = strdup(xgetenv("SAVESTATUSLOG")); defaultsave = strtok(savelist, ","); /* * TRUE: Save everything by default; may list some that are not saved. * ONLY: Save nothing by default; may list some that are saved. * FALSE: Save nothing. */ defaultsaveop = (strcasecmp(defaultsave, "TRUE") == 0); tok = strtok(NULL, ","); while (tok) { newrec = (columndef_t *)malloc(sizeof(columndef_t)); if (*tok == '!') { newrec->saveit = 0; newrec->name = strdup(tok+1); } else { newrec->saveit = 1; newrec->name = strdup(tok); } xtreeAdd(columndefs, newrec->name, newrec); tok = strtok(NULL, ","); } xfree(savelist); } { FILE *pidfd = fopen(pidfn, "w"); if (pidfd) { fprintf(pidfd, "%lu\n", (unsigned long)getpid()); fclose(pidfd); } } sprintf(alleventsfn, "%s/allevents", histdir); if (save_allevents) { alleventsfd = fopen(alleventsfn, "a"); if (alleventsfd == NULL) { errprintf("Cannot open the all-events file '%s'\n", alleventsfn); } setvbuf(alleventsfd, (char *)NULL, _IOLBF, 0); } /* For picking up lost children */ setup_signalhandler("xymond_history"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sig_handler; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGHUP, &sa, NULL); signal(SIGPIPE, SIG_DFL); while (running) { char *metadata[20] = { NULL, }; int metacount; char *p; char *statusdata = ""; char *hostname, *hostnamecommas, *testname, *dismsg, *modifiers; time_t tstamp, lastchg, disabletime, clienttstamp; int tstamp_i, lastchg_i; int newcolor, oldcolor; int downtimeactive; struct tm tstamptm; int trend; int childstat; /* Pickup any finished child processes to avoid zombies */ while (wait3(&childstat, WNOHANG, NULL) > 0) ; if (rotatefiles && alleventsfd) { fclose(alleventsfd); alleventsfd = fopen(alleventsfn, "a"); if (alleventsfd == NULL) { errprintf("Cannot re-open the all-events file '%s'\n", alleventsfn); } else { setvbuf(alleventsfd, (char *)NULL, _IOLBF, 0); } } msg = get_xymond_message(C_STACHG, "xymond_history", &seq, NULL); if (msg == NULL) { running = 0; continue; } if (nextfscheck < gettimer()) { logdirfull = (chkfreespace(histlogdir, minlogspace, minlogspace) != 0); if (logdirfull) errprintf("Historylog directory %s has less than %d%% free space - disabling save of data for 5 minutes\n", histlogdir, minlogspace); nextfscheck = gettimer() + 300; } p = strchr(msg, '\n'); if (p) { *p = '\0'; statusdata = msg_data(p+1, 0); } metacount = 0; memset(&metadata, 0, sizeof(metadata)); p = gettok(msg, "|"); while (p && (metacount < 20)) { metadata[metacount++] = p; p = gettok(NULL, "|"); } if ((metacount > 9) && (strncmp(metadata[0], "@@stachg", 8) == 0)) { xtreePos_t handle; columndef_t *saveit = NULL; /* @@stachg#seq|timestamp|sender|origin|hostname|testname|expiretime|color|prevcolor|changetime|disabletime|disablemsg|downtimeactive|clienttstamp|modifiers */ sscanf(metadata[1], "%d.%*d", &tstamp_i); tstamp = tstamp_i; hostname = metadata[4]; testname = metadata[5]; newcolor = parse_color(metadata[7]); oldcolor = parse_color(metadata[8]); lastchg = atoi(metadata[9]); disabletime = atoi(metadata[10]); dismsg = metadata[11]; downtimeactive = (atoi(metadata[12]) > 0); clienttstamp = atoi(metadata[13]); modifiers = metadata[14]; if (newcolor == -1) { errprintf("Bad message: newcolor is unknown '%s'\n", metadata[7]); continue; } p = hostnamecommas = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = ','; handle = xtreeFind(columndefs, testname); if (handle == xtreeEnd(columndefs)) { saveit = (columndef_t *)malloc(sizeof(columndef_t)); saveit->name = strdup(testname); saveit->saveit = defaultsaveop; xtreeAdd(columndefs, saveit->name, saveit); } else { saveit = (columndef_t *) xtreeData(columndefs, handle); } if (save_statusevents) { char statuslogfn[PATH_MAX]; int logexists; FILE *statuslogfd; char oldcol[100]; char timestamp[40]; struct stat st; MEMDEFINE(statuslogfn); MEMDEFINE(oldcol); MEMDEFINE(timestamp); sprintf(statuslogfn, "%s/%s.%s", histdir, hostnamecommas, testname); stat(statuslogfn, &st); statuslogfd = fopen(statuslogfn, "r+"); logexists = (statuslogfd != NULL); *oldcol = '\0'; if (logexists) { /* * There is a fair chance xymond has not been * running all the time while this system was monitored. * So get the time of the latest status change from the file, * instead of relying on the "lastchange" value we get * from xymond. This is also needed when migrating from * standard bbd to xymond. */ off_t pos = -1; char l[1024]; int gotit; MEMDEFINE(l); fseeko(statuslogfd, 0, SEEK_END); if (ftello(statuslogfd) > 512) { /* Go back 512 from EOF, and skip to start of a line */ fseeko(statuslogfd, -512, SEEK_END); gotit = (fgets(l, sizeof(l)-1, statuslogfd) == NULL); } else { /* Read from beginning of file */ fseeko(statuslogfd, 0, SEEK_SET); gotit = 0; } while (!gotit) { off_t tmppos = ftello(statuslogfd); int dur_i; if (fgets(l, sizeof(l)-1, statuslogfd)) { /* Sun Oct 10 06:49:42 2004 red 1097383782 602 */ if ((strlen(l) > 24) && (sscanf(l+24, " %s %d %d", oldcol, &lastchg_i, &dur_i) == 2) && (parse_color(oldcol) != -1)) { /* * Record the start location of the line */ pos = tmppos; lastchg = lastchg_i; } } else { gotit = 1; } } if (pos == -1) { /* * Couldnt find anything in the log. * Take lastchg from the timestamp of the logfile, * and just append the data. */ lastchg = st.st_mtime; fseeko(statuslogfd, 0, SEEK_END); } else { /* * lastchg was updated above. * Seek to where the last line starts. */ fseeko(statuslogfd, pos, SEEK_SET); } MEMUNDEFINE(l); } else { /* * Logfile does not exist. */ lastchg = tstamp; statuslogfd = fopen(statuslogfn, "a"); if (statuslogfd == NULL) { errprintf("Cannot open status historyfile '%s' : %s\n", statuslogfn, strerror(errno)); } } if (strcmp(oldcol, colorname(newcolor)) == 0) { /* We wont update history unless the color did change. */ if ((gettimer() - starttime) > 300) { errprintf("Will not update %s - color unchanged (%s)\n", statuslogfn, oldcol); } if (hostnamecommas) xfree(hostnamecommas); if (statuslogfd) fclose(statuslogfd); MEMUNDEFINE(statuslogfn); MEMUNDEFINE(oldcol); MEMUNDEFINE(timestamp); continue; } if (statuslogfd) { if (logexists) { struct tm oldtm; /* Re-print the old record, now with the final duration */ memcpy(&oldtm, localtime(&lastchg), sizeof(oldtm)); strftime(timestamp, sizeof(timestamp), "%a %b %e %H:%M:%S %Y", &oldtm); fprintf(statuslogfd, "%s %s %d %d\n", timestamp, oldcol, (int)lastchg, (int)(tstamp - lastchg)); } /* And the new record. */ memcpy(&tstamptm, localtime(&tstamp), sizeof(tstamptm)); strftime(timestamp, sizeof(timestamp), "%a %b %e %H:%M:%S %Y", &tstamptm); fprintf(statuslogfd, "%s %s %d", timestamp, colorname(newcolor), (int)tstamp); fclose(statuslogfd); } MEMUNDEFINE(statuslogfn); MEMUNDEFINE(oldcol); MEMUNDEFINE(timestamp); } if (save_histlogs && saveit->saveit && !logdirfull) { char *hostdash; char fname[PATH_MAX]; FILE *histlogfd; MEMDEFINE(fname); p = hostdash = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = '_'; sprintf(fname, "%s/%s", histlogdir, hostdash); mkdir(fname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); p = fname + sprintf(fname, "%s/%s/%s", histlogdir, hostdash, testname); mkdir(fname, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); p += sprintf(p, "/%s", histlogtime(tstamp)); histlogfd = fopen(fname, "w"); if (histlogfd) { /* * When a host gets disabled or goes purple, the status * message data is not changed - so it will include a * wrong color as the first word of the message. * Therefore we need to fixup this so it matches the * newcolor value. */ int txtcolor = parse_color(statusdata); char *origstatus = statusdata; char *eoln, *restofdata; int written, closestatus, ok = 1; if (txtcolor != -1) { fprintf(histlogfd, "%s", colorname(newcolor)); statusdata += strlen(colorname(txtcolor)); } if (dismsg && *dismsg) nldecode(dismsg); if (disabletime > 0) { fprintf(histlogfd, " Disabled until %s\n%s\n\n", ctime(&disabletime), (dismsg ? dismsg : "")); fprintf(histlogfd, "Status message when disabled follows:\n\n"); statusdata = origstatus; } else if (dismsg && *dismsg) { fprintf(histlogfd, " Planned downtime: %s\n\n", dismsg); fprintf(histlogfd, "Original status message follows:\n\n"); statusdata = origstatus; } restofdata = statusdata; if (modifiers && *modifiers) { char *modtxt; /* We must finish writing the first line before putting in the modifiers */ eoln = strchr(restofdata, '\n'); if (eoln) { restofdata = eoln+1; *eoln = '\0'; fprintf(histlogfd, "%s\n", statusdata); } nldecode(modifiers); modtxt = strtok(modifiers, "\n"); while (modtxt) { fprintf(histlogfd, "%s\n", modtxt); modtxt = strtok(NULL, "\n"); } } written = fwrite(restofdata, 1, strlen(restofdata), histlogfd); if (written != strlen(restofdata)) { ok = 0; errprintf("Error writing to file %s: %s\n", fname, strerror(errno)); closestatus = fclose(histlogfd); /* Ignore any errors on close */ } else { fprintf(histlogfd, "Status unchanged in 0.00 minutes\n"); fprintf(histlogfd, "Message received from %s\n", metadata[2]); if (clienttstamp) fprintf(histlogfd, "Client data ID %d\n", (int) clienttstamp); closestatus = fclose(histlogfd); if (closestatus != 0) { ok = 0; errprintf("Error writing to file %s: %s\n", fname, strerror(errno)); } } if (!ok) remove(fname); } else { errprintf("Cannot create histlog file '%s' : %s\n", fname, strerror(errno)); } xfree(hostdash); MEMUNDEFINE(fname); } strncpy(oldcol2, ((oldcolor >= 0) ? colorname(oldcolor) : "-"), 2); strncpy(newcol2, colorname(newcolor), 2); newcol2[2] = oldcol2[2] = '\0'; if (oldcolor == -1) trend = -1; /* we dont know how bad it was */ else if (newcolor > oldcolor) trend = 2; /* It's getting worse */ else if (newcolor < oldcolor) trend = 1; /* It's getting better */ else trend = 0; /* Shouldn't happen ... */ if (save_hostevents) { char hostlogfn[PATH_MAX]; FILE *hostlogfd; MEMDEFINE(hostlogfn); sprintf(hostlogfn, "%s/%s", histdir, hostname); hostlogfd = fopen(hostlogfn, "a"); if (hostlogfd) { fprintf(hostlogfd, "%s %d %d %d %s %s %d\n", testname, (int)tstamp, (int)lastchg, (int)(tstamp - lastchg), newcol2, oldcol2, trend); fclose(hostlogfd); } else { errprintf("Cannot open host logfile '%s' : %s\n", hostlogfn, strerror(errno)); } MEMUNDEFINE(hostlogfn); } if (save_allevents) { fprintf(alleventsfd, "%s %s %d %d %d %s %s %d\n", hostname, testname, (int)tstamp, (int)lastchg, (int)(tstamp - lastchg), newcol2, oldcol2, trend); fflush(alleventsfd); } xfree(hostnamecommas); } else if ((metacount > 3) && ((strncmp(metadata[0], "@@drophost", 10) == 0))) { /* @@drophost|timestamp|sender|hostname */ hostname = metadata[3]; if (save_histlogs) { char *hostdash; char testdir[PATH_MAX]; MEMDEFINE(testdir); /* Remove all directories below the host-specific histlog dir */ p = hostdash = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = '_'; sprintf(testdir, "%s/%s", histlogdir, hostdash); dropdirectory(testdir, 1); xfree(hostdash); MEMUNDEFINE(testdir); } if (save_hostevents) { char hostlogfn[PATH_MAX]; struct stat st; MEMDEFINE(hostlogfn); sprintf(hostlogfn, "%s/%s", histdir, hostname); if ((stat(hostlogfn, &st) == 0) && S_ISREG(st.st_mode)) { unlink(hostlogfn); } MEMUNDEFINE(hostlogfn); } if (save_statusevents) { DIR *dirfd; struct dirent *de; char *hostlead; char statuslogfn[PATH_MAX]; struct stat st; MEMDEFINE(statuslogfn); /* Remove $XYMONVAR/hist/host,name.* */ p = hostnamecommas = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = ','; hostlead = malloc(strlen(hostname) + 2); strcpy(hostlead, hostnamecommas); strcat(hostlead, "."); dirfd = opendir(histdir); if (dirfd) { while ((de = readdir(dirfd)) != NULL) { if (strncmp(de->d_name, hostlead, strlen(hostlead)) == 0) { sprintf(statuslogfn, "%s/%s", histdir, de->d_name); if ((stat(statuslogfn, &st) == 0) && S_ISREG(st.st_mode)) { unlink(statuslogfn); } } } closedir(dirfd); } xfree(hostlead); xfree(hostnamecommas); MEMUNDEFINE(statuslogfn); } } else if ((metacount > 4) && ((strncmp(metadata[0], "@@droptest", 10) == 0))) { /* @@droptest|timestamp|sender|hostname|testname */ hostname = metadata[3]; testname = metadata[4]; if (save_histlogs) { char *hostdash; char testdir[PATH_MAX]; MEMDEFINE(testdir); p = hostdash = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = '_'; sprintf(testdir, "%s/%s/%s", histlogdir, hostdash, testname); dropdirectory(testdir, 1); xfree(hostdash); MEMUNDEFINE(testdir); } if (save_statusevents) { char *hostnamecommas; char statuslogfn[PATH_MAX]; struct stat st; MEMDEFINE(statuslogfn); p = hostnamecommas = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = ','; sprintf(statuslogfn, "%s/%s.%s", histdir, hostnamecommas, testname); if ((stat(statuslogfn, &st) == 0) && S_ISREG(st.st_mode)) unlink(statuslogfn); xfree(hostnamecommas); MEMUNDEFINE(statuslogfn); } } else if ((metacount > 4) && ((strncmp(metadata[0], "@@renamehost", 12) == 0))) { /* @@renamehost|timestamp|sender|hostname|newhostname */ char *newhostname; hostname = metadata[3]; newhostname = metadata[4]; if (save_histlogs) { char *hostdash; char *newhostdash; char olddir[PATH_MAX]; char newdir[PATH_MAX]; MEMDEFINE(olddir); MEMDEFINE(newdir); p = hostdash = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = '_'; p = newhostdash = strdup(newhostname); while ((p = strchr(p, '.')) != NULL) *p = '_'; sprintf(olddir, "%s/%s", histlogdir, hostdash); sprintf(newdir, "%s/%s", histlogdir, newhostdash); rename(olddir, newdir); xfree(newhostdash); xfree(hostdash); MEMUNDEFINE(newdir); MEMUNDEFINE(olddir); } if (save_hostevents) { char hostlogfn[PATH_MAX]; char newhostlogfn[PATH_MAX]; MEMDEFINE(hostlogfn); MEMDEFINE(newhostlogfn); sprintf(hostlogfn, "%s/%s", histdir, hostname); sprintf(newhostlogfn, "%s/%s", histdir, newhostname); rename(hostlogfn, newhostlogfn); MEMUNDEFINE(hostlogfn); MEMUNDEFINE(newhostlogfn); } if (save_statusevents) { DIR *dirfd; struct dirent *de; char *hostlead; char *newhostnamecommas; char statuslogfn[PATH_MAX]; char newlogfn[PATH_MAX]; MEMDEFINE(statuslogfn); MEMDEFINE(newlogfn); p = hostnamecommas = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = ','; hostlead = malloc(strlen(hostname) + 2); strcpy(hostlead, hostnamecommas); strcat(hostlead, "."); p = newhostnamecommas = strdup(newhostname); while ((p = strchr(p, '.')) != NULL) *p = ','; dirfd = opendir(histdir); if (dirfd) { while ((de = readdir(dirfd)) != NULL) { if (strncmp(de->d_name, hostlead, strlen(hostlead)) == 0) { char *testname = strchr(de->d_name, '.'); sprintf(statuslogfn, "%s/%s", histdir, de->d_name); sprintf(newlogfn, "%s/%s%s", histdir, newhostnamecommas, testname); rename(statuslogfn, newlogfn); } } closedir(dirfd); } xfree(newhostnamecommas); xfree(hostlead); xfree(hostnamecommas); MEMUNDEFINE(statuslogfn); MEMUNDEFINE(newlogfn); } } else if ((metacount > 5) && (strncmp(metadata[0], "@@renametest", 12) == 0)) { /* @@renametest|timestamp|sender|hostname|oldtestname|newtestname */ char *newtestname; hostname = metadata[3]; testname = metadata[4]; newtestname = metadata[5]; if (save_histlogs) { char *hostdash; char olddir[PATH_MAX]; char newdir[PATH_MAX]; MEMDEFINE(olddir); MEMDEFINE(newdir); p = hostdash = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = '_'; sprintf(olddir, "%s/%s/%s", histlogdir, hostdash, testname); sprintf(newdir, "%s/%s/%s", histlogdir, hostdash, newtestname); rename(olddir, newdir); xfree(hostdash); MEMUNDEFINE(newdir); MEMUNDEFINE(olddir); } if (save_statusevents) { char *hostnamecommas; char statuslogfn[PATH_MAX]; char newstatuslogfn[PATH_MAX]; MEMDEFINE(statuslogfn); MEMDEFINE(newstatuslogfn); p = hostnamecommas = strdup(hostname); while ((p = strchr(p, '.')) != NULL) *p = ','; sprintf(statuslogfn, "%s/%s.%s", histdir, hostnamecommas, testname); sprintf(newstatuslogfn, "%s/%s.%s", histdir, hostnamecommas, newtestname); rename(statuslogfn, newstatuslogfn); xfree(hostnamecommas); MEMUNDEFINE(newstatuslogfn); MEMUNDEFINE(statuslogfn); } } else if (strncmp(metadata[0], "@@idle", 6) == 0) { /* Nothing */ } else if (strncmp(metadata[0], "@@shutdown", 10) == 0) { running = 0; } 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); } continue; } else if (strncmp(metadata[0], "@@reload", 8) == 0) { /* Do nothing */ } } MEMUNDEFINE(newcol2); MEMUNDEFINE(oldcol2); MEMUNDEFINE(alleventsfn); MEMUNDEFINE(pidfn); fclose(alleventsfd); unlink(pidfn); return 0; }
int main(int argc, char *argv[]) { char *msg; int running; int argi, seq; struct timespec *timeout = NULL; pcre *hostexp = NULL; pcre *exhostexp = NULL; pcre *testexp = NULL; pcre *extestexp = NULL; pcre *colorexp = NULL; const char *errmsg = NULL; int errofs = 0; FILE *logfd = stdout; int batchtimeout = 30; char *batchcmd = NULL; strbuffer_t *batchbuf = NULL; time_t lastmsgtime = 0; int hostnameitem = 4, testnameitem = 5, coloritem = 7; /* Handle program options. */ for (argi = 1; (argi < argc); argi++) { if (strcmp(argv[argi], "--debug") == 0) { /* * A global "debug" variable is available. If * it is set, then "dbgprintf()" outputs debug messages. */ debug = 1; } else if (strncmp(argv[argi], "--timeout=", 10) == 0) { /* * You can have a timeout when waiting for new * messages. If it happens, you will get a "@@idle\n" * message with sequence number 0. * If you dont want a timeout, just pass a NULL for the timeout parameter. */ timeout = (struct timespec *)(malloc(sizeof(struct timespec))); timeout->tv_sec = (atoi(argv[argi]+10)); timeout->tv_nsec = 0; } else if (strcmp(argv[argi], "--client") == 0) { hostnameitem = 3; testnameitem = 4; errprintf("Expecting to be fed from 'client' channel\n"); } else if (argnmatch(argv[argi], "--hosts=")) { char *exp = strchr(argv[argi], '=') + 1; hostexp = pcre_compile(exp, PCRE_CASELESS, &errmsg, &errofs, NULL); if (hostexp == NULL) printf("Invalid expression '%s'\n", exp); } else if (argnmatch(argv[argi], "--exhosts=")) { char *exp = strchr(argv[argi], '=') + 1; exhostexp = pcre_compile(exp, PCRE_CASELESS, &errmsg, &errofs, NULL); if (exhostexp == NULL) printf("Invalid expression '%s'\n", exp); } else if (argnmatch(argv[argi], "--tests=")) { char *exp = strchr(argv[argi], '=') + 1; testexp = pcre_compile(exp, PCRE_CASELESS, &errmsg, &errofs, NULL); if (testexp == NULL) printf("Invalid expression '%s'\n", exp); } else if (argnmatch(argv[argi], "--extests=")) { char *exp = strchr(argv[argi], '=') + 1; extestexp = pcre_compile(exp, PCRE_CASELESS, &errmsg, &errofs, NULL); if (extestexp == NULL) printf("Invalid expression '%s'\n", exp); } else if (argnmatch(argv[argi], "--colors=")) { char *exp = strchr(argv[argi], '=') + 1; colorexp = pcre_compile(exp, PCRE_CASELESS, &errmsg, &errofs, NULL); if (colorexp == NULL) printf("Invalid expression '%s'\n", exp); } else if (argnmatch(argv[argi], "--outfile=")) { char *fn = strchr(argv[argi], '=') + 1; logfd = fopen(fn, "a"); if (logfd == NULL) { printf("Cannot open logfile %s: %s\n", fn, strerror(errno)); logfd = stdout; } } else if (argnmatch(argv[argi], "--batch-timeout=")) { char *p = strchr(argv[argi], '='); batchtimeout = atoi(p+1); timeout = (struct timespec *)(malloc(sizeof(struct timespec))); timeout->tv_sec = batchtimeout; timeout->tv_nsec = 0; } else if (argnmatch(argv[argi], "--batch-command=")) { char *p = strchr(argv[argi], '='); batchcmd = strdup(p+1); batchbuf = newstrbuffer(0); } else { printf("Unknown option %s\n", argv[argi]); printf("Usage: %s [--hosts=EXP] [--tests=EXP] [--exhosts=EXP] [--extests=EXP] [--color=EXP] [--outfile=FILENAME] [--batch-timeout=N] [--batch-command=COMMAND]\n", argv[0]); return 0; } } signal(SIGCHLD, SIG_IGN); running = 1; while (running) { char *eoln, *restofmsg, *p; char *metadata[MAX_META+1]; int metacount; msg = get_xymond_message(C_LAST, argv[0], &seq, timeout); if (msg == NULL) { /* * get_xymond_message will return NULL if xymond_channel closes * the input pipe. We should shutdown when that happens. */ running = 0; continue; } /* * Now we have a message. So do something with it. * * The first line of the message is always a '|' separated * list of meta-data about the message. After the first * line, the content varies by channel. */ /* 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 < MAX_META)) { metadata[metacount++] = p; p = gettok(NULL, "|"); } metadata[metacount] = NULL; /* * A "shutdown" message is sent when the master daemon * terminates. The child workers should shutdown also. */ if (strncmp(metadata[0], "@@shutdown", 10) == 0) { printf("Shutting down\n"); running = 0; continue; } /* * A "logrotate" message is sent when the Xymon logs are * rotated. The child workers must re-open their logfiles, * typically stdin and stderr - the filename is always * provided in the XYMONDHANNEL_LOGFILENAME environment. */ 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); } continue; } /* * A "reload" means the hosts.cfg file has changed. */ else if (strncmp(metadata[0], "@@reload", 8) == 0) { /* Nothing ... right now */ } /* * An "idle" message appears when get_xymond_message() * exceeds the timeout setting (ie. you passed a timeout * value). This allows your worker module to perform * some internal processing even though no messages arrive. */ else if (strncmp(metadata[0], "@@idle", 6) == 0) { dbgprintf("Got an 'idle' message\n"); } /* * The "drophost", "droptest", "renamehost" and "renametst" * indicates that a host/test was deleted or renamed. If the * worker module maintains some internal storage (in memory * or persistent file-storage), it should act on these * messages to maintain data consistency. */ else if ((metacount > 3) && (strncmp(metadata[0], "@@drophost", 10) == 0)) { dbgprintf("Got a 'drophost' message for host '%s'\n", metadata[3]); } else if ((metacount > 3) && (strncmp(metadata[0], "@@dropstate", 11) == 0)) { dbgprintf("Got a 'dropstate' message for host '%s'\n", metadata[3]); } else if ((metacount > 4) && (strncmp(metadata[0], "@@droptest", 10) == 0)) { dbgprintf("Got a 'droptest' message for host '%s' test '%s'\n", metadata[3], metadata[4]); } else if ((metacount > 4) && (strncmp(metadata[0], "@@renamehost", 12) == 0)) { dbgprintf("Got a 'renamehost' message for host '%s' -> '%s'\n", metadata[3], metadata[4]); } else if ((metacount > 5) && (strncmp(metadata[0], "@@renametest", 12) == 0)) { dbgprintf("Got a 'renametest' message for host '%s' test '%s' -> '%s'\n", metadata[3], metadata[4], metadata[5]); } /* * Process this message. */ else { int ovector[30]; int match, i; char *hostname = metadata[hostnameitem]; char *testname = metadata[testnameitem]; char *color = metadata[coloritem]; /* See if we should handle the batched messages we've got */ if (batchcmd && ((lastmsgtime + batchtimeout) < gettimer()) && (STRBUFLEN(batchbuf) > 0)) { pid_t childpid = fork(); int childres = 0; if (childpid < 0) { /* Fork failed! */ errprintf("Fork failed: %s\n", strerror(errno)); } else if (childpid == 0) { /* Child */ FILE *cmdpipe = popen(batchcmd, "w"); if (cmdpipe) { /* Write the data to the batch command pipe */ int n, bytesleft = STRBUFLEN(batchbuf); char *outp = STRBUF(batchbuf); while (bytesleft) { n = fwrite(outp, 1, bytesleft, cmdpipe); if (n >= 0) { bytesleft -= n; outp += n; } else { errprintf("Error while writing data to batch command\n"); bytesleft = 0; } } childres = pclose(cmdpipe); } else { errprintf("Could not open pipe to batch command '%s'\n", batchcmd); childres = 127; } exit(childres); } else if (childpid > 0) { /* Parent continues */ } clearstrbuffer(batchbuf); } if (hostexp) { match = (pcre_exec(hostexp, NULL, hostname, strlen(hostname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); if (!match) continue; } if (exhostexp) { match = (pcre_exec(exhostexp, NULL, hostname, strlen(hostname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); if (match) continue; } if (testexp) { match = (pcre_exec(testexp, NULL, testname, strlen(testname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); if (!match) continue; } if (exhostexp) { match = (pcre_exec(extestexp, NULL, testname, strlen(testname), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); if (match) continue; } if (colorexp) { match = (pcre_exec(colorexp, NULL, color, strlen(color), 0, 0, ovector, (sizeof(ovector)/sizeof(int))) >= 0); if (!match) continue; } lastmsgtime = gettimer(); if (batchcmd) { addtobuffer(batchbuf, "## "); for (i=0; (i < metacount); i++) { addtobuffer(batchbuf, metadata[i]); addtobuffer(batchbuf, " "); } addtobuffer(batchbuf, "\n"); addtobuffer(batchbuf, restofmsg); addtobuffer(batchbuf, "\n"); } else { fprintf(logfd, "## "); for (i=0; (i < metacount); i++) fprintf(logfd, "%s ", metadata[i]); fprintf(logfd, "\n"); fprintf(logfd, "%s\n", restofmsg); } } } return 0; }