--- a/src/CMakeLists.txt Tue Apr 07 19:41:48 2009 +0300
+++ b/src/CMakeLists.txt Tue Apr 07 21:09:25 2009 +0300
@@ -18,6 +18,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)
# define our libraries
set (MODULE_LIBRARIES "dl")
@@ -32,6 +33,7 @@
# add our modules
add_library (irc_log MODULE ${IRC_LOG_SOURCES})
+add_library (logwatch MODULE ${LOGWATCH_SOURCES})
# set libraries
target_link_libraries (nexus ${NEXUS_LIBRARIES})
@@ -39,7 +41,7 @@
target_link_libraries (irc_log ${Evsql_LIBRARIES})
# global target properties
-set_target_properties (nexus test irc_log PROPERTIES
+set_target_properties (nexus test irc_log logwatch PROPERTIES
COMPILE_FLAGS ${CFLAGS}
)
@@ -49,7 +51,7 @@
)
# modules have weird names
-set_target_properties (irc_log PROPERTIES
+set_target_properties (irc_log logwatch PROPERTIES
PREFIX "mod_"
LIBRARY_OUTPUT_DIRECTORY "modules"
)
--- a/src/module.c Tue Apr 07 19:41:48 2009 +0300
+++ b/src/module.c Tue Apr 07 21:09:25 2009 +0300
@@ -316,15 +316,21 @@
// update status
module->unloading = true;
- // invoke the unload func, passing it our reference
- // note that the module might not exist anymore after calling this
- if ((err = module->desc->unload(module->ctx, module))) {
- // mark it as "unloaded"
+ if (module->desc->unload) {
+ // invoke the unload func, passing it our reference
+ // note that the module might not exist anymore after calling this
+ if ((err = module->desc->unload(module->ctx, module))) {
+ // mark it as "unloaded"
+ module_unloaded(module);
+
+ return err;
+ }
+
+ } else {
+ // no unload procedure, just destroy it as soon as needed
module_unloaded(module);
- return err;
}
-
// ok
return SUCCESS;
}
@@ -371,7 +377,7 @@
TAILQ_REMOVE(&module->modules->list, module, modules_list);
// run the destroy hook
- if (module->desc && module->desc->destroy)
+ if (module->desc && module->desc->destroy && module->ctx)
module->desc->destroy(module->ctx);
// unload the dl handle
--- a/src/module.h Tue Apr 07 19:41:48 2009 +0300
+++ b/src/module.h Tue Apr 07 21:09:25 2009 +0300
@@ -88,7 +88,7 @@
* If the unload operation fails (returns an error code), then the module is considered as unloaded (as if
* module_unloaded() was called - don't call this if you return an error).
*
- * Implementing this is mandatory.
+ * Implementing this is optional, if all of this can be implemented in destroy.
*
* @param ctx the module's context pointer as returned by init
* @param module the hanging module reference, that must be passed to module_unloaded()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/logwatch.c Tue Apr 07 21:09:25 2009 +0300
@@ -0,0 +1,84 @@
+#include "logwatch.h"
+
+#include "../config.h"
+
+static err_t logwatch_init (struct nexus *nexus, void **ctx_ptr, struct error_info *err)
+{
+ struct logwatch *ctx;
+
+ // allocate
+ if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
+ RETURN_SET_ERROR(err, ERR_CALLOC);
+
+ // init
+ TAILQ_INIT(&ctx->sources);
+ TAILQ_INIT(&ctx->filters);
+ TAILQ_INIT(&ctx->channels);
+
+ // store
+ ctx->nexus = nexus;
+
+ // ok
+ *ctx_ptr = ctx;
+
+ return SUCCESS;
+}
+
+/**
+ * Add a logwatch_source with a FIFO at the given path
+ */
+static err_t logwatch_conf_source_fifo (void *_ctx, char *path, struct error_info *err)
+{
+ struct logwatch *ctx = _ctx;
+
+ // open it
+ if (logwatch_open_fifo(ctx, path, err) == NULL)
+ return ERROR_CODE(err);
+
+ // ok
+ return SUCCESS;
+}
+
+/**
+ * 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" ),
+
+ CONFIG_OPT_END
+};
+
+/**
+ * Deinitialize by freeing all filters, closing all sources, and releasing all channels.
+ *
+ * XXX: unused
+ */
+static err_t logwatch_unload (void *_ctx, struct module *module)
+{
+ struct logwatch *ctx = _ctx;
+
+ // XXX: implement
+
+ return SUCCESS;
+}
+
+static void logwatch_destroy (void *_ctx)
+{
+ struct logwatch *ctx = _ctx;
+ struct logwatch_source *source;
+
+ // flush the sources list
+ while ((source = TAILQ_FIRST(&ctx->sources)))
+ logwatch_source_destroy(source);
+}
+
+/**
+ * The module function table
+ */
+struct module_desc logwatch_module = {
+ .init = logwatch_init,
+ .config_options = logwatch_config_options,
+ .unload = NULL, // logwatch_unload,
+ .destroy = logwatch_destroy
+};
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/logwatch.h Tue Apr 07 21:09:25 2009 +0300
@@ -0,0 +1,113 @@
+/**
+ * @file
+ *
+ * A module to filter out certain lines from normal syslog() files, and forward them to an IRC channel.
+ */
+#include <sys/queue.h>
+#include "../irc_chan.h"
+#include "../sock.h"
+#include "../line_proto.h"
+
+#include <event2/event.h>
+#include <pcre.h>
+
+/**
+ * A source of log lines.
+ *
+ * XXX: currently this is just hardcoded to be a FIFO
+ */
+struct logwatch_source {
+ /** The logwatch context */
+ struct logwatch *ctx;
+
+ /** The input FIFO */
+ struct line_proto *lp;
+
+ /** Our entry in logwatch::sources */
+ TAILQ_ENTRY(logwatch_source) logwatch_sources;
+};
+
+/**
+ * Maximum length of input lines
+ */
+#define LOGWATCH_SOURCE_LINE_MAX 1024
+
+/**
+ * A filter specifies what lines to match, and how to then format the output.
+ */
+struct logwatch_filter {
+ /** The name of the filter */
+ char *name;
+
+ /** The source to restrict this to, if any */
+ const struct logwatch_sourcee *source;
+
+ /** The compiled regular expression to match */
+ pcre *regexp;
+
+ /** The output format string */
+ char *format;
+
+ /** The channel to send output to */
+ struct logwatch_chan *chan;
+
+ /** Our entry in logwatch::filters */
+ TAILQ_ENTRY(logwatch_filter) logwatch_filters;
+};
+
+/**
+ * A channel for outputting logwatch output
+ */
+struct logwatch_chan {
+ /** The channel... */
+ struct irc_chan *chan;
+
+ /** Our entry in logwatch::channels */
+ TAILQ_ENTRY(logwatch_chan) logwatch_channels;
+};
+
+/**
+ * The logwatch module state
+ */
+struct logwatch {
+ /** The nexus we are loaded on */
+ struct nexus *nexus;
+
+ /** List of sources */
+ TAILQ_HEAD(logwatch_source_list, logwatch_source) sources;
+
+ /** List of filters */
+ TAILQ_HEAD(logwatch_filter_list, logwatch_filter) filters;
+
+ /** List of output channels */
+ TAILQ_HEAD(logwatch_chan_list, logwatch_chan) channels;
+};
+
+/**
+ * Add a new FIFO logwatch_source
+ *
+ * @param ctx the logwatch state
+ * @param path the path to the fifo
+ * @param err returned error info
+ * @return the new logwatch_source, or NULL on error
+ */
+struct logwatch_source* logwatch_open_fifo (struct logwatch *ctx, const char *path, struct error_info *err);
+
+/**
+ * Destroy a source, removing it from the list of sources.
+ *
+ * XXX: remove all affected filters as well?
+ */
+void logwatch_source_destroy (struct logwatch_source *source);
+
+/**
+ * Add a new output channel
+ */
+struct logwatch_chan* logwatch_add_chan (struct logwatch *ctx, struct irc_chan *chan);
+
+/**
+ * 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);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/logwatch_source.c Tue Apr 07 21:09:25 2009 +0300
@@ -0,0 +1,87 @@
+#include "logwatch.h"
+#include "../log.h"
+
+#include <stdlib.h>
+
+void logwatch_source_on_line (char *line, void *arg)
+{
+ struct logwatch_source *source = arg;
+
+ log_info("%s", line);
+}
+
+void logwatch_source_on_error (struct error_info *err, void *arg)
+{
+ struct logwatch_source *source = arg;
+
+ log_error("%s", error_msg(err));
+}
+
+static const struct line_proto_callbacks lp_callbacks = {
+ .on_line = logwatch_source_on_line,
+ .on_error = logwatch_source_on_error,
+};
+
+/**
+ * Initialize with the given sock
+ */
+err_t logwatch_source_init (struct logwatch_source *source, struct logwatch *ctx, struct sock_stream *stream, struct error_info *err)
+{
+ source->ctx = ctx;
+
+ // create the lp to wrap the sock
+ if (line_proto_create(&source->lp, stream, LOGWATCH_SOURCE_LINE_MAX, &lp_callbacks, source, err))
+ goto error;
+
+ // add to logwatch_sources
+ TAILQ_INSERT_TAIL(&ctx->sources, source, logwatch_sources);
+
+ // ok
+ return SUCCESS;
+
+error:
+ return ERROR_CODE(err);
+}
+
+struct logwatch_source* logwatch_open_fifo (struct logwatch *ctx, const char *path, struct error_info *err)
+{
+ struct logwatch_source *source;
+ struct sock_stream *stream = NULL;
+
+ // alloc
+ if ((source = calloc(1, sizeof(*source))) == NULL)
+ JUMP_SET_ERROR(err, ERR_CALLOC);
+
+ // open
+ if (fifo_open_read(&stream, path, err))
+ goto error;
+
+ // init
+ if (logwatch_source_init(source, ctx, stream, err))
+ goto error;
+
+ // ok
+ return source;
+
+error:
+ // cleanup
+ if (stream)
+ sock_stream_release(stream);
+
+ if (source)
+ free(source);
+
+ return NULL;
+}
+
+void logwatch_source_destroy (struct logwatch_source *source)
+{
+ // release the line_proto
+ if (source->lp)
+ line_proto_release(source->lp);
+
+ // remove from the list
+ TAILQ_REMOVE(&source->ctx->sources, source, logwatch_sources);
+
+ free(source);
+}