# HG changeset patch # User Tero Marttila # Date 1239545886 -10800 # Node ID f2ece471fb07dce829f0ed7b5c1540fc6688440d # Parent df949b399491541c07cbd9cd270e0d4d55c094a3 implement logwatch_source names, and logwatch_chan diff -r df949b399491 -r f2ece471fb07 TODO --- a/TODO Sat Apr 11 06:03:49 2009 +0300 +++ b/TODO Sun Apr 12 17:18:06 2009 +0300 @@ -9,11 +9,15 @@ * fix use of line_proto_send * more expansive tests +irc_cmd/chain: + * handle irc_cmd_remove from inside irc_cmd_invoke + irc_net: * reconnect, maybe cycling servers? config: - * An even more advanced structured value parser that can then handle config values for more things like the command line --options + * user-defined types + * return values irc_log: * recode to valid UTF8 diff -r df949b399491 -r f2ece471fb07 src/error.h --- a/src/error.h Sat Apr 11 06:03:49 2009 +0300 +++ b/src/error.h Sun Apr 12 17:18:06 2009 +0300 @@ -120,6 +120,7 @@ _ERR_GENERAL = 0xffff00, ERR_CMD_OPT, ERR_UNKNOWN, + ERR_DUP_NAME, }; diff -r df949b399491 -r f2ece471fb07 src/irc_cmd.h --- a/src/irc_cmd.h Sat Apr 11 06:03:49 2009 +0300 +++ b/src/irc_cmd.h Sun Apr 12 17:18:06 2009 +0300 @@ -5,6 +5,8 @@ * @file * * Command handlers callback lists for use with irc_line's + * + * XXX: irc_cmd_remove called from iniside irc_cmd_invoke? */ #include "irc_line.h" diff -r df949b399491 -r f2ece471fb07 src/modules/logwatch.c --- a/src/modules/logwatch.c Sat Apr 11 06:03:49 2009 +0300 +++ b/src/modules/logwatch.c Sun Apr 12 17:18:06 2009 +0300 @@ -3,6 +3,8 @@ #include "../config.h" #include "../log.h" +#include + static err_t logwatch_init (struct nexus *nexus, void **ctx_ptr, struct error_info *err) { struct logwatch *ctx; @@ -25,25 +27,90 @@ return SUCCESS; } -struct logwatch_chan* logwatch_add_chan (struct logwatch *ctx, struct irc_chan *chan, struct error_info *err) +/** + * Look for an existing logwatch_chan entry, returning it if it exists + */ +static struct logwatch_chan* logwatch_chan_lookup (struct logwatch *ctx, struct irc_chan *irc_chan) { - struct logwatch_chan *lw_chan; + struct logwatch_chan *chan; + // look for it + TAILQ_FOREACH(chan, &ctx->channels, logwatch_channels) + if (chan->irc_chan == irc_chan) + return chan; + + // not found + return NULL; +} + +/** + * Create a new irc_chan with an initial refcount of one + */ +static struct logwatch_chan* logwatch_chan_create (struct logwatch *ctx, struct irc_chan *irc_chan) +{ + struct logwatch_chan *chan; + // alloc - if ((lw_chan = calloc(1, sizeof(*lw_chan))) == NULL) - JUMP_SET_ERROR(err, ERR_CALLOC); + if ((chan = calloc(1, sizeof(*chan))) == NULL) + return NULL; // store - lw_chan->chan = chan; + chan->ctx = ctx; + chan->irc_chan = irc_chan; + chan->refcount = 1; - // add to list - TAILQ_INSERT_TAIL(&ctx->channels, lw_chan, logwatch_channels); + // add + TAILQ_INSERT_TAIL(&ctx->channels, chan, logwatch_channels); // ok - return lw_chan; + return chan; +} -error: - return NULL; +/** + * Destroy a logwatch_chan + */ +static void logwatch_chan_destroy (struct logwatch_chan *chan) +{ + // XXX: check refcount + assert(chan->refcount == 0); + + // remove + TAILQ_REMOVE(&chan->ctx->channels, chan, logwatch_channels); + + // release + free(chan); +} + +struct logwatch_chan* logwatch_get_chan (struct logwatch *ctx, struct irc_chan *irc_chan) +{ + struct logwatch_chan *chan; + + // existing? + if ((chan = logwatch_chan_lookup(ctx, irc_chan))) { + // get ref + chan->refcount++; + + } else { + // create a new one with a ref + // XXX: errors... + chan = logwatch_chan_create(ctx, irc_chan); + } + + // ok + return chan; +} + +void logwatch_put_chan (struct logwatch_chan *chan) +{ + // valid refcount + assert(chan->refcount); + + // still alive? + if (--chan->refcount) + return; + + // destroy + logwatch_chan_destroy(chan); } void logwatch_on_line (struct logwatch *ctx, const struct logwatch_source *source, const char *line) @@ -54,17 +121,28 @@ // apply each filter TAILQ_FOREACH(filter, &ctx->filters, logwatch_filters) { if (logwatch_filter_apply(filter, source, line, &err)) - log_warn("logwatch_filter_apply(%s, %p, %s): %s", filter->name, source, line, error_msg(&err)); + log_warn("logwatch_filter_apply(%s, %s, %s): %s", filter->name, source->name, line, error_msg(&err)); } } +void logwatch_on_error (struct logwatch *ctx, const struct logwatch_source *source, const struct error_info *err) +{ + struct logwatch_chan *chan; + struct logwatch_filter *filter; + + // notify each relevant channel +} + /** * 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) +static err_t logwatch_conf_source_fifo (void *_ctx, const struct config_option *option, const struct config_value values[], struct error_info *err) { struct logwatch *ctx = _ctx; + // parse arguments + const char *path = config_get_string(option, values, "path"); + // open it if (logwatch_open_fifo(ctx, path, err) == NULL) return ERROR_CODE(err); @@ -81,16 +159,25 @@ struct logwatch *ctx = _ctx; struct logwatch_filter *filter; - const struct logwatch_source *source; - const char *name, *pattern, *format; - struct irc_chan *chan; + const struct logwatch_source *source = NULL; + struct logwatch_chan *chan; + const char *name, *source_name, *pattern, *format; + struct irc_chan *irc_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" ); + name = config_get_string (option, values, "name" ); + source_name = config_get_string (option, values, "source" ); + pattern = config_get_string (option, values, "pattern" ); + format = config_get_string (option, values, "format" ); + irc_chan = config_get_irc_chan (option, values, "chan" ); + + // lookup name + if (source_name && (source = logwatch_source_lookup(ctx, source_name)) == NULL) + RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "unknown logwatch_source name"); + + // lookup the channel + if ((chan = logwatch_get_chan(ctx, irc_chan)) == NULL) + RETURN_SET_ERROR_STR(err, ERR_MODULE_CONF, "logwatch_get_chan failed"); // invoke if ((filter = logwatch_filter(ctx, name, source, pattern, format, chan, err)) == NULL) @@ -107,42 +194,40 @@ * Configuration options */ struct config_option logwatch_config_options[] = CONFIG_OPTIONS( - CONFIG_OPT_STRING( "source_fifo", logwatch_conf_source_fifo, "", "read lines from the fifo at the given path" ), + CONFIG_OPT( "source_fifo", logwatch_conf_source_fifo, + "read input lines from the FIFO at the given path", + + CONFIG_PARAM( "path", CONFIG_STRING, "filesystem path to FIFO", false ) + ), CONFIG_OPT( "filter", logwatch_conf_filter, "filter lines from source (or all), using the given regular expression (or all lines), and format output " "using the given format expression (or pass through directly), and finally send the output 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( "source", CONFIG_STRING, "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. - * - * 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_filter *filter; struct logwatch_source *source; + // flush the filters list + while ((filter = TAILQ_FIRST(&ctx->filters))) + logwatch_filter_destroy(filter); + // flush the sources list while ((source = TAILQ_FIRST(&ctx->sources))) logwatch_source_destroy(source); + + // release the context + free(ctx); } /** @@ -151,7 +236,7 @@ struct module_desc logwatch_module = { .init = logwatch_init, .config_options = logwatch_config_options, - .unload = NULL, // logwatch_unload, + .unload = NULL, .destroy = logwatch_destroy }; diff -r df949b399491 -r f2ece471fb07 src/modules/logwatch.h --- a/src/modules/logwatch.h Sat Apr 11 06:03:49 2009 +0300 +++ b/src/modules/logwatch.h Sun Apr 12 17:18:06 2009 +0300 @@ -20,6 +20,9 @@ /** The logwatch context we are registered to */ struct logwatch *ctx; + /** Our name */ + char *name; + /** The input FIFO */ struct line_proto *lp; @@ -33,6 +36,23 @@ #define LOGWATCH_SOURCE_LINE_MAX 1024 /** + * Logwatch's per-channel state + */ +struct logwatch_chan { + /** The logwatch context we are registered to */ + struct logwatch *ctx; + + /** The actual irc_chan */ + struct irc_chan *irc_chan; + + /** Number of references */ + size_t refcount; + + /** Our entry in logwatch::channels */ + TAILQ_ENTRY(logwatch_chan) logwatch_channels; +}; + +/** * A filter specifies what lines to match, and how to then format the output. */ struct logwatch_filter { @@ -58,7 +78,7 @@ /** * The channel to send output to */ - struct irc_chan *chan; + struct logwatch_chan *chan; /** Our entry in logwatch::filters */ TAILQ_ENTRY(logwatch_filter) logwatch_filters; @@ -75,19 +95,6 @@ #define LOGWATCH_FILTER_OUT_MAX 450 /** - * A channel for outputting logwatch output - * - * XXX; do we need this? - */ -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 { @@ -100,7 +107,7 @@ /** List of filters */ TAILQ_HEAD(logwatch_filter_list, logwatch_filter) filters; - /** List of output channels */ + /** List of chanenls */ TAILQ_HEAD(logwatch_chan_list, logwatch_chan) channels; }; @@ -108,7 +115,7 @@ * Add a new FIFO logwatch_source * * @param ctx the logwatch state - * @param path the path to the fifo + * @param path the path to the fifo, also used as the name * @param err returned error info * @return the new logwatch_source, or NULL on error */ @@ -117,22 +124,35 @@ /** * Destroy a source, removing it from the list of sources. * - * XXX: remove all affected filters as well? + * XXX: remove all affected filters as well */ void logwatch_source_destroy (struct logwatch_source *source); /** - * Add a new output channel + * Lookup a logwatch_source by name + */ +const struct logwatch_source* logwatch_source_lookup (struct logwatch *ctx, const char *name); + +/** + * Find an existing logwatch_chan for the given channel, or create a new one. Returns a real reference that should be + * returned using logwatch_put_chan(). * - * XXX; do we need this? + * @returns NULL on ERR_CALLOC */ -struct logwatch_chan* logwatch_add_chan (struct logwatch *ctx, struct irc_chan *chan, struct error_info *err); +struct logwatch_chan* logwatch_get_chan (struct logwatch *ctx, struct irc_chan *irc_chan); + +/** + * Returns a reference aquired using logwatch_get_chan(). + */ +void logwatch_put_chan (struct logwatch_chan *chan); /** * Add a new filter. + * + * The given logwatch_chan should be a new reference. */ 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); + const char *pattern, const char *format, struct logwatch_chan *chan, struct error_info *err); /** * Destroy a logwatch_filter, unregistering it @@ -145,7 +165,16 @@ err_t logwatch_filter_apply (const struct logwatch_filter *filter, const struct logwatch_source *source, const char *line, struct error_info *err); /** - * Handle a line from the given source by applying it to all filters + * Remove any filters registered with the given source + */ +void logwatch_filter_remove (struct logwatch *ctx, const struct logwatch_source *source); + +/** + * Handle a line from the given source by applying it to all filters. */ void logwatch_on_line (struct logwatch *ctx, const struct logwatch_source *source, const char *line); +/** + * Handle a disasterous error on a logwatch_source by notifying any irc_chan's that it is linked to via our filters. + */ +void logwatch_on_error (struct logwatch *ctx, const struct logwatch_source *source, const struct error_info *err); diff -r df949b399491 -r f2ece471fb07 src/modules/logwatch_filter.c --- a/src/modules/logwatch_filter.c Sat Apr 11 06:03:49 2009 +0300 +++ b/src/modules/logwatch_filter.c Sun Apr 12 17:18:06 2009 +0300 @@ -8,7 +8,7 @@ #include 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) + const char *pattern, const char *format, struct logwatch_chan *chan, struct error_info *err) { struct logwatch_filter *filter; const char *err_msg; @@ -39,6 +39,8 @@ // add it TAILQ_INSERT_TAIL(&ctx->filters, filter, logwatch_filters); + + // mark it as registered filter->ctx = ctx; // ok @@ -54,16 +56,37 @@ void logwatch_filter_destroy (struct logwatch_filter *filter) { + // remove it if it's registered if (filter->ctx) - // remove it TAILQ_REMOVE(&filter->ctx->filters, filter, logwatch_filters); + + // this if is probably not needed + if (filter->regexp) + pcre_free(filter->regexp); + + // release the logwatch_chan ref + logwatch_put_chan(filter->chan); + // free misc free(filter->format); - if (filter->regexp) pcre_free(filter->regexp); free(filter->name); free(filter); } +void logwatch_filter_remove (struct logwatch *ctx, const struct logwatch_source *source) +{ + struct logwatch_filter *filter, *next; + + // inspect each filter + for (filter = TAILQ_FIRST(&ctx->filters); filter; filter = next) { + next = TAILQ_NEXT(filter, logwatch_filters); + + // destroy matching + if (filter->source == source) + logwatch_filter_destroy(filter); + } +} + /** * str_format context for logwatch_filter_apply operation */ @@ -81,6 +104,9 @@ size_t group_count; }; +/** + * Our callback for str_format params used by logwatch_filter_apply() + */ static err_t logwatch_filter_str_format_cb (const char *name, const char **value, ssize_t *value_len, void *arg) { struct logwatch_filter_str_format_ctx *ctx = arg; @@ -161,10 +187,10 @@ buf_ptr += str_advance(NULL, &buf_size, str_quote(buf_ptr, buf_size, line, -1)); } - log_info("%s:%p -> %s:%s", line, source, irc_chan_name(filter->chan), buf); + log_info("<%s>:%s -> %s:%s", source->name, line, irc_chan_name(filter->chan->irc_chan), buf); // then send it as a notice - if ((ERROR_CODE(err) = irc_chan_NOTICE(filter->chan, buf))) + if ((ERROR_CODE(err) = irc_chan_NOTICE(filter->chan->irc_chan, buf))) goto error; // ok diff -r df949b399491 -r f2ece471fb07 src/modules/logwatch_source.c --- a/src/modules/logwatch_source.c Sat Apr 11 06:03:49 2009 +0300 +++ b/src/modules/logwatch_source.c Sun Apr 12 17:18:06 2009 +0300 @@ -2,6 +2,7 @@ #include "../log.h" #include +#include void logwatch_source_on_line (char *line, void *arg) { @@ -19,6 +20,9 @@ // XXX: complain more loudly log_error("%s", error_msg(err)); + + // drop it + logwatch_source_destroy(source); } static const struct line_proto_callbacks lp_callbacks = { @@ -26,14 +30,35 @@ .on_error = logwatch_source_on_error, }; +const struct logwatch_source* logwatch_source_lookup (struct logwatch *ctx, const char *name) +{ + const struct logwatch_source *source; + + // compare + TAILQ_FOREACH(source, &ctx->sources, logwatch_sources) + if (strcmp(source->name, name) == 0) + return source; + + // not found + return NULL; +} + /** * 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) +err_t logwatch_source_init (struct logwatch_source *source, struct logwatch *ctx, const char *name, struct sock_stream *stream, struct error_info *err) { + // duplicate name? + if (logwatch_source_lookup(ctx, name)) + return SET_ERROR(err, ERR_DUP_NAME); + // store source->ctx = ctx; + // the name + if ((source->name = strdup(name)) == NULL) + return SET_ERROR(err, ERR_STRDUP); + // create the lp to wrap the sock if (line_proto_create(&source->lp, stream, LOGWATCH_SOURCE_LINE_MAX, &lp_callbacks, source, err)) goto error; @@ -62,7 +87,7 @@ goto error; // init - if (logwatch_source_init(source, ctx, stream, err)) + if (logwatch_source_init(source, ctx, path, stream, err)) goto error; // ok @@ -88,5 +113,10 @@ // remove from the list TAILQ_REMOVE(&source->ctx->sources, source, logwatch_sources); + // remove any affected filters + logwatch_filter_remove(source->ctx, source); + + // release + free(source->name); free(source); } diff -r df949b399491 -r f2ece471fb07 src/str.c --- a/src/str.c Sat Apr 11 06:03:49 2009 +0300 +++ b/src/str.c Sun Apr 12 17:18:06 2009 +0300 @@ -245,7 +245,6 @@ *name_ptr = *flags_ptr = '\0'; break; - case '}': // syntax @@ -280,13 +279,13 @@ if (!flags_size) return ERR_STR_FMT_FLAGS_LEN; - } else if (in_param) { // add to param name name_ptr += str_advance(NULL, &name_size, str_append_char(name_ptr, name_size, *format)); if (!name_size) return ERR_STR_FMT_NAME_LEN; + } else { // add to output buf += str_advance(NULL, &buf_size, str_append_char(buf, buf_size, *format));