#include "collectd.h"
#include "filter_chain.h"
+#include "utils/common/common.h"
+#include "utils/metadata/meta_data.h"
+#include "utils_llist.h"
-#include <sys/types.h>
#include <regex.h>
+#include <sys/types.h>
-#define log_err(...) ERROR ("`regex' match: " __VA_ARGS__)
-#define log_warn(...) WARNING ("`regex' match: " __VA_ARGS__)
+#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;
+struct mr_regex_s {
+ regex_t re;
+ char *re_str;
- mr_regex_t *next;
+ 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;
- _Bool invert;
+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;
+ llist_t *meta; /* Maps each meta key into mr_regex_t* */
+ bool invert;
};
/*
* internal helper functions
*/
-static void mr_free_regex (mr_regex_t *r) /* {{{ */
+static void mr_free_regex(mr_regex_t *r) /* {{{ */
{
- if (r == NULL)
- return;
+ if (r == NULL)
+ return;
- regfree (&r->re);
- memset (&r->re, 0, sizeof (r->re));
- free (r->re_str);
+ regfree(&r->re);
+ memset(&r->re, 0, sizeof(r->re));
+ sfree(r->re_str);
- if (r->next != NULL)
- mr_free_regex (r->next);
+ if (r->next != NULL)
+ mr_free_regex(r->next);
} /* }}} void mr_free_regex */
-static void mr_free_match (mr_match_t *m) /* {{{ */
+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);
+ 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);
+ for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next) {
+ sfree(e->key);
+ mr_free_regex((mr_regex_t *)e->value);
+ }
+ llist_destroy(m->meta);
+
+ sfree(m);
} /* }}} void mr_free_match */
-static int mr_match_regexen (mr_regex_t *re_head, /* {{{ */
- const char *string)
-{
- if (re_head == NULL)
- return (FC_MATCH_MATCHES);
-
- for (mr_regex_t *re = re_head; re != NULL; re = re->next)
- {
- int status;
-
- status = regexec (&re->re, string,
- /* nmatch = */ 0, /* pmatch = */ NULL,
- /* eflags = */ 0);
- if (status == 0)
- {
- DEBUG ("regex match: Regular expression `%s' matches `%s'.",
- re->re_str, string);
- }
- else
- {
- DEBUG ("regex match: Regular expression `%s' does not match `%s'.",
- re->re_str, string);
- return (FC_MATCH_NO_MATCH);
- }
-
- }
-
- return (FC_MATCH_MATCHES);
+static int mr_match_regexen(mr_regex_t *re_head, /* {{{ */
+ const char *string) {
+ if (re_head == NULL)
+ return FC_MATCH_MATCHES;
+
+ for (mr_regex_t *re = re_head; re != NULL; re = re->next) {
+ int status;
+
+ status = regexec(&re->re, string,
+ /* nmatch = */ 0, /* pmatch = */ NULL,
+ /* eflags = */ 0);
+ if (status == 0) {
+ DEBUG("regex match: Regular expression `%s' matches `%s'.", re->re_str,
+ string);
+ } else {
+ DEBUG("regex match: Regular expression `%s' does not match `%s'.",
+ re->re_str, string);
+ return FC_MATCH_NO_MATCH;
+ }
+ }
+
+ return FC_MATCH_MATCHES;
} /* }}} 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 = calloc (1, sizeof (*re));
- if (re == NULL)
- {
- log_err ("mr_config_add_regex: calloc failed.");
- return (-1);
- }
- re->next = NULL;
-
- re->re_str = strdup (ci->values[0].value.string);
- if (re->re_str == NULL)
- {
- 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);
+static int mr_add_regex(mr_regex_t **re_head, const char *re_str, /* {{{ */
+ const char *option) {
+ mr_regex_t *re;
+ int status;
+
+ re = calloc(1, sizeof(*re));
+ if (re == NULL) {
+ log_err("mr_add_regex: calloc failed.");
+ return -1;
+ }
+ re->next = NULL;
+
+ re->re_str = strdup(re_str);
+ if (re->re_str == NULL) {
+ sfree(re);
+ log_err("mr_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, option,
+ errmsg);
+ sfree(re->re_str);
+ sfree(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_add_regex */
+
+static int mr_config_add_regex(mr_regex_t **re_head, /* {{{ */
+ oconfig_item_t *ci) {
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) {
+ log_warn("`%s' needs exactly one string argument.", ci->key);
+ return -1;
+ }
+
+ return mr_add_regex(re_head, ci->values[0].value.string, ci->key);
} /* }}} int mr_config_add_regex */
-static int mr_create (const oconfig_item_t *ci, void **user_data) /* {{{ */
+static int mr_config_add_meta_regex(llist_t **meta, /* {{{ */
+ oconfig_item_t *ci) {
+ char *meta_key;
+ llentry_t *entry;
+ mr_regex_t *re_head;
+ int status;
+ char buffer[1024];
+
+ if ((ci->values_num != 2) || (ci->values[0].type != OCONFIG_TYPE_STRING) ||
+ (ci->values[1].type != OCONFIG_TYPE_STRING)) {
+ log_warn("`%s' needs exactly two string arguments.", ci->key);
+ return -1;
+ }
+
+ if (*meta == NULL) {
+ *meta = llist_create();
+ if (*meta == NULL) {
+ log_err("mr_config_add_meta_regex: llist_create failed.");
+ return -1;
+ }
+ }
+
+ meta_key = ci->values[0].value.string;
+ entry = llist_search(*meta, meta_key);
+ if (entry == NULL) {
+ meta_key = strdup(meta_key);
+ if (meta_key == NULL) {
+ log_err("mr_config_add_meta_regex: strdup failed.");
+ return -1;
+ }
+ entry = llentry_create(meta_key, NULL);
+ if (entry == NULL) {
+ log_err("mr_config_add_meta_regex: llentry_create failed.");
+ sfree(meta_key);
+ return -1;
+ }
+ /* meta_key and entry will now be freed by mr_free_match(). */
+ llist_append(*meta, entry);
+ }
+
+ snprintf(buffer, sizeof(buffer), "%s `%s'", ci->key, meta_key);
+ /* Can't pass &entry->value into mr_add_regex, so copy in/out. */
+ re_head = entry->value;
+ status = mr_add_regex(&re_head, ci->values[1].value.string, buffer);
+ if (status == 0) {
+ entry->value = re_head;
+ }
+ return status;
+} /* }}} int mr_config_add_meta_regex */
+
+static int mr_create(const oconfig_item_t *ci, void **user_data) /* {{{ */
{
- mr_match_t *m;
- int status;
-
- m = calloc (1, sizeof (*m));
- if (m == NULL)
- {
- log_err ("mr_create: calloc failed.");
- return (-ENOMEM);
- }
-
- m->invert = 0;
-
- status = 0;
- for (int 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 if (strcasecmp ("Invert", child->key) == 0)
- status = cf_util_get_boolean(child, &m->invert);
- 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);
+ mr_match_t *m;
+ int status;
+
+ m = calloc(1, sizeof(*m));
+ if (m == NULL) {
+ log_err("mr_create: calloc failed.");
+ return -ENOMEM;
+ }
+
+ m->invert = false;
+
+ status = 0;
+ for (int 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 if (strcasecmp("MetaData", child->key) == 0)
+ status = mr_config_add_meta_regex(&m->meta, child);
+ else if (strcasecmp("Invert", child->key) == 0)
+ status = cf_util_get_boolean(child, &m->invert);
+ 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) && (m->meta == 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) /* {{{ */
+static int mr_destroy(void **user_data) /* {{{ */
{
- if ((user_data != NULL) && (*user_data != NULL))
- mr_free_match (*user_data);
- return (0);
+ 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 __attribute__((unused)) *ds, /* {{{ */
- const value_list_t *vl,
- notification_meta_t __attribute__((unused)) **meta,
- void **user_data)
-{
- mr_match_t *m;
- int match_value = FC_MATCH_MATCHES;
- int nomatch_value = FC_MATCH_NO_MATCH;
-
- if ((user_data == NULL) || (*user_data == NULL))
- return (-1);
-
- m = *user_data;
-
- if (m->invert)
- {
- match_value = FC_MATCH_NO_MATCH;
- nomatch_value = FC_MATCH_MATCHES;
- }
-
- if (mr_match_regexen (m->host, vl->host) == FC_MATCH_NO_MATCH)
- return (nomatch_value);
- if (mr_match_regexen (m->plugin, vl->plugin) == FC_MATCH_NO_MATCH)
- return (nomatch_value);
- if (mr_match_regexen (m->plugin_instance,
- vl->plugin_instance) == FC_MATCH_NO_MATCH)
- return (nomatch_value);
- if (mr_match_regexen (m->type, vl->type) == FC_MATCH_NO_MATCH)
- return (nomatch_value);
- if (mr_match_regexen (m->type_instance,
- vl->type_instance) == FC_MATCH_NO_MATCH)
- return (nomatch_value);
-
- return (match_value);
+static int mr_match(const data_set_t __attribute__((unused)) * ds, /* {{{ */
+ const value_list_t *vl,
+ notification_meta_t __attribute__((unused)) * *meta,
+ void **user_data) {
+ mr_match_t *m;
+ int match_value = FC_MATCH_MATCHES;
+ int nomatch_value = FC_MATCH_NO_MATCH;
+
+ if ((user_data == NULL) || (*user_data == NULL))
+ return -1;
+
+ m = *user_data;
+
+ if (m->invert) {
+ match_value = FC_MATCH_NO_MATCH;
+ nomatch_value = FC_MATCH_MATCHES;
+ }
+
+ if (mr_match_regexen(m->host, vl->host) == FC_MATCH_NO_MATCH)
+ return nomatch_value;
+ if (mr_match_regexen(m->plugin, vl->plugin) == FC_MATCH_NO_MATCH)
+ return nomatch_value;
+ if (mr_match_regexen(m->plugin_instance, vl->plugin_instance) ==
+ FC_MATCH_NO_MATCH)
+ return nomatch_value;
+ if (mr_match_regexen(m->type, vl->type) == FC_MATCH_NO_MATCH)
+ return nomatch_value;
+ if (mr_match_regexen(m->type_instance, vl->type_instance) ==
+ FC_MATCH_NO_MATCH)
+ return nomatch_value;
+ for (llentry_t *e = llist_head(m->meta); e != NULL; e = e->next) {
+ mr_regex_t *meta_re = (mr_regex_t *)e->value;
+ char *value;
+ int status;
+ if (vl->meta == NULL)
+ return nomatch_value;
+ status = meta_data_get_string(vl->meta, e->key, &value);
+ if (status == (-ENOENT)) /* key is not present */
+ return nomatch_value;
+ if (status != 0) /* some other problem */
+ continue; /* error will have already been printed. */
+ if (mr_match_regexen(meta_re, value) == FC_MATCH_NO_MATCH) {
+ sfree(value);
+ return nomatch_value;
+ }
+ sfree(value);
+ }
+
+ return match_value;
} /* }}} int mr_match */
-void module_register (void)
-{
- match_proc_t mproc = { 0 };
+void module_register(void) {
+ match_proc_t mproc = {0};
- mproc.create = mr_create;
- mproc.destroy = mr_destroy;
- mproc.match = mr_match;
- fc_register_match ("regex", 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 : */
-