Mercurial > wflogs-daemon
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/wflogs-config.cpp Wed May 15 13:15:59 2013 -0700 @@ -0,0 +1,358 @@ +/* + +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"); +}