# HG changeset patch # User Tero Marttila # Date 1239127765 -10800 # Node ID 64f50072db9e420610cc9a31b6dfd0d34a2cb5bf # Parent 05b8d51503137b62390f5fbbe103393d1debbde5 add logwatch module, that can already open FIFOs diff -r 05b8d5150313 -r 64f50072db9e src/CMakeLists.txt --- 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" ) diff -r 05b8d5150313 -r 64f50072db9e src/module.c --- 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 diff -r 05b8d5150313 -r 64f50072db9e src/module.h --- 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() diff -r 05b8d5150313 -r 64f50072db9e src/modules/logwatch.c --- /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, "", "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 +}; + diff -r 05b8d5150313 -r 64f50072db9e src/modules/logwatch.h --- /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 +#include "../irc_chan.h" +#include "../sock.h" +#include "../line_proto.h" + +#include +#include + +/** + * 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); + diff -r 05b8d5150313 -r 64f50072db9e src/modules/logwatch_source.c --- /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 + +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); +}