+++ /dev/null
-/**
- * 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 : */
-
--- /dev/null
+/**
+ * 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 : */
+