Code

match_regex plugin: Renamed `filter_pcre' to `match_regex'.
authorFlorian Forster <octo@huhu.verplant.org>
Fri, 21 Nov 2008 22:14:42 +0000 (23:14 +0100)
committerFlorian Forster <octo@huhu.verplant.org>
Fri, 21 Nov 2008 22:14:42 +0000 (23:14 +0100)
In order to fit into the new match/target schema, the substitute part of the
plugin has been removed for now and will be put in a target plugin in the
future.

The match_regex now registeres a match with the new infrastructure and uses
regular expressions to match certain values based on their identifier.

configure.in
src/Makefile.am
src/filter_pcre.c [deleted file]
src/match_regex.c [new file with mode: 0644]

index 21af0b5453c0eca539656628471e261fc50abb12..0d1bd2588a82f954e6788a6f891b2bc41d3eafd3 100644 (file)
@@ -2945,7 +2945,6 @@ AC_PLUGIN([entropy],     [$plugin_entropy],    [Entropy statistics])
 AC_PLUGIN([exec],        [yes],                [Execution of external programs])
 AC_PLUGIN([filecount],   [yes],                [Count files in directories])
 AC_PLUGIN([filter_ignore], [yes],                [Ignore specific values])
-AC_PLUGIN([filter_pcre], [$with_libpcre],      [Filter based on PCRE])
 AC_PLUGIN([hddtemp],     [yes],                [Query hddtempd])
 AC_PLUGIN([interface],   [$plugin_interface],  [Interface traffic statistics])
 AC_PLUGIN([iptables],    [$with_libiptc],      [IPTables rule counters])
@@ -2955,6 +2954,7 @@ AC_PLUGIN([irq],         [$plugin_irq],        [IRQ statistics])
 AC_PLUGIN([libvirt],     [$plugin_libvirt],    [Virtual machine statistics])
 AC_PLUGIN([load],        [$plugin_load],       [System load])
 AC_PLUGIN([logfile],     [yes],                [File logging plugin])
+AC_PLUGIN([match_regex], [yes],                [The regex match])
 AC_PLUGIN([mbmon],       [yes],                [Query mbmond])
 AC_PLUGIN([memcached],   [yes],                [memcached statistics])
 AC_PLUGIN([memory],      [$plugin_memory],     [Memory usage])
@@ -3120,7 +3120,6 @@ Configuration:
     exec  . . . . . . . . $enable_exec
     filecount . . . . . . $enable_filecount
     filter_ignore . . . . $enable_filter_ignore
-    filter_pcre . . . . . $enable_filter_pcre
     hddtemp . . . . . . . $enable_hddtemp
     interface . . . . . . $enable_interface
     iptables  . . . . . . $enable_iptables
@@ -3130,6 +3129,7 @@ Configuration:
     libvirt . . . . . . . $enable_libvirt
     load  . . . . . . . . $enable_load
     logfile . . . . . . . $enable_logfile
+    match_regex . . . . . $enable_match_regex
     mbmon . . . . . . . . $enable_mbmon
     memcached . . . . . . $enable_memcached
     memory  . . . . . . . $enable_memory
index 960dfe4da2a688add1eeca7a84f847ce57cb3a5c..24f06fdbb7e7f1f9ea4b6a120122e31098569544 100644 (file)
@@ -284,16 +284,6 @@ collectd_LDADD += "-dlopen" filter_ignore.la
 collectd_DEPENDENCIES += filter_ignore.la
 endif
 
-if BUILD_PLUGIN_FILTER_PCRE
-pkglib_LTLIBRARIES += filter_pcre.la
-filter_pcre_la_SOURCES = filter_pcre.c
-filter_pcre_la_CPPFLAGS = $(BUILD_WITH_LIBPCRE_CFLAGS)
-filter_pcre_la_LDFLAGS = -module -avoid-version \
-               $(BUILD_WITH_LIBPCRE_LIBS)
-collectd_LDADD += "-dlopen" filter_pcre.la
-collectd_DEPENDENCIES += filter_pcre.la
-endif
-
 if BUILD_PLUGIN_HDDTEMP
 pkglib_LTLIBRARIES += hddtemp.la
 hddtemp_la_SOURCES = hddtemp.c
