changeset 2:400b1de6e1c6

allow multiple config contexts
author Carl Byington <carl@five-ten-sg.com>
date Fri, 17 May 2013 10:32:12 -0700
parents 964c1127ae65
children 2ea606326f5b
files ChangeLog NEWS configure.in src/wflogs-config.cpp src/wflogs-config.h wflogs-daemon.conf wflogs-daemon.spec.in xml/wflogs-daemon.in
diffstat 8 files changed, 230 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed May 15 13:31:12 2013 -0700
+++ b/ChangeLog	Fri May 17 10:32:12 2013 -0700
@@ -1,3 +1,5 @@
+1.1 2013-05-17
+    Allow multiple config contexts.
+
 1.0 2013-05-15
     Initial release.
-
--- a/NEWS	Wed May 15 13:31:12 2013 -0700
+++ b/NEWS	Fri May 17 10:32:12 2013 -0700
@@ -1,1 +1,2 @@
+1.1  2013-05-17 allow multiple config contexts
 1.0  2013-05-15 Initial release.
--- a/configure.in	Wed May 15 13:31:12 2013 -0700
+++ b/configure.in	Fri May 17 10:32:12 2013 -0700
@@ -1,6 +1,6 @@
 
 AC_PREREQ(2.59)
-AC_INIT(wflogs-daemon,1.0,carl@five-ten-sg.com)
+AC_INIT(wflogs-daemon,1.1,carl@five-ten-sg.com)
 AC_CONFIG_SRCDIR([config.h.in])
 AC_CONFIG_HEADER([config.h])
 
--- a/src/wflogs-config.cpp	Wed May 15 13:31:12 2013 -0700
+++ b/src/wflogs-config.cpp	Fri May 17 10:32:12 2013 -0700
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2007 Carl Byington - 510 Software Group, released under
+Copyright (c) 2013 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
 
@@ -34,13 +34,11 @@
 
 ////////////////////////////////////////////////
 //
