Mercurial > wflogs-daemon
view src/wflogs-config.cpp @ 0:0aa1171aebd2 stable-1-0-0
initial version
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Wed, 15 May 2013 13:15:59 -0700 |
parents | |
children | 400b1de6e1c6 |
line wrap: on
line source
/* Copyright (c) 2007 Carl Byington - 510 Software Group, released under the GPL version 3 or any later version at your choice available at http://www.gnu.org/licenses/gpl-3.0.txt */ #include "includes.h" #include <fcntl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #include <limits.h> const char *token_context; const char *token_file; const char *token_include; const char *token_lbrace; const char *token_output; const char *token_pattern; const char *token_period; const char *token_rbrace; const char *token_semi; const char *token_tempin; const char *token_versions; const char *token_wflogs; string_set all_strings;// owns all the strings, only modified by the config loader thread const int maxlen = 1000; // used for snprintf buffers //////////////////////////////////////////////// // CONFIG::CONFIG() { reference_count = 0; fd = -1; len = 0; fdo = -1; generation = 0; load_time = 0; period = 120; versions = 3; output = NULL; tempin = NULL; wflogs = NULL; fn = NULL; pattern = NULL; } CONFIG::~CONFIG() { } void CONFIG::sleep(int duration, time_t &previous) { ::sleep(duration); time_t now = time(NULL); previous = now; } void CONFIG::free_all() { regfree(&re); close(); closeo(); } void CONFIG::openo(bool msg) { open_time = time(NULL); fdo = ::creat(tempin, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fdo == -1) { if (msg) { char buf[maxlen]; snprintf(buf, sizeof(buf), "wflogs tempin file %s not writeable", tempin); tokp->token_error(buf); } } } void CONFIG::open(bool msg) { fd = ::open(fn, O_RDONLY); len = 0; if (fd == -1) { if (msg) { char buf[maxlen]; snprintf(buf, sizeof(buf), "syslog file %s not readable", fn); tokp->token_error(buf); } } else { if (debug_syslog > 1) { snprintf(buf, sizeof(buf), "syslog file %s opened", fn); my_syslog(buf); } if (msg) lseek(fd, 0, SEEK_END); if (fstat(fd, &openfdstat)) { close(); snprintf(buf, sizeof(buf), "syslog file %s cannot stat after open", fn); tokp->token_error(buf); } // specify that this fd gets closed on exec, so that selinux // won't complain about iptables trying to read log files. int oldflags = fcntl(fd, F_GETFD, 0); if (oldflags >= 0) { fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC); } } } bool CONFIG::write(char *p) { // p points to \0 at end of buf, may be destroyed if (failedo()) { openo(false); if (failedo()) return false; } *p = '\n'; ::write(fdo, buf, p-buf+1); } bool CONFIG::read() { if (failed()) { open(false); if (failed()) return false; } int n = ::read(fd, buf+len, buflen-len); bool have = (n > 0); if (have) { len += n; while (true) { char *p = (char*)memchr(buf, '\n', len); if (!p) break; n = p-buf; *p = '\0'; process(p); // process null terminated string, but may destroy the null len -= n+1; memmove(buf, p+1, len); } // no <lf> in a full buffer if (len == buflen) len = 0; } else { // check for file close struct stat filenamest; if (0 == stat(fn, &filenamest)) { if ((filenamest.st_dev != openfdstat.st_dev) || (filenamest.st_ino != openfdstat.st_ino)) { close(); } } else { // filename no longer exists close(); } } check_wflog(); return have; } void CONFIG::closeo() { if (fdo != -1) ::close(fdo); fdo = -1; } void CONFIG::close() { if (debug_syslog > 1) { snprintf(buf, sizeof(buf), "syslog file %s closed", fn); my_syslog(buf); } if (fd != -1) ::close(fd); fd = -1; } void CONFIG::process(char *p) { // p points to \0 at end of buf, may be destroyed if (pattern) { if (0 == regexec(&re, buf, 0, NULL, 0)) { if (debug_syslog > 2) { my_syslog(buf); // show lines with matches } write(p); } } } void CONFIG::check_wflog() { time_t now = time(NULL); if ((fdo != -1) && (open_time + period < now)) { closeo(); // rename previous wflog html output files char buf[maxlen]; char fn1[maxlen]; char fn2[maxlen]; for (int i=1; i<versions; i++) { int j = versions - 1 - i; int k = j + 1; snprintf(fn1, maxlen, output, j); snprintf(fn2, maxlen, output, k); snprintf(buf, maxlen, "mv \"%s\" \"%s\"", fn1, fn2); system(buf); } snprintf(buf, maxlen, wflogs, fn1); system(buf); openo(false); } } void CONFIG::dump() { int level = 0; char indent[maxlen]; int i = min(maxlen-1, level*4); memset(indent, ' ', i); indent[i] = '\0'; printf("%s period %d; \n", indent, period); printf("%s versions %d; \n", indent, versions); printf("%s output \"%s\";\n", indent, output); printf("%s tempin \"%s\";\n", indent, tempin); printf("%s wflogs \"%s\";\n", indent, wflogs); printf("%s file \"%s\";\n", indent, fn); printf("%s pattern \"%s\";\n", indent, pattern); } //////////////////////////////////////////////// // helper to discard the strings held by a string_set // void discard(string_set &s) { for (string_set::iterator i=s.begin(); i!=s.end(); i++) { free((void*)*i); } s.clear(); } //////////////////////////////////////////////// // helper to register a string in a string set // const char* register_string(string_set &s, const char *name) { string_set::const_iterator i = s.find(name); if (i != s.end()) return *i; char *x = strdup(name); s.insert(x); return x; } //////////////////////////////////////////////// // register a global string // const char* register_string(const char *name) { return register_string(all_strings, name); } //////////////////////////////////////////////// // clear all global strings, helper for valgrind checking // void clear_strings() { discard(all_strings); } //////////////////////////////////////////////// // bool tsa(TOKEN &tok, const char *token); bool tsa(TOKEN &tok, const char *token) { const char *have = tok.next(); if (have == token) return true; tok.token_error(token, have); return false; } //////////////////////////////////////////////// // parse a config file // bool load_conf(CONFIG &dc, const char *fn) { TOKEN tok(fn, &dc.config_files); dc.set_token(tok); while (true) { const char *have = tok.next(); if (!have) break; if (have == token_period) { have = tok.next(); dc.set_period(atoi(have)); if (!tsa(tok, token_semi)) return false; } else if (have == token_versions) { have = tok.next(); dc.set_versions(atoi(have)); if (!tsa(tok, token_semi)) return false; } else if (have == token_output) { dc.set_output(tok.next()); if (!tsa(tok, token_semi)) return false; } else if (have == token_tempin) { dc.set_tempin(tok.next()); if (!tsa(tok, token_semi)) return false; } else if (have == token_wflogs) { dc.set_wflogs(tok.next()); if (!tsa(tok, token_semi)) return false; } else if (have == token_file) { dc.set_file(tok.next()); if (!tsa(tok, token_semi)) return false; } else if (have == token_pattern) { dc.pattern = tok.next(); int rc = regcomp(&dc.re, dc.pattern, REG_ICASE | REG_EXTENDED); if (rc) { char bu[maxlen]; regerror(rc, &dc.re, bu, maxlen); char buf[maxlen]; snprintf(buf, sizeof(buf), "pattern %s not valid - %s", dc.pattern, bu); tok.token_error(buf); dc.pattern = NULL; } if (!tsa(tok, token_semi)) return false; } else { tok.token_error("statement", have); return false; } } return true; } //////////////////////////////////////////////// // init the tokens // void token_init() { token_file = register_string("file"); token_include = register_string("include"); token_lbrace = register_string("{"); token_output = register_string("output"); token_pattern = register_string("pattern"); token_period = register_string("period"); token_rbrace = register_string("}"); token_semi = register_string(";"); token_tempin = register_string("tempin"); token_versions = register_string("versions"); token_wflogs = register_string("wflogs"); }