X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fmatch_regex.c;h=dd4018b03b4ec0e07b4efb5ce6871210511d58dc;hp=cd6301673a1a3673b8912375554da3a32bfd8bb1;hb=da11ce02eb202b3e01d3e2d1b40f248a84430973;hpb=1326af38b3ef25c41c994cd76c043202636b3d70 diff --git a/src/match_regex.c b/src/match_regex.c index cd630167..dd4018b0 100644 --- a/src/match_regex.c +++ b/src/match_regex.c @@ -33,13 +33,16 @@ #include "collectd.h" +#include "common.h" #include "filter_chain.h" +#include "meta_data.h" +#include "utils_llist.h" -#include #include +#include -#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 @@ -47,267 +50,317 @@ 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 = 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("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; + if (vl->meta != NULL) { + 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 = 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 : */ -