X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Ftarget_replace.c;h=54d41647cc08d6a01bbbd58ec28da514a86d6ae3;hp=382fc3575de6b0aca4c7b3926366dea0cbae832c;hb=7b8851b26928b609ce850e78c1eabb50ff319244;hpb=2079ee1517e34de372f58e7e2267ad5c71a8a41f diff --git a/src/target_replace.c b/src/target_replace.c index 382fc357..54d41647 100644 --- a/src/target_replace.c +++ b/src/target_replace.c @@ -37,17 +37,28 @@ typedef struct tr_action_s tr_action_t; struct tr_action_s { regex_t re; char *replacement; - int may_be_empty; + _Bool may_be_empty; tr_action_t *next; }; +struct tr_meta_data_action_s; +typedef struct tr_meta_data_action_s tr_meta_data_action_t; +struct tr_meta_data_action_s { + char *key; + regex_t re; + char *replacement; + + tr_meta_data_action_t *next; +}; + struct tr_data_s { tr_action_t *host; tr_action_t *plugin; tr_action_t *plugin_instance; /* tr_action_t *type; */ tr_action_t *type_instance; + tr_meta_data_action_t *meta; }; typedef struct tr_data_s tr_data_t; @@ -57,16 +68,16 @@ static char *tr_strdup(const char *orig) /* {{{ */ char *dest; if (orig == NULL) - return (NULL); + return NULL; sz = strlen(orig) + 1; dest = malloc(sz); if (dest == NULL) - return (NULL); + return NULL; memcpy(dest, orig, sz); - return (dest); + return dest; } /* }}} char *tr_strdup */ static void tr_action_destroy(tr_action_t *act) /* {{{ */ @@ -83,26 +94,41 @@ static void tr_action_destroy(tr_action_t *act) /* {{{ */ sfree(act); } /* }}} void tr_action_destroy */ +static void tr_meta_data_action_destroy(tr_meta_data_action_t *act) /* {{{ */ +{ + if (act == NULL) + return; + + sfree(act->key); + regfree(&act->re); + sfree(act->replacement); + + if (act->next != NULL) + tr_meta_data_action_destroy(act->next); + + sfree(act); +} /* }}} void tr_meta_data_action_destroy */ + static int tr_config_add_action(tr_action_t **dest, /* {{{ */ - const oconfig_item_t *ci, int may_be_empty) { + const oconfig_item_t *ci, _Bool may_be_empty) { tr_action_t *act; int status; if (dest == NULL) - return (-EINVAL); + return -EINVAL; if ((ci->values_num != 2) || (ci->values[0].type != OCONFIG_TYPE_STRING) || (ci->values[1].type != OCONFIG_TYPE_STRING)) { ERROR("Target `replace': The `%s' option requires exactly two string " "arguments.", ci->key); - return (-1); + return -1; } act = calloc(1, sizeof(*act)); if (act == NULL) { ERROR("tr_config_add_action: calloc failed."); - return (-ENOMEM); + return -ENOMEM; } act->replacement = NULL; @@ -118,15 +144,14 @@ static int tr_config_add_action(tr_action_t **dest, /* {{{ */ "failed: %s.", ci->values[0].value.string, errbuf); sfree(act); - return (-EINVAL); + return -EINVAL; } act->replacement = tr_strdup(ci->values[1].value.string); if (act->replacement == NULL) { ERROR("tr_config_add_action: tr_strdup failed."); - regfree(&act->re); - sfree(act); - return (-ENOMEM); + tr_action_destroy(act); + return -ENOMEM; } /* Insert action at end of list. */ @@ -142,18 +167,108 @@ static int tr_config_add_action(tr_action_t **dest, /* {{{ */ prev->next = act; } - return (0); + return 0; } /* }}} int tr_config_add_action */ +static int tr_config_add_meta_action(tr_meta_data_action_t **dest, /* {{{ */ + const oconfig_item_t *ci, + _Bool should_delete) { + tr_meta_data_action_t *act; + int status; + + if (dest == NULL) + return -EINVAL; + + if (should_delete) { + if ((ci->values_num != 2) || (ci->values[0].type != OCONFIG_TYPE_STRING) || + (ci->values[1].type != OCONFIG_TYPE_STRING)) { + ERROR("Target `replace': The `%s' option requires exactly two string " + "arguments.", + ci->key); + return -1; + } + } else { + if ((ci->values_num != 3) || (ci->values[0].type != OCONFIG_TYPE_STRING) || + (ci->values[1].type != OCONFIG_TYPE_STRING) || + (ci->values[2].type != OCONFIG_TYPE_STRING)) { + ERROR("Target `replace': The `%s' option requires exactly three string " + "arguments.", + ci->key); + return -1; + } + } + + if (strlen(ci->values[0].value.string) == 0) { + ERROR("Target `replace': The `%s' option does not accept empty string as " + "first argument.", + ci->key); + return -1; + } + + act = calloc(1, sizeof(*act)); + if (act == NULL) { + ERROR("tr_config_add_meta_action: calloc failed."); + return -ENOMEM; + } + + act->key = NULL; + act->replacement = NULL; + + status = regcomp(&act->re, ci->values[1].value.string, REG_EXTENDED); + if (status != 0) { + char errbuf[1024] = ""; + + /* regerror assures null termination. */ + regerror(status, &act->re, errbuf, sizeof(errbuf)); + ERROR("Target `replace': Compiling the regular expression `%s' " + "failed: %s.", + ci->values[1].value.string, errbuf); + sfree(act->key); + sfree(act); + return -EINVAL; + } + + act->key = tr_strdup(ci->values[0].value.string); + if (act->key == NULL) { + ERROR("tr_config_add_meta_action: tr_strdup failed."); + tr_meta_data_action_destroy(act); + return -ENOMEM; + } + + if (!should_delete) { + act->replacement = tr_strdup(ci->values[2].value.string); + if (act->replacement == NULL) { + ERROR("tr_config_add_meta_action: tr_strdup failed."); + tr_meta_data_action_destroy(act); + return -ENOMEM; + } + } + + /* Insert action at end of list. */ + if (*dest == NULL) + *dest = act; + else { + tr_meta_data_action_t *prev; + + prev = *dest; + while (prev->next != NULL) + prev = prev->next; + + prev->next = act; + } + + return 0; +} /* }}} int tr_config_add_meta_action */ + static int tr_action_invoke(tr_action_t *act_head, /* {{{ */ char *buffer_in, size_t buffer_in_size, - int may_be_empty) { + _Bool may_be_empty) { int status; char buffer[DATA_MAX_NAME_LEN]; regmatch_t matches[8] = {[0] = {0}}; if (act_head == NULL) - return (-EINVAL); + return -EINVAL; sstrncpy(buffer, buffer_in, sizeof(buffer)); @@ -179,7 +294,8 @@ static int tr_action_invoke(tr_action_t *act_head, /* {{{ */ subst_status = subst(temp, sizeof(temp), buffer, (size_t)matches[0].rm_so, (size_t)matches[0].rm_eo, act->replacement); if (subst_status == NULL) { - ERROR("Target `replace': subst (buffer = %s, start = %zu, end = %zu, " + ERROR("Target `replace': subst (buffer = %s, start = %" PRIsz + ", end = %" PRIsz ", " "replacement = %s) failed.", buffer, (size_t)matches[0].rm_so, (size_t)matches[0].rm_eo, act->replacement); @@ -193,34 +309,140 @@ static int tr_action_invoke(tr_action_t *act_head, /* {{{ */ if ((may_be_empty == 0) && (buffer[0] == 0)) { WARNING("Target `replace': Replacement resulted in an empty string, " "which is not allowed for this buffer (`host' or `plugin')."); - return (0); + return 0; } DEBUG("target_replace plugin: tr_action_invoke: -> buffer = %s;", buffer); sstrncpy(buffer_in, buffer, buffer_in_size); - return (0); + return 0; } /* }}} int tr_action_invoke */ +static int tr_meta_data_action_invoke(/* {{{ */ + tr_meta_data_action_t *act_head, + meta_data_t **dest) { + int status; + regmatch_t matches[8] = {[0] = {0}}; + + if (act_head == NULL) + return -EINVAL; + + if ((*dest) == NULL) /* nothing to do */ + return 0; + + for (tr_meta_data_action_t *act = act_head; act != NULL; act = act->next) { + char temp[DATA_MAX_NAME_LEN]; + char *subst_status; + int value_type; + int meta_data_status; + char *value; + meta_data_t *result; + + value_type = meta_data_type(*dest, act->key); + if (value_type == 0) /* not found */ + continue; + if (value_type != MD_TYPE_STRING) { + WARNING("Target `replace': Attempting replace on metadata key `%s', " + "which isn't a string.", + act->key); + continue; + } + + meta_data_status = meta_data_get_string(*dest, act->key, &value); + if (meta_data_status != 0) { + ERROR("Target `replace': Unable to retrieve metadata value for `%s'.", + act->key); + return meta_data_status; + } + + DEBUG("target_replace plugin: tr_meta_data_action_invoke: `%s' " + "old value = `%s'", + act->key, value); + + status = regexec(&act->re, value, STATIC_ARRAY_SIZE(matches), matches, + /* flags = */ 0); + if (status == REG_NOMATCH) { + sfree(value); + continue; + } else if (status != 0) { + char errbuf[1024] = ""; + + regerror(status, &act->re, errbuf, sizeof(errbuf)); + ERROR("Target `replace': Executing a regular expression failed: %s.", + errbuf); + sfree(value); + continue; + } + + if (act->replacement == NULL) { + /* no replacement; delete the key */ + DEBUG("target_replace plugin: tr_meta_data_action_invoke: " + "deleting `%s'", + act->key); + meta_data_delete(*dest, act->key); + sfree(value); + continue; + } + + subst_status = subst(temp, sizeof(temp), value, (size_t)matches[0].rm_so, + (size_t)matches[0].rm_eo, act->replacement); + if (subst_status == NULL) { + ERROR("Target `replace': subst (value = %s, start = %" PRIsz + ", end = %" PRIsz ", " + "replacement = %s) failed.", + value, (size_t)matches[0].rm_so, (size_t)matches[0].rm_eo, + act->replacement); + sfree(value); + continue; + } + + DEBUG("target_replace plugin: tr_meta_data_action_invoke: `%s' " + "value `%s' -> `%s'", + act->key, value, temp); + + if ((result = meta_data_create()) == NULL) { + ERROR("Target `replace': failed to create metadata for `%s'.", act->key); + sfree(value); + return -ENOMEM; + } + + meta_data_status = meta_data_add_string(result, act->key, temp); + if (meta_data_status != 0) { + ERROR("Target `replace': Unable to set metadata value for `%s'.", + act->key); + meta_data_destroy(result); + sfree(value); + return meta_data_status; + } + + meta_data_clone_merge(dest, result); + meta_data_destroy(result); + sfree(value); + } /* for (act = act_head; act != NULL; act = act->next) */ + + return 0; +} /* }}} int tr_meta_data_action_invoke */ + static int tr_destroy(void **user_data) /* {{{ */ { tr_data_t *data; if (user_data == NULL) - return (-EINVAL); + return -EINVAL; data = *user_data; if (data == NULL) - return (0); + return 0; tr_action_destroy(data->host); tr_action_destroy(data->plugin); tr_action_destroy(data->plugin_instance); /* tr_action_destroy (data->type); */ tr_action_destroy(data->type_instance); + tr_meta_data_action_destroy(data->meta); sfree(data); - return (0); + return 0; } /* }}} int tr_destroy */ static int tr_create(const oconfig_item_t *ci, void **user_data) /* {{{ */ @@ -231,7 +453,7 @@ static int tr_create(const oconfig_item_t *ci, void **user_data) /* {{{ */ data = calloc(1, sizeof(*data)); if (data == NULL) { ERROR("tr_create: calloc failed."); - return (-ENOMEM); + return -ENOMEM; } data->host = NULL; @@ -239,6 +461,7 @@ static int tr_create(const oconfig_item_t *ci, void **user_data) /* {{{ */ data->plugin_instance = NULL; /* data->type = NULL; */ data->type_instance = NULL; + data->meta = NULL; status = 0; for (int i = 0; i < ci->children_num; i++) { @@ -262,6 +485,12 @@ static int tr_create(const oconfig_item_t *ci, void **user_data) /* {{{ */ else if (strcasecmp("TypeInstance", child->key) == 0) status = tr_config_add_action(&data->type_instance, child, /* may be empty = */ 1); + else if (strcasecmp("MetaData", child->key) == 0) + status = tr_config_add_meta_action(&data->meta, child, + /* should delete = */ 0); + else if (strcasecmp("DeleteMetaData", child->key) == 0) + status = tr_config_add_meta_action(&data->meta, child, + /* should delete = */ 1); else { ERROR("Target `replace': The `%s' configuration option is not understood " "and will be ignored.", @@ -278,7 +507,7 @@ static int tr_create(const oconfig_item_t *ci, void **user_data) /* {{{ */ if ((data->host == NULL) && (data->plugin == NULL) && (data->plugin_instance == NULL) /* && (data->type == NULL) */ - && (data->type_instance == NULL)) { + && (data->type_instance == NULL) && (data->meta == NULL)) { ERROR("Target `replace': You need to set at least one of `Host', " "`Plugin', `PluginInstance' or `TypeInstance'."); status = -1; @@ -289,11 +518,11 @@ static int tr_create(const oconfig_item_t *ci, void **user_data) /* {{{ */ if (status != 0) { tr_destroy((void *)&data); - return (status); + return status; } *user_data = data; - return (0); + return 0; } /* }}} int tr_create */ static int tr_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ @@ -302,12 +531,16 @@ static int tr_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ tr_data_t *data; if ((ds == NULL) || (vl == NULL) || (user_data == NULL)) - return (-EINVAL); + return -EINVAL; data = *user_data; if (data == NULL) { ERROR("Target `replace': Invoke: `data' is NULL."); - return (-EINVAL); + return -EINVAL; + } + + if (data->meta != NULL) { + tr_meta_data_action_invoke(data->meta, &(vl->meta)); } #define HANDLE_FIELD(f, e) \ @@ -316,10 +549,10 @@ static int tr_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */ HANDLE_FIELD(host, 0); HANDLE_FIELD(plugin, 0); HANDLE_FIELD(plugin_instance, 1); - /* HANDLE_FIELD (type); */ + /* HANDLE_FIELD (type, 0); */ HANDLE_FIELD(type_instance, 1); - return (FC_TARGET_CONTINUE); + return FC_TARGET_CONTINUE; } /* }}} int tr_invoke */ void module_register(void) { @@ -330,5 +563,3 @@ void module_register(void) { tproc.invoke = tr_invoke; fc_register_target("replace", tproc); } /* module_register */ - -/* vim: set sw=2 sts=2 tw=78 et fdm=marker : */