@@ -400,6 +390,16 @@ collectd_LDADD += "-dlopen" logfile.la
 collectd_DEPENDENCIES += logfile.la
 endif
 
+if BUILD_PLUGIN_MATCH_REGEX
+pkglib_LTLIBRARIES += match_regex.la
+match_regex_la_SOURCES = match_regex.c
+match_regex_la_CPPFLAGS = $(BUILD_WITH_LIBPCRE_CFLAGS)
+match_regex_la_LDFLAGS = -module -avoid-version \
+               $(BUILD_WITH_LIBPCRE_LIBS)
+collectd_LDADD += "-dlopen" match_regex.la
+collectd_DEPENDENCIES += match_regex.la
+endif
+
 if BUILD_PLUGIN_MBMON
 pkglib_LTLIBRARIES += mbmon.la
 mbmon_la_SOURCES = mbmon.c
diff --git a/src/filter_pcre.c b/src/filter_pcre.c
deleted file mode 100644 (file)
index 3b1afbf..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-/**
- * collectd - src/filter_pcre.c
- * Copyright (C) 2008  Sebastian Harl
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; only version 2 of the License is applicable.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
- *
- * Author:
- *   Sebastian Harl <sh at tokkee.org>
- **/
-
-/*
- * This module allows to filter and rewrite value lists based on
- * Perl-compatible regular expressions.
- */
-
-#include "collectd.h"
-#include "configfile.h"
-#include "plugin.h"
-#include "common.h"
-
-#include "utils_subst.h"
-
-#include <pcre.h>
-
-#define log_err(...) ERROR ("filter_pcre: " __VA_ARGS__)
-#define log_warn(...) WARNING ("filter_pcre: " __VA_ARGS__)
-
-/*
- * private data types
- */
-
-typedef struct {
-       /* regular expression */
-       pcre       *re;
-       const char *re_str;
-
-       /* extra information from studying the pattern */
-       pcre_extra *extra;
-
-       /* replacment text for string substitution */
-       const char *replacement;
-} c_pcre_t;
-
-#define C_PCRE_INIT(regex) do { \
-               (regex).re     = NULL; \
-               (regex).re_str = NULL; \
-               (regex).extra  = NULL; \
-               (regex).replacement = NULL; \
-       } while (0)
-
-#define C_PCRE_FREE(regex) do { \
-               pcre_free ((regex).re); \
-               free ((void *)(regex).re_str); \
-               pcre_free ((regex).extra); \
-               free ((void *)(regex).replacement); \
-               C_PCRE_INIT (regex); \
-       } while (0)
-
-typedef struct {
-       c_pcre_t host;
-       c_pcre_t plugin;
-       c_pcre_t plugin_instance;
-       c_pcre_t type;
-       c_pcre_t type_instance;
-
-       int action;
-} regex_t;
-
-typedef struct {
-       int vec[30];
-       int status;
-} ovec_t;
-
-typedef struct {
-       ovec_t host;
-       ovec_t plugin;
-       ovec_t plugin_instance;
-       ovec_t type;
-       ovec_t type_instance;
-} ovectors_t;
-
-/*
- * private variables
- */
-
-static regex_t *regexes     = NULL;
-static int      regexes_num = 0;
-
-/*
- * internal helper functions
- */
-
-/* returns true if string matches the regular expression */
-static int c_pcre_match (c_pcre_t *re, const char *string, ovec_t *ovec)
-{
-       if ((NULL == re) || (NULL == re->re))
-               return 1;
-
-       if (NULL == string)
-               string = "";
-
-       ovec->status = pcre_exec (re->re,
-                       /* extra       = */ re->extra,
-                       /* subject     = */ string,
-                       /* length      = */ strlen (string),
-                       /* startoffset = */ 0,
-                       /* options     = */ 0,
-                       /* ovector     = */ ovec->vec,
-                       /* ovecsize    = */ STATIC_ARRAY_SIZE (ovec->vec));
-
-       if (0 <= ovec->status)
-               return 1;
-
-       if (PCRE_ERROR_NOMATCH != ovec->status)
-               log_err ("PCRE matching of string \"%s\" failed with status %d",
-                               string, ovec->status);
-       return 0;
-} /* c_pcre_match */
-
-static int c_pcre_subst (c_pcre_t *re, char *string, size_t strlen,
-               ovec_t *ovec)
-{
-       char buffer[strlen];
-
-       if ((NULL == re) || (NULL == re->replacement))
-               return 0;
-
-       assert (0 <= ovec->status);
-
-       if (NULL == subst (buffer, sizeof (buffer), string,
-                               ovec->vec[0], ovec->vec[1], re->replacement)) {
-               log_err ("Substitution in string \"%s\" (using regex \"%s\" and "
-                               "replacement string \"%s\") failed.",
-                               string, re->re_str, re->replacement);
-               return -1;
-       }
-
-       sstrncpy (string, buffer, strlen);
-       return 0;
-} /* c_pcre_subst */
-
-static regex_t *regex_new (void)
-{
-       regex_t *re;
-       regex_t *temp;
-
-       temp = (regex_t *) realloc (regexes, (regexes_num + 1)
-                       * sizeof (*regexes));
-       if (NULL == temp) {
-               log_err ("Out of memory.");
-               return NULL;
-       }
-       regexes = temp;
-       regexes_num++;
-
-       re = regexes + (regexes_num - 1);
-
-       C_PCRE_INIT (re->host);
-       C_PCRE_INIT (re->plugin);
-       C_PCRE_INIT (re->plugin_instance);
-       C_PCRE_INIT (re->type);
-       C_PCRE_INIT (re->type_instance);
-
-       re->action = 0;
-       return re;
-} /* regex_new */
-
-static void regex_delete (regex_t *re)
-{
-       if (NULL == re)
-               return;
-
-       C_PCRE_FREE (re->host);
-       C_PCRE_FREE (re->plugin);
-       C_PCRE_FREE (re->plugin_instance);
-       C_PCRE_FREE (re->type);
-       C_PCRE_FREE (re->type_instance);
-
-       re->action = 0;
-} /* regex_delete */
-
-/* returns true if the value list matches the regular expression */
-static int regex_match (regex_t *re, value_list_t *vl, ovectors_t *ovectors)
-{
-       int matches = 0;
-
-       if (NULL == re)
-               return 1;
-
-       if (c_pcre_match (&re->host, vl->host, &ovectors->host))
-               ++matches;
-
-       if (c_pcre_match (&re->plugin, vl->plugin, &ovectors->plugin))
-               ++matches;
-
-       if (c_pcre_match (&re->plugin_instance, vl->plugin_instance,
-                               &ovectors->plugin_instance))
-               ++matches;
-
-       if (c_pcre_match (&re->type, vl->type, &ovectors->type))
-               ++matches;
-
-       if (c_pcre_match (&re->type_instance, vl->type_instance,
-                               &ovectors->type_instance))
-               ++matches;
-
-       if (5 == matches)
-               return 1;
-       return 0;
-} /* regex_match */
-
-static int regex_subst (regex_t *re, value_list_t *vl, ovectors_t *ovectors)
-{
-       if (NULL == re)
-               return 0;
-
-       c_pcre_subst (&re->host, vl->host, sizeof (vl->host),
-                       &ovectors->host);
-       c_pcre_subst (&re->plugin, vl->plugin, sizeof (vl->plugin),
-                       &ovectors->plugin);
-       c_pcre_subst (&re->plugin_instance, vl->plugin_instance,
-                       sizeof (vl->plugin_instance), &ovectors->plugin_instance);
-       c_pcre_subst (&re->type, vl->type, sizeof (vl->type),
-                       &ovectors->type);
-       c_pcre_subst (&re->type_instance, vl->type_instance,
-                       sizeof (vl->type_instance), &ovectors->type_instance);
-       return 0;
-} /* regex_subst */
-
-/*
- * interface to collectd
- */
-
-static int c_pcre_filter (const data_set_t *ds, value_list_t *vl)
-{
-       int i;
-
-       ovectors_t ovectors;
-
-       for (i = 0; i < regexes_num; ++i)
-               if (regex_match (regexes + i, vl, &ovectors)) {
-                       regex_subst (regexes + i, vl, &ovectors);
-                       return regexes[i].action;
-               }
-       return 0;
-} /* c_pcre_filter */
-
-static int c_pcre_shutdown (void)
-{
-       int i;
-
-       plugin_unregister_filter ("filter_pcre");
-       plugin_unregister_shutdown ("filter_pcre");
-
-       for (i = 0; i < regexes_num; ++i)
-               regex_delete (regexes + i);
-
-       sfree (regexes);
-       regexes_num = 0;
-       return 0;
-} /* c_pcre_shutdown */
-
-static int config_set_regex (c_pcre_t *re, oconfig_item_t *ci)
-{
-       const char *pattern;
-       const char *errptr;
-       int erroffset;
-
-       if ((0 != ci->children_num) || (1 != ci->values_num)
-                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
-               log_err ("<RegEx>: %s expects a single string argument.", ci->key);
-               return 1;
-       }
-
-       pattern = ci->values[0].value.string;
-
-       re->re = pcre_compile (pattern,
-                       /* options   = */ 0,
-                       /* errptr    = */ &errptr,
-                       /* erroffset = */ &erroffset,
-                       /* tableptr  = */ NULL);
-
-       if (NULL == re->re) {
-               log_err ("<RegEx>: PCRE compilation of pattern \"%s\" failed "
-                               "at offset %d: %s", pattern, erroffset, errptr);
-               return 1;
-       }
-
-       re->re_str = sstrdup (pattern);
-
-       re->extra = pcre_study (re->re,
-                       /* options = */ 0,
-                       /* errptr  = */ &errptr);
-
-       if (NULL != errptr) {
-               log_err ("<RegEx>: PCRE studying of pattern \"%s\" failed: %s",
-                               pattern, errptr);
-               return 1;
-       }
-       return 0;
-} /* config_set_regex */
-
-static int config_set_replacement (c_pcre_t *re, oconfig_item_t *ci)
-{
-       if ((0 != ci->children_num) || (1 != ci->values_num)
-                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
-               log_err ("<RegEx>: %s expects a single string argument.", ci->key);
-               return 1;
-       }
-
-       if (NULL == re->re) {
-               log_err ("<RegEx>: %s without an appropriate regex (%s) "
-                               "is not allowed.", ci->key, ci->key + strlen ("Substitute"));
-               return 1;
-       }
-
-       re->replacement = sstrdup (ci->values[0].value.string);
-       return 0;
-} /* config_set_replacement */
-
-static int config_set_action (int *action, oconfig_item_t *ci)
-{
-       const char *action_str;
-
-       if ((0 != ci->children_num) || (1 != ci->values_num)
-                       || (OCONFIG_TYPE_STRING != ci->values[0].type)) {
-               log_err ("<RegEx>: Action expects a single string argument.");
-               return 1;
-       }
-
-       action_str = ci->values[0].value.string;
-
-       if (0 == strcasecmp (action_str, "NoWrite"))
-               *action |= FILTER_NOWRITE;
-       else if (0 == strcasecmp (action_str, "NoThresholdCheck"))
-               *action |= FILTER_NOTHRESHOLD_CHECK;
-       else if (0 == strcasecmp (action_str, "Ignore"))
-               *action |= FILTER_IGNORE;
-       else
-               log_warn ("<Regex>: Ignoring unknown action \"%s\".", action_str);
-       return 0;
-} /* config_set_action */
-
-static int c_pcre_config_regex (oconfig_item_t *ci)
-{
-       regex_t *re;
-       int i;
-
-       if (0 != ci->values_num) {
-               log_err ("<RegEx> expects no arguments.");
-               return 1;
-       }
-
-       re = regex_new ();
-       if (NULL == re)
-               return -1;
-
-       for (i = 0; i < ci->children_num; ++i) {
-               oconfig_item_t *c = ci->children + i;
-               int status = 0;
-
-               if (0 == strcasecmp (c->key, "Host"))
-                       status = config_set_regex (&re->host, c);
-               else if (0 == strcasecmp (c->key, "Plugin"))
-                       status = config_set_regex (&re->plugin, c);
-               else if (0 == strcasecmp (c->key, "PluginInstance"))
-                       status = config_set_regex (&re->plugin_instance, c);
-               else if (0 == strcasecmp (c->key, "Type"))
-                       status = config_set_regex (&re->type, c);
-               else if (0 == strcasecmp (c->key, "TypeInstance"))
-                       status = config_set_regex (&re->type_instance, c);
-               else if (0 == strcasecmp (c->key, "Action"))
-                       status = config_set_action (&re->action, c);
-               else if (0 == strcasecmp (c->key, "SubstituteHost"))
-                       status = config_set_replacement (&re->host, c);
-               else if (0 == strcasecmp (c->key, "SubstitutePlugin"))
-                       status = config_set_replacement (&re->plugin, c);
-               else if (0 == strcasecmp (c->key, "SubstitutePluginInstance"))
-                       status = config_set_replacement (&re->plugin_instance, c);
-               else if (0 == strcasecmp (c->key, "SubstituteType"))
-                       status = config_set_replacement (&re->type, c);
-               else if (0 == strcasecmp (c->key, "SubstituteTypeInstance"))
-                       status = config_set_replacement (&re->type_instance, c);
-               else
-                       log_warn ("<RegEx>: Ignoring unknown config key \"%s\".", c->key);
-
-               if (0 != status) {
-                       log_err ("Ignoring regular expression definition.");
-                       regex_delete (re);
-                       --regexes_num;
-               }
-       }
-       return 0;
-} /* c_pcre_config_regex */
-
-static int c_pcre_config (oconfig_item_t *ci)
-{
-       int i;
-
-       for (i = 0; i < ci->children_num; ++i) {
-               oconfig_item_t *c = ci->children + i;
-
-               if (0 == strcasecmp (c->key, "RegEx"))
-                       c_pcre_config_regex (c);
-               else
-                       log_warn ("Ignoring unknown config key \"%s\".", c->key);
-       }
-
-       plugin_register_filter ("filter_pcre", c_pcre_filter);
-       plugin_register_shutdown ("filter_pcre", c_pcre_shutdown);
-       return 0;
-} /* c_pcre_config */
-
-void module_register (void)
-{
-       plugin_register_complex_config ("filter_pcre", c_pcre_config);
-} /* module_register */
-
-/* vim: set sw=4 ts=4 tw=78 noexpandtab : */
-
diff --git a/src/match_regex.c b/src/match_regex.c
new file mode 100644 (file)
index 0000000..4353b3a
--- /dev/null
@@ -0,0 +1,287 @@
+/**
+ * collectd - src/match_regex.c
+ * Copyright (C) 2008  Sebastian Harl
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Sebastian Harl <sh at tokkee.org>
+ *   Florian Forster <octo at verplant.org>
+ **/
+
+/*
+ * This module allows to filter and rewrite value lists based on
+ * Perl-compatible regular expressions.
+ */
+
+#include "collectd.h"
+#include "filter_chain.h"
+
+#include <sys/types.h>
+#include <regex.h>
+
+#define log_err(...) ERROR ("`regex' match: " __VA_ARGS__)
+#define log_warn(...) WARNING ("`regex' match: " __VA_ARGS__)
+
+/*
+ * private data types
+ */
+
+struct mr_regex_s;
+typedef struct mr_regex_s mr_regex_t;
+struct mr_regex_s
+{
+       regex_t re;
+       char *re_str;
+
+       mr_regex_t *next;
+};
+
+struct mr_match_s;
+typedef struct mr_match_s mr_match_t;
+struct mr_match_s
+{
+       mr_regex_t *host;
+       mr_regex_t *plugin;
+       mr_regex_t *plugin_instance;
+       mr_regex_t *type;
+       mr_regex_t *type_instance;
+};
+
+/*
+ * internal helper functions
+ */
+static void mr_free_regex (mr_regex_t *r) /* {{{ */
+{
+       if (r == NULL)
+               return;
+
+       regfree (&r->re);
+       memset (&r->re, 0, sizeof (r->re));
+       free (r->re_str);
+
+       if (r->next != NULL)
+               mr_free_regex (r->next);
+} /* }}} void mr_free_regex */
+
+static void mr_free_match (mr_match_t *m) /* {{{ */
+{
+       if (m == NULL)
+               return;
+
+       mr_free_regex (m->host);
+       mr_free_regex (m->plugin);
+       mr_free_regex (m->plugin_instance);
+       mr_free_regex (m->type);
+       mr_free_regex (m->type_instance);
+
+       free (m);
+} /* }}} void mr_free_match */
+
+static int mr_match_regexen (mr_regex_t *re_head, /* {{{ */
+               const char *string)
+{
+       mr_regex_t *re;
+
+       if (re_head == NULL)
+               return (FC_MATCH_MATCHES);
+
+       for (re = re_head; re != NULL; re = re->next)
+       {
+               int status;
+
+               status = regexec (&re->re, string,
+                               /* nmatch = */ 0, /* pmatch = */ NULL,
+                               /* eflags = */ 0);
+               if (status == 0)
+                       return (FC_MATCH_MATCHES);
+       }
+
+       return (FC_MATCH_NO_MATCH);
+} /* }}} int mr_match_regexen */
+
+static int mr_config_add_regex (mr_regex_t **re_head, /* {{{ */
+               oconfig_item_t *ci)
+{
+       mr_regex_t *re;
+       int status;
+
+       if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+       {
+               log_warn ("`%s' needs exactly one string argument.", ci->key);
+               return (-1);
+       }
+
+       re = (mr_regex_t *) malloc (sizeof (*re));
+       if (re == NULL)
+       {
+               log_err ("mr_config_add_regex: malloc failed.");
+               return (-1);
+       }
+       memset (re, 0, sizeof (*re));
+       re->next = NULL;
+
+       re->re_str = strdup (ci->values[0].value.string);
+       if (re->re_str)
+       {
+               free (re);
+               log_err ("mr_config_add_regex: strdup failed.");
+               return (-1);
+       }
+
+       status = regcomp (&re->re, re->re_str, REG_EXTENDED | REG_NOSUB);
+       if (status != 0)
+       {
+               char errmsg[1024];
+               regerror (status, &re->re, errmsg, sizeof (errmsg));
+               errmsg[sizeof (errmsg) - 1] = 0;
+               log_err ("Compiling regex `%s' for `%s' failed: %s.", 
+                               re->re_str, ci->key, errmsg);
+               free (re->re_str);
+               free (re);
+               return (-1);
+       }
+
+       if (*re_head == NULL)
+       {
+               *re_head = re;
+       }
+       else
+       {
+               mr_regex_t *ptr;
+
+               ptr = *re_head;
+               while (ptr->next != NULL)
+                       ptr = ptr->next;
+
+               ptr->next = re;
+       }
+
+       return (0);
+} /* }}} int mr_config_add_regex */
+
+static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
+{
+       mr_match_t *m;
+       int status;
+       int i;
+
+       m = (mr_match_t *) malloc (sizeof (*m));
+       if (m == NULL)
+       {
+               log_err ("mr_create: malloc failed.");
+               return (-ENOMEM);
+       }
+       memset (m, 0, sizeof (*m));
+
+       status = 0;
+       for (i = 0; i < ci->children_num; i++)
+       {
+               oconfig_item_t *child = ci->children + i;
+
+               if ((strcasecmp ("Host", child->key) == 0)
+                               || (strcasecmp ("Hostname", child->key) == 0))
+                       status = mr_config_add_regex (&m->host, child);
+               else if (strcasecmp ("Plugin", child->key) == 0)
+                       status = mr_config_add_regex (&m->plugin, child);
+               else if (strcasecmp ("PluginInstance", child->key) == 0)
+                       status = mr_config_add_regex (&m->plugin_instance, child);
+               else if (strcasecmp ("Type", child->key) == 0)
+                       status = mr_config_add_regex (&m->type, child);
+               else if (strcasecmp ("TypeInstance", child->key) == 0)
+                       status = mr_config_add_regex (&m->type_instance, child);
+               else
+               {
+                       log_err ("The `%s' configuration option is not understood and "
+                                       "will be ignored.", child->key);
+                       status = 0;
+               }
+
+               if (status != 0)
+                       break;
+       }
+
+       /* Additional sanity-checking */
+       while (status == 0)
+       {
+               if ((m->host == NULL)
+                               && (m->plugin == NULL)
+                               && (m->plugin_instance == NULL)
+                               && (m->type == NULL)
+                               && (m->type_instance == NULL))
+               {
+                       log_err ("No (valid) regular expressions have been configured. "
+                                       "This match will be ignored.");
+                       status = -1;
+               }
+
+               break;
+       }
+
+       if (status != 0)
+       {
+               mr_free_match (m);
+               return (status);
+       }
+
+       *user_data = m;
+       return (0);
+} /* }}} int mr_create */
+
+static int mr_destroy (void **user_data) /* {{{ */
+{
+       if ((user_data != NULL) && (*user_data != NULL))
+               mr_free_match (*user_data);
+       return (0);
+} /* }}} int mr_destroy */
+
+static int mr_match (const data_set_t *ds, const value_list_t *vl, /* {{{ */
+               notification_meta_t **meta, void **user_data)
+{
+       mr_match_t *m;
+
+       if ((user_data == NULL) || (*user_data == NULL))
+               return (-1);
+
+       m = *user_data;
+
+       if (mr_match_regexen (m->host, vl->host) == FC_MATCH_NO_MATCH)
+               return (FC_MATCH_NO_MATCH);
+       if (mr_match_regexen (m->plugin, vl->plugin) == FC_MATCH_NO_MATCH)
+               return (FC_MATCH_NO_MATCH);
+       if (mr_match_regexen (m->plugin_instance,
+                               vl->plugin_instance) == FC_MATCH_NO_MATCH)
+               return (FC_MATCH_NO_MATCH);
+       if (mr_match_regexen (m->type, vl->type) == FC_MATCH_NO_MATCH)
+               return (FC_MATCH_NO_MATCH);
+       if (mr_match_regexen (m->type_instance,
+                               vl->type_instance) == FC_MATCH_NO_MATCH)
+               return (FC_MATCH_NO_MATCH);
+
+       return (FC_MATCH_MATCHES);
+} /* }}} int mr_match */
+
+void module_register (void)
+{
+       match_proc_t mproc;
+
+       memset (&mproc, 0, sizeof (mproc));
+       mproc.create  = mr_create;
+       mproc.destroy = mr_destroy;
+       mproc.match   = mr_match;
+       fc_register_match ("regex", mproc);
+} /* module_register */
+
+/* vim: set sw=4 ts=4 tw=78 noexpandtab fdm=marker : */
+