implement logwatch_conf_filter such that it compiles and loads, but not yet tested
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cmake/Modules/FindPCRE.cmake Wed Apr 08 02:25:30 2009 +0300
@@ -0,0 +1,23 @@
+# Find PCRE
+# Once done, this will define:
+#
+# PCRE_FOUND
+# PCRE_INCLUDE_DIRS
+# PCRE_LIBRARIES
+
+include (LibFindMacros)
+
+# include dir
+find_path (PCRE_INCLUDE_DIR
+ NAMES "pcre.h"
+)
+
+# library
+find_library (PCRE_LIBRARY
+ NAMES "pcre"
+)
+
+# set the external vars
+set (PCRE_PROCESS_INCLUDES PCRE_INCLUDE_DIR)
+set (PCRE_PROCESS_LIBS PCRE_LIBRARY)
+libfind_process (PCRE)
--- a/src/CMakeLists.txt Wed Apr 08 01:28:46 2009 +0300
+++ b/src/CMakeLists.txt Wed Apr 08 02:25:30 2009 +0300
@@ -4,9 +4,10 @@
find_package (LibPQ REQUIRED)
find_package (Evsql REQUIRED)
find_package (Lua51 REQUIRED)
+find_package (PCRE REQUIRED)
# add our include path
-include_directories (${LibEvent_INCLUDE_DIRS} ${GnuTLS_INCLUDE_DIRS} ${Evsql_INCLUDE_DIRS} ${Lua51_INCLUDE_DIRS})
+include_directories (${LibEvent_INCLUDE_DIRS} ${GnuTLS_INCLUDE_DIRS} ${Evsql_INCLUDE_DIRS} ${Lua51_INCLUDE_DIRS} ${PCRE_INCLUDE_DIRS})
# define our source code modules
set (CORE_SOURCES error.c log.c)
@@ -18,7 +19,7 @@
set (NEXUS_SOURCES nexus.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES} ${LUA_SOURCES} ${CONSOLE_SOURCES} signals.c module.c config.c)
set (TEST_SOURCES test.c ${CORE_SOURCES} ${SOCK_SOURCES} ${IRC_SOURCES})
set (IRC_LOG_SOURCES modules/irc_log.c)
-set (LOGWATCH_SOURCES modules/logwatch.c modules/logwatch_source.c)
+set (LOGWATCH_SOURCES modules/logwatch.c modules/logwatch_source.c modules/logwatch_filter.c)
# define our libraries
set (MODULE_LIBRARIES "dl")
@@ -39,6 +40,7 @@
target_link_libraries (nexus ${NEXUS_LIBRARIES})
target_link_libraries (test ${NEXUS_LIBRARIES})
target_link_libraries (irc_log ${Evsql_LIBRARIES})
+target_link_libraries (logwatch ${PCRE_LIBRARIES})
# global target properties
set_target_properties (nexus test irc_log logwatch PROPERTIES
--- a/src/config.c Wed Apr 08 01:28:46 2009 +0300
+++ b/src/config.c Wed Apr 08 02:25:30 2009 +0300
@@ -128,7 +128,7 @@
}
// the option's handler?
- if (option->func && option->func(ctx, values, err))
+ if (option->func && option->func(ctx, option, values, err))
goto error;
// ok
@@ -170,7 +170,7 @@
return config_apply(options, ctx, name, conf_value, err);
}
-err_t config_apply_raw (const struct config_option *options, struct nexus *nexus, void *ctx, const char *name, char *raw_value, struct error_info *err)
+err_t config_apply_raw (const struct config_option options[], struct nexus *nexus, void *ctx, const char *name, char *raw_value, struct error_info *err)
{
const struct config_option *option;
struct config_value value[2] = {
@@ -190,3 +190,46 @@
return config_apply_opt(option, ctx, value, err);
}
+const struct config_value* config_get_value (const struct config_option *option, const struct config_value values[], const char *name)
+{
+ const struct config_param *param;
+ const struct config_value *value;
+
+ // handle each param
+ for (param = option->params, value = values; param->name && param->type && value->type; param++, value++) {
+ // matches?
+ if (strcmp(param->name, name) == 0) {
+ // not NULL?
+ if (value->type != CONFIG_NULL)
+ return value;
+
+ else
+ return NULL;
+ }
+ }
+
+ // not found
+ return NULL;
+}
+
+const char* config_get_string (const struct config_option *option, const struct config_value values[], const char *name)
+{
+ const struct config_value *value;
+
+ return (value = config_get_value(option, values, name)) ? value->string : NULL;
+}
+
+struct irc_chan* config_get_irc_chan (const struct config_option *option, const struct config_value values[], const char *name)
+{
+ const struct config_value *value;
+
+ return (value = config_get_value(option, values, name)) ? value->irc_chan : NULL;
+}
+
+void* config_get_user (const struct config_option *option, const struct config_value values[], const char *name, const char *user_type)
+{
+ const struct config_value *value;
+
+ return ((value = config_get_value(option, values, name)) && strcmp(value->user.type, user_type) == 0) ? value->user.ptr : NULL;
+}
+
--- a/src/config.h Wed Apr 08 01:28:46 2009 +0300
+++ b/src/config.h Wed Apr 08 02:25:30 2009 +0300
@@ -15,9 +15,15 @@
enum config_type {
CONFIG_INVALID,
+ /** No value at all */
+ CONFIG_NULL,
+
/** A plain NUL-terminated string */
CONFIG_STRING,
+ /** A user-defined type, further identified by a string */
+ CONFIG_USER,
+
/** An IRC channel */
CONFIG_IRC_CHAN,
};
@@ -36,6 +42,15 @@
/** Value for CONFIG_IRC_CHAN */
struct irc_chan *irc_chan;
+
+ /** Value for CONFIG_USER */
+ struct {
+ /** The specific user type */
+ const char *type;
+
+ /** A pointer to the user type */
+ void *ptr;
+ } user;
};
};
@@ -49,6 +64,9 @@
/** The type */
enum config_type type;
+ /** The specific type for CONFIG_USER */
+ const char *user_type;
+
/** Description */
const char *description;
@@ -60,6 +78,9 @@
/** Use handler function? */
bool is_handler;
+
+ /** Optional value? */
+ bool optional;
};
/**
@@ -83,38 +104,56 @@
const struct config_param params[CONFIG_PARAMS_MAX];
/** The handler function */
- err_t (*func) (void *ctx, const struct config_value values[], struct error_info *err);
+ err_t (*func) (void *ctx, const struct config_option *option, const struct config_value values[], struct error_info *err);
/** Help text */
const char *help;
};
-#define CONFIG_PARAM(name, type, desc) \
- { name, type, desc, { NULL }, false }
+#define CONFIG_PARAM(name, type, desc, optional) \
+ { name, type, NULL, desc, { NULL }, false, optional }
+
+#define CONFIG_PARAM_OPTIONAL(name, type, desc) \
+ CONFIG_PARAM(name, type, desc, true)
+
+#define CONFIG_PARAM_USER(name, user_type, desc, optional) \
+ { name, CONFIG_USER, user_type, desc, { NULL }, false, optional }
+
+#define CONFIG_PARAM_USER_OPTIONAL(name, user_type, desc) \
+ CONFIG_PARAM_USER(name, user_type, desc, true)
#define CONFIG_PARAM_HANDLER(name, type, desc, _func_name_, func) \
- { name, type, desc, {._func_name_ = func }, true }
+ { name, type, NULL, desc, {._func_name_ = func }, true, false }
-#define CONFIG_OPT(name, params, func, help) \
- { name, params, func, help }
+#define CONFIG_PARAM_END \
+ { NULL, 0, NULL, NULL, { NULL }, false, false }
+
+#define CONFIG_OPT(name, func, help, ...) \
+ { name, { __VA_ARGS__, CONFIG_PARAM_END }, func, help }
#define CONFIG_OPT_STRING(name, func, desc, help) \
- { name, { CONFIG_PARAM_HANDLER(name, CONFIG_STRING, desc, string, func) }, NULL, help }
+ CONFIG_OPT(name, NULL, help, CONFIG_PARAM_HANDLER(name, CONFIG_STRING, desc, string, func))
#define CONFIG_OPT_IRC_CHAN(name, func, desc, help) \
- { name, { CONFIG_PARAM_HANDLER(name, CONFIG_IRC_CHAN, desc, irc_chan, func) }, NULL, help }
+ CONFIG_OPT(name, NULL, help, CONFIG_PARAM_HANDLER(name, CONFIG_IRC_CHAN, desc, irc_chan, func))
#define CONFIG_OPT_END \
{ NULL, {}, NULL, NULL }
+#define CONFIG_OPTIONS(...) \
+ { __VA_ARGS__, CONFIG_OPT_END }
+
#define CONFIG_VALUE(type, _name_, value) \
- { (type), { ._name_ = (value) } }
+ { (type), { ._name_ = value } }
#define CONFIG_VALUE_STRING(str_value) \
- CONFIG_VALUE(CONFIG_STRING, string, str_value)
+ CONFIG_VALUE(CONFIG_STRING, string, (str_value))
#define CONFIG_VALUE_IRC_CHAN(irc_chan_value) \
- CONFIG_VALUE(CONFIG_IRC_CHAN, irc_chan, irc_chan_value)
+ CONFIG_VALUE(CONFIG_IRC_CHAN, irc_chan, (irc_chan_value))
+
+#define CONFIG_VALUE_USER(user_type, user_value) \
+ CONFIG_VALUE(CONFIG_USER, user, { user_type, user_value })
#define CONFIG_VALUE_END \
{ 0, { NULL } }
@@ -206,6 +245,15 @@
*
* @see config_parse
*/
-err_t config_apply_raw (const struct config_option *options, struct nexus *nexus, void *ctx, const char *name, char *raw_value, struct error_info *err);
+err_t config_apply_raw (const struct config_option option[], struct nexus *nexus, void *ctx, const char *name, char *raw_value, struct error_info *err);
+
+/**
+ * Lookup a config_value by name from the given list of config_values for the given config_option
+ */
+const struct config_value* config_get_value (const struct config_option *option, const struct config_value values[], const char *name);
+
+const char* config_get_string (const struct config_option *option, const struct config_value values[], const char *name);
+struct irc_chan* config_get_irc_chan (const struct config_option *option, const struct config_value values[], const char *name);
+void* config_get_user (const struct config_option *option, const struct config_value values[], const char *name, const char *user_type);
#endif
--- a/src/error.c Wed Apr 08 01:28:46 2009 +0300
+++ b/src/error.c Wed Apr 08 02:25:30 2009 +0300
@@ -59,14 +59,11 @@
{ _ERR_INVALID, NULL, 0 }
}, _config_error_desc[] = {
- // extra: the (unknown) config field name
- { ERR_CONFIG_NAME, "no matching config name", ERR_EXTRA_STR },
-
- // XXX: extra: the mismatching types
- { ERR_CONFIG_TYPE, "wrong config type", ERR_EXTRA_NONE },
-
- // extra: the name of the field with missing value
+ { ERR_CONFIG_NAME, "unknown config option", ERR_EXTRA_STR },
+ { ERR_CONFIG_TYPE, "invalid config type", ERR_EXTRA_NONE },
{ ERR_CONFIG_REQUIRED, "missing required value", ERR_EXTRA_STR },
+ { ERR_CONFIG_VALUE, "invalid value", ERR_EXTRA_STR },
+ { ERR_CONFIG_PARAMS, "invalid number of paramters", ERR_EXTRA_NONE },
{ _ERR_INVALID, NULL, 0 }
@@ -97,6 +94,7 @@
_sock_error_desc,
_sock_gnutls_error_desc,
_irc_error_desc,
+ _config_error_desc,
_module_error_desc,
_lua_error_desc,
NULL
--- a/src/error.h Wed Apr 08 01:28:46 2009 +0300
+++ b/src/error.h Wed Apr 08 02:25:30 2009 +0300
@@ -108,6 +108,10 @@
_ERR_IRC_CHAN = 0x000d00,
ERR_IRC_CHAN_STATE,
+ /** pcre errors */
+ _ERR_PCRE = 0x000e00,
+ ERR_PCRE_COMPILE, ///< pcre_compile: <error_msg>
+
/** General errors */
_ERR_GENERAL = 0xffff00,
ERR_CMD_OPT,
--- a/src/modules/irc_log.c Wed Apr 08 01:28:46 2009 +0300
+++ b/src/modules/irc_log.c Wed Apr 08 02:25:30 2009 +0300
@@ -462,12 +462,10 @@
/**
* Our configuration options
*/
-struct config_option irc_log_config_options[] = {
+struct config_option irc_log_config_options[] = CONFIG_OPTIONS(
CONFIG_OPT_STRING( "db_info", &irc_log_conf_db_info, "[<key>=<value> [...]]", "set database connection info, see libpq docs" ),
- CONFIG_OPT_IRC_CHAN( "channel", &irc_log_conf_channel, "<channel>", "log the given channel" ),
-
- CONFIG_OPT_END
-};
+ CONFIG_OPT_IRC_CHAN( "channel", &irc_log_conf_channel, "<channel>", "log the given channel" )
+);
/**
* Deinitialize, logging CLOSE events for all channels, and removing any hooks we've added
--- a/src/modules/logwatch.c Wed Apr 08 01:28:46 2009 +0300
+++ b/src/modules/logwatch.c Wed Apr 08 02:25:30 2009 +0300
@@ -24,6 +24,27 @@
return SUCCESS;
}
+struct logwatch_chan* logwatch_add_chan (struct logwatch *ctx, struct irc_chan *chan, struct error_info *err)
+{
+ struct logwatch_chan *lw_chan;
+
+ // alloc
+ if ((lw_chan = calloc(1, sizeof(*lw_chan))) == NULL)
+ JUMP_SET_ERROR(err, ERR_CALLOC);
+
+ // store
+ lw_chan->chan = chan;
+
+ // add to list
+ TAILQ_INSERT_TAIL(&ctx->channels, lw_chan, logwatch_channels);
+
+ // ok
+ return lw_chan;
+
+error:
+ return NULL;
+}
+
/**
* Add a logwatch_source with a FIFO at the given path
*/
@@ -40,13 +61,53 @@
}
/**
+ * Add a logwatch_filter for the given bits
+ */
+static err_t logwatch_conf_filter (void *_ctx, const struct config_option *option, const struct config_value values[], struct error_info *err)
+{
+ struct logwatch *ctx = _ctx;
+ struct logwatch_filter *filter;
+
+ const struct logwatch_source *source;
+ const char *name, *pattern, *format;
+ struct irc_chan *chan;
+
+ // parse arguments
+ name = config_get_string (option, values, "name" );
+ source = config_get_user (option, values, "source", "logwatch_source" );
+ pattern = config_get_string (option, values, "pattern" );
+ format = config_get_string (option, values, "format" );
+ chan = config_get_irc_chan (option, values, "chan" );
+
+ // invoke
+ if ((filter = logwatch_filter(ctx, name, source, pattern, format, chan, err)) == NULL)
+ goto error;
+
+ // ok
+ return SUCCESS;
+
+error:
+ return ERROR_CODE(err);
+}
+
+/**
* Configuration options
*/
-struct config_option logwatch_config_options[] = {
- CONFIG_OPT_STRING( "source_fifo", &logwatch_conf_source_fifo, "<path>", "read lines from the fifo at the given path" ),
+struct config_option logwatch_config_options[] = CONFIG_OPTIONS(
+ CONFIG_OPT_STRING( "source_fifo", logwatch_conf_source_fifo, "<path>", "read lines from the fifo at the given path" ),
- CONFIG_OPT_END
-};
+ CONFIG_OPT( "filter", logwatch_conf_filter,
+ "filter lines (from source, if given), using the given regular expression pattern (if given), "
+ "format output using the given format expression (if given), and finally send the filtered/formatted lines "
+ "to the given channel",
+
+ CONFIG_PARAM( "name", CONFIG_STRING, "filter name", false ),
+ CONFIG_PARAM_USER( "source", "logwatch_source", "optional logwatch_source to use", true ),
+ CONFIG_PARAM( "pattern", CONFIG_STRING, "optional regular expression pattern", true ),
+ CONFIG_PARAM( "format", CONFIG_STRING, "optional output format", true ),
+ CONFIG_PARAM( "chan", CONFIG_IRC_CHAN, "channel to send output to", false )
+ )
+);
/**
* Deinitialize by freeing all filters, closing all sources, and releasing all channels.
--- a/src/modules/logwatch.h Wed Apr 08 01:28:46 2009 +0300
+++ b/src/modules/logwatch.h Wed Apr 08 02:25:30 2009 +0300
@@ -17,7 +17,7 @@
* XXX: currently this is just hardcoded to be a FIFO
*/
struct logwatch_source {
- /** The logwatch context */
+ /** The logwatch context we are registered to */
struct logwatch *ctx;
/** The input FIFO */
@@ -36,20 +36,29 @@
* A filter specifies what lines to match, and how to then format the output.
*/
struct logwatch_filter {
+ /** The logwatch context we are registered to */
+ struct logwatch *ctx;
+
/** The name of the filter */
char *name;
/** The source to restrict this to, if any */
- const struct logwatch_sourcee *source;
+ const struct logwatch_source *source;
- /** The compiled regular expression to match */
+ /**
+ * The compiled regular expression to match, or NULL to match all lines.
+ */
pcre *regexp;
- /** The output format string */
+ /**
+ * The output format string, or NULL to send the line itself as-is
+ */
char *format;
- /** The channel to send output to */
- struct logwatch_chan *chan;
+ /**
+ * The channel to send output to
+ */
+ struct irc_chan *chan;
/** Our entry in logwatch::filters */
TAILQ_ENTRY(logwatch_filter) logwatch_filters;
@@ -57,6 +66,8 @@
/**
* A channel for outputting logwatch output
+ *
+ * XXX; do we need this?
*/
struct logwatch_chan {
/** The channel... */
@@ -102,12 +113,19 @@
/**
* Add a new output channel
+ *
+ * XXX; do we need this?
*/
-struct logwatch_chan* logwatch_add_chan (struct logwatch *ctx, struct irc_chan *chan);
+struct logwatch_chan* logwatch_add_chan (struct logwatch *ctx, struct irc_chan *chan, struct error_info *err);
/**
* Add a new filter
*/
-struct logwatch_filter logwatch_add_filter (struct logwatch *ctx, const struct logwatch_source *source,
- const char *regexp, const char *fmt, struct logwatch_chan *chan);
+struct logwatch_filter* logwatch_filter (struct logwatch *ctx, const char *name, const struct logwatch_source *source,
+ const char *pattern, const char *fmt, struct irc_chan *chan, struct error_info *err);
+/**
+ * Destroy a logwatch_filter, unregistering it
+ */
+void logwatch_filter_destroy (struct logwatch_filter *filter);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/logwatch_filter.c Wed Apr 08 02:25:30 2009 +0300
@@ -0,0 +1,61 @@
+#include "logwatch.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct logwatch_filter* logwatch_filter (struct logwatch *ctx, const char *name, const struct logwatch_source *source,
+ const char *pattern, const char *format, struct irc_chan *chan, struct error_info *err)
+{
+ struct logwatch_filter *filter;
+ const char *err_msg;
+ int err_offset;
+
+ // alloc
+ if ((filter = calloc(1, sizeof(*filter))) == NULL)
+ JUMP_SET_ERROR(err, ERR_CALLOC);
+
+ // optional source
+ filter->source = source;
+
+ // name?
+ if (name && (filter->name = strdup(name)) == NULL)
+ JUMP_SET_ERROR(err, ERR_STRDUP);
+
+ // compile the regexp
+ // XXX: any flags?
+ if (pattern && (filter->regexp = pcre_compile(pattern, 0, &err_msg, &err_offset, NULL)))
+ JUMP_SET_ERROR_STR(err, ERR_PCRE_COMPILE, err_msg);
+
+ // format?
+ if (format && (filter->format = strdup(format)) == NULL)
+ JUMP_SET_ERROR(err, ERR_STRDUP);
+
+ // output channel
+ filter->chan = chan;
+
+ // add it
+ TAILQ_INSERT_TAIL(&ctx->filters, filter, logwatch_filters);
+ filter->ctx = ctx;
+
+ // ok
+ return filter;
+
+error:
+ // cleanup
+ if (filter)
+ logwatch_filter_destroy(filter);
+
+ return NULL;
+}
+
+void logwatch_filter_destroy (struct logwatch_filter *filter)
+{
+ if (filter->ctx)
+ // remove it
+ TAILQ_REMOVE(&filter->ctx->filters, filter, logwatch_filters);
+
+ free(filter->format);
+ if (filter->regexp) pcre_free(filter->regexp);
+ free(filter->name);
+ free(filter);
+}