-CONFIG::CONFIG() {
-    reference_count    = 0;
+CONTEXT::CONTEXT(const char *nam) {
+    name               = nam;
     fd                 = -1;
     len                = 0;
     fdo                = -1;
-    generation         = 0;
-    load_time          = 0;
     period             = 120;
     versions           = 3;
     output             = NULL;
@@ -51,25 +49,25 @@
 }
 
 
-CONFIG::~CONFIG() {
+CONTEXT::~CONTEXT() {
+    free_all();
 }
 
 
-void CONFIG::sleep(int duration, time_t &previous) {
-    ::sleep(duration);
-    time_t now = time(NULL);
-    previous = now;
+void CONTEXT::dump() {
+    printf("context %s {\n", name);
+    printf("    period   %d; \n", period);
+    printf("    versions %d; \n", versions);
+    printf("    output   \"%s\";\n", output);
+    printf("    tempin   \"%s\";\n", tempin);
+    printf("    wflogs   \"%s\";\n", wflogs);
+    printf("    file     \"%s\";\n", fn);
+    printf("    pattern  \"%s\";\n", pattern);
+    printf("};\n\n");
 }
 
 
-void CONFIG::free_all() {
-    regfree(&re);
-    close();
-    closeo();
-}
-
-
-void CONFIG::openo(bool msg) {
+void CONTEXT::openo(bool msg) {
     open_time = time(NULL);
     fdo = ::creat(tempin, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
     if (fdo == -1) {
@@ -82,7 +80,7 @@
 }
 
 
-void CONFIG::open(bool msg) {
+void CONTEXT::open(bool msg) {
     fd        = ::open(fn, O_RDONLY);
     len       = 0;
     if (fd == -1) {
@@ -103,8 +101,8 @@
             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.
+        // specify that this fd gets closed on exec, so that wflogs
+        // won't have access to it.
         int oldflags = fcntl(fd, F_GETFD, 0);
         if (oldflags >= 0) {
             fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC);
@@ -113,7 +111,7 @@
 }
 
 
-bool CONFIG::write(char *p) {
+bool CONTEXT::write(char *p) {
     // p points to \0 at end of buf, may be destroyed
     if (failedo()) {
         openo(false);
@@ -124,7 +122,7 @@
 }
 
 
-bool CONFIG::read() {
+bool CONTEXT::read() {
     if (failed()) {
         open(false);
         if (failed()) return false;
@@ -164,13 +162,13 @@
 }
 
 
-void CONFIG::closeo() {
+void CONTEXT::closeo() {
     if (fdo != -1) ::close(fdo);
     fdo = -1;
 }
 
 
-void CONFIG::close() {
+void CONTEXT::close() {
     if (debug_syslog > 1) {
         snprintf(buf, sizeof(buf), "syslog file %s closed", fn);
         my_syslog(buf);
@@ -180,7 +178,7 @@
 }
 
 
-void CONFIG::process(char *p) {
+void CONTEXT::process(char *p) {
     // p points to \0 at end of buf, may be destroyed
     if (pattern) {
         if (0 == regexec(&re, buf, 0, NULL, 0)) {
@@ -193,7 +191,7 @@
 }
 
 
-void CONFIG::check_wflog() {
+void CONTEXT::check_wflog() {
     time_t now = time(NULL);
     if ((fdo != -1) && (open_time + period < now)) {
         closeo();
@@ -216,19 +214,58 @@
 }
 
 
+void CONTEXT::free_all() {
+    regfree(&re);
+    close();
+    closeo();
+}
+
+
+////////////////////////////////////////////////
+//
+CONFIG::CONFIG() {
+    reference_count    = 0;
+    generation         = 0;
+    load_time          = 0;
+}
+
+
+CONFIG::~CONFIG() {
+    for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) {
+        CONTEXT *c = *i;
+        delete c;
+    }
+}
+
+
 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);
+    for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) {
+        CONTEXTP c = *i;
+        c->dump();
+    }
+}
+
+
+bool CONFIG::read() {
+    bool rc = false;
+    for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) {
+        CONTEXT *c = *i;
+        rc |= c->read();
+    }
+}
+
+void CONFIG::sleep(int duration, time_t &previous) {
+    ::sleep(duration);
+    time_t now = time(NULL);
+    previous = now;
+}
+
+
+void CONFIG::free_all() {
+    for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) {
+        CONTEXT *c = *i;
+        c->free_all();
+    }
 }
 
 
@@ -283,67 +320,102 @@
 
 
 ////////////////////////////////////////////////
-// parse a config file
 //
-bool load_conf(CONFIG &dc, const char *fn) {
-    TOKEN tok(fn, &dc.config_files);
-    dc.set_token(tok);
+bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent);
+bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) {
+    const char *name = tok.next();
+    if (!tsa(tok, token_lbrace)) return false;
+    CONTEXTP con = new CONTEXT(name);
+    con->set_token(tok);
     while (true) {
         const char *have = tok.next();
         if (!have) break;
+        if (have == token_rbrace) break;  // done
         if (have == token_period) {
             have = tok.next();
-            dc.set_period(atoi(have));
+            con->set_period(atoi(have));
             if (!tsa(tok, token_semi)) return false;
         }
         else if (have == token_versions) {
             have = tok.next();
-            dc.set_versions(atoi(have));
+            con->set_versions(atoi(have));
             if (!tsa(tok, token_semi)) return false;
         }
         else if (have == token_output) {
-            dc.set_output(tok.next());
+            con->set_output(tok.next());
             if (!tsa(tok, token_semi)) return false;
         }
         else if (have == token_tempin) {
-            dc.set_tempin(tok.next());
+            con->set_tempin(tok.next());
             if (!tsa(tok, token_semi)) return false;
         }
         else if (have == token_wflogs) {
-            dc.set_wflogs(tok.next());
+            con->set_wflogs(tok.next());
             if (!tsa(tok, token_semi)) return false;
         }
         else if (have == token_file) {
-            dc.set_file(tok.next());
+            con->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);
+            con->pattern = tok.next();
+            int rc = regcomp(&con->re, con->pattern, REG_ICASE | REG_EXTENDED);
             if (rc) {
                 char bu[maxlen];
-                regerror(rc, &dc.re, bu, maxlen);
+                regerror(rc, &con->re, bu, maxlen);
                 char buf[maxlen];
-                snprintf(buf, sizeof(buf), "pattern %s not valid - %s", dc.pattern, bu);
+                snprintf(buf, sizeof(buf), "pattern %s not valid - %s", con->pattern, bu);
                 tok.token_error(buf);
-                dc.pattern = NULL;
+                con->pattern = NULL;
             }
 
             if (!tsa(tok, token_semi)) return false;
         }
         else {
-            tok.token_error("statement", have);
+            tok.token_error("period/versions/output/tempin/wflogs/file/pattern", have);
             return false;
         }
     }
+    if (!tsa(tok, token_semi)) {
+        delete con;
+        return false;
+    }
+    dc.add_context(con);
     return true;
 }
 
 
 ////////////////////////////////////////////////
+// parse a config file
+//
+bool load_conf(CONFIG &dc, const char *fn) {
+    int count = 0;
+    TOKEN tok(fn, &dc.config_files);
+    while (true) {
+        const char *have = tok.next();
+        if (!have) break;
+        if (have == token_context) {
+            if (!parse_context(tok, dc, NULL)) {
+                tok.token_error("load_conf() failed to parse context");
+                return false;
+            }
+            else count++;
+        }
+        else {
+            tok.token_error(token_context, have);
+            return false;
+        }
+    }
+    tok.token_error("load_conf() found %d contexts in %s", count, fn);
+    return (!dc.contexts.empty());
+}
+
+
+////////////////////////////////////////////////
 // init the tokens
 //
 void token_init() {
+    token_context    = register_string("context");
     token_file       = register_string("file");
     token_include    = register_string("include");
     token_lbrace     = register_string("{");
--- a/src/wflogs-config.h	Wed May 15 13:31:12 2013 -0700
+++ b/src/wflogs-config.h	Fri May 17 10:32:12 2013 -0700
@@ -1,6 +1,6 @@
 /*
 
-Copyright (c) 2007 Carl Byington - 510 Software Group, released under
+Copyright (c) 2013 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
 
@@ -20,10 +20,9 @@
 const int buflen = 1024;
 
 
-class CONFIG {
+class CONTEXT {
 public:
-    // the only mutable stuff once it has been loaded from the config file
-    int                 reference_count;    // protected by the global config_mutex
+    const char *        name;               // name of this context
     // input side
     int                 fd;                 // input fn syslog file
     struct stat         openfdstat;
@@ -32,10 +31,6 @@
     // output side
     int                 fdo;                // output tempin wflogs file
     time_t              open_time;          // time when fdo opened
-    // all the rest is constant after loading from the config file
-    int                 generation;
-    time_t              load_time;
-    string_set          config_files;
     TOKEN               *tokp;
     // our data
     int             period;     // in seconds
@@ -48,8 +43,8 @@
     const char *    pattern;    // regex to filter lines
     regex_t         re;         // internal regex to filter lines
 
-    CONFIG();
-    ~CONFIG();
+    CONTEXT(const char *nam);
+    ~CONTEXT();
     void    set_token(TOKEN &tok)       { tokp = &tok; };
     void    set_period(int p)           { period = p; };
     void    set_versions(int v)         { versions = v; };
@@ -61,15 +56,36 @@
     bool    failedo()                   { return (fdo == -1); };
     bool    failed()                    { return (fd == -1); };
     void    dump();
+    void    openo(bool msg);
     void    open(bool msg);
-    void    openo(bool msg);
+    bool    write(char *p);
     bool    read();
-    bool    write(char *p);
+    void    closeo();
+    void    close();
     void    process(char *p);
-    void    close();
-    void    closeo();
+    void    check_wflog();      // time to call it?
+    void    free_all();
+};
+typedef CONTEXT *               CONTEXTP;
+typedef list<CONTEXTP>          context_list;
+
+
+class CONFIG {
+public:
+    // the only mutable stuff once it has been loaded from the config file
+    int                 reference_count;    // protected by the global config_mutex
+    // all the rest is constant after loading from the config file
+    int                 generation;
+    time_t              load_time;
+    string_set          config_files;
+    context_list        contexts;
+
+    CONFIG();
+    ~CONFIG();
+    void    add_context(CONTEXTP con)  {contexts.push_back(con);} ;
+    void    dump();
+    bool    read();
     void    sleep(int duration, time_t &previous);
-    void    check_wflog();      // time to call it?
     void    free_all();
 };
 
@@ -77,11 +93,11 @@
 const char* register_string(string_set &s, const char *name);
 const char* register_string(const char *name);
 void        clear_strings();
-int         ip_address(const char *have);
 bool        load_conf(CONFIG &dc, const char *fn);
 void        token_init();
 
 
+extern const char *token_context;
 extern const char *token_file;
 extern const char *token_include;
 extern const char *token_lbrace;
--- a/wflogs-daemon.conf	Wed May 15 13:31:12 2013 -0700
+++ b/wflogs-daemon.conf	Fri May 17 10:32:12 2013 -0700
@@ -1,7 +1,30 @@
-period   120;
-versions 20;
-output   "/var/www/html/firewall.%d.html";
-tempin   "/tmp/wflogs.input";
-wflogs   "wflogs -i all -o html /tmp/wflogs.input >%s";
-file     "/var/log/messages";
-pattern  "vyatta kernel";
+context fast-response {
+    period   120;
+    versions 20;
+    output   "/var/www/html/firewall.0fast.%d.html";
+    tempin   "/tmp/wflogs.fast.input";
+    wflogs   "nice wflogs -i all -o html /tmp/wflogs.fast.input >%s &";
+    file     "/var/log/messages";
+    pattern  "vyatta kernel";
+};
+
+context daily {
+    period   86400;
+    versions 7;
+    output   "/var/www/html/firewall.1daily.%d.html";
+    tempin   "/tmp/wflogs.daily.input";
+    wflogs   "nice wflogs -i all -o html /tmp/wflogs.daily.input >%s &";
+    file     "/var/log/messages";
+    pattern  "vyatta kernel";
+};
+
+context weekly {
+    period   604800;
+    versions 4;
+    output   "/var/www/html/firewall.2weekly.%d.html";
+    tempin   "/tmp/wflogs.weekly.input";
+    wflogs   "nice wflogs -i all -o html /tmp/wflogs.weekly.input >%s &";
+    file     "/var/log/messages";
+    pattern  "vyatta kernel";
+};
+
--- a/wflogs-daemon.spec.in	Wed May 15 13:31:12 2013 -0700
+++ b/wflogs-daemon.spec.in	Fri May 17 10:32:12 2013 -0700
@@ -67,5 +67,8 @@
 
 
 %changelog
+* Fri May 17 2013 Carl Byington <carl@five-ten-sg.com> - 1.1-1
+- allow multiple config contexts
+
 * Wed May 15 2013 Carl Byington <carl@five-ten-sg.com> - 1.0-1
 - initial revision
--- a/xml/wflogs-daemon.in	Wed May 15 13:31:12 2013 -0700
+++ b/xml/wflogs-daemon.in	Fri May 17 10:32:12 2013 -0700
@@ -19,7 +19,7 @@
 
     <refentry id="@PACKAGE@.1">
         <refentryinfo>
-            <date>2013-05-15</date>
+            <date>2013-05-17</date>
         </refentryinfo>
 
         <refmeta>
@@ -128,7 +128,7 @@
 
     <refentry id="@PACKAGE@.conf.5">
         <refentryinfo>
-            <date>2013-05-15</date>
+            <date>2013-05-17</date>
         </refentryinfo>
 
         <refmeta>
@@ -157,7 +157,8 @@
             </para>
 
             <literallayout class="monospaced"><![CDATA[
-CONFIG     = {STATEMENT}+
+CONFIG     = {CONTEXT ";"}+
+CONTEXT    = "context" NAME "{" {STATEMENT}+ "}"
 STATEMENT := (PERIOD | VERSIONS | OUTPUT | TEMPIN | WFLOGS | FILE | PATTERN) ";"
 PERIOD    := "period" INTEGER-VALUE-SECONDS
 VERSIONS  := "versions" INTEGER-VALUE
@@ -171,13 +172,35 @@
         <refsect1 id='sample.5'>
             <title>Sample</title>
             <literallayout class="monospaced"><![CDATA[
-period   120;
-versions 3;
-output   "/var/www/html/firewall.%d.html";
-tempin   "/tmp/wflogs.input";
-wflogs   "wflogs -i all -o html /tmp/wflogs.input >%s";
-file     "/var/log/messages";
-pattern  "vyatta kernel";]]></literallayout>
+context fast-response {
+    period   120;
+    versions 20;
+    output   "/var/www/html/firewall.0fast.%d.html";
+    tempin   "/tmp/wflogs.fast.input";
+    wflogs   "nice wflogs -i all -o html /tmp/wflogs.fast.input >%s &";
+    file     "/var/log/messages";
+    pattern  "vyatta kernel";
+};
+
+context daily {
+    period   86400;
+    versions 7;
+    output   "/var/www/html/firewall.1daily.%d.html";
+    tempin   "/tmp/wflogs.daily.input";
+    wflogs   "nice wflogs -i all -o html /tmp/wflogs.daily.input >%s &";
+    file     "/var/log/messages";
+    pattern  "vyatta kernel";
+};
+
+context weekly {
+    period   604800;
+    versions 4;
+    output   "/var/www/html/firewall.2weekly.%d.html";
+    tempin   "/tmp/wflogs.weekly.input";
+    wflogs   "nice wflogs -i all -o html /tmp/wflogs.weekly.input >%s &";
+    file     "/var/log/messages";
+    pattern  "vyatta kernel";
+};]]></literallayout>
         </refsect1>
 
         <refsect1 id='version.5'>