--- 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
--- 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,
};
--- 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"
--- 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 <assert.h>
+
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, "<path>", "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
};
--- 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);
--- 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 <assert.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)
+ 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
--- 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 <stdlib.h>
+#include <string.h>
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);
}
--- 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));