summaryrefslogtreecommitdiffstats
path: root/fluent-bit/src/flb_config_map.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-09 13:19:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-09 13:20:02 +0000
commit58daab21cd043e1dc37024a7f99b396788372918 (patch)
tree96771e43bb69f7c1c2b0b4f7374cb74d7866d0cb /fluent-bit/src/flb_config_map.c
parentReleasing debian version 1.43.2-1. (diff)
downloadnetdata-58daab21cd043e1dc37024a7f99b396788372918.tar.xz
netdata-58daab21cd043e1dc37024a7f99b396788372918.zip
Merging upstream version 1.44.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--fluent-bit/src/flb_config_map.c817
1 files changed, 817 insertions, 0 deletions
diff --git a/fluent-bit/src/flb_config_map.c b/fluent-bit/src/flb_config_map.c
new file mode 100644
index 000000000..9a3dd7ac4
--- /dev/null
+++ b/fluent-bit/src/flb_config_map.c
@@ -0,0 +1,817 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+/* Fluent Bit
+ * ==========
+ * Copyright (C) 2015-2022 The Fluent Bit Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fluent-bit/flb_info.h>
+#include <fluent-bit/flb_kv.h>
+#include <fluent-bit/flb_env.h>
+#include <fluent-bit/flb_mem.h>
+#include <fluent-bit/flb_log.h>
+#include <fluent-bit/flb_utils.h>
+#include <fluent-bit/flb_slist.h>
+#include <fluent-bit/flb_macros.h>
+#include <fluent-bit/flb_config_map.h>
+
+static int check_list_size(struct mk_list *list, int type)
+{
+ int len;
+
+ len = mk_list_size(list);
+ if (type == FLB_CONFIG_MAP_SLIST_1 || type == FLB_CONFIG_MAP_CLIST_1) {
+ if (len < 1) {
+ return -1;
+ }
+ }
+ else if (type == FLB_CONFIG_MAP_SLIST_2 || type == FLB_CONFIG_MAP_CLIST_2) {
+ if (len < 2) {
+ return -1;
+ }
+ }
+ else if (type == FLB_CONFIG_MAP_SLIST_3 || type == FLB_CONFIG_MAP_CLIST_3) {
+ if (len < 3) {
+ return -1;
+ }
+ }
+ else if (type == FLB_CONFIG_MAP_SLIST_4 || type == FLB_CONFIG_MAP_CLIST_4) {
+ if (len < 4) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Given a string, split the content using it proper separator generating a linked
+ * list of 'slist'
+ */
+static struct mk_list *parse_string_map_to_list(struct flb_config_map *map, char *str)
+{
+ int ret = -1;
+ int type;
+ int max_split = -1;
+ struct mk_list *list;
+
+ type = map->type;
+
+ /* Allocate list head */
+ list = flb_malloc(sizeof(struct mk_list));
+ if (!list) {
+ flb_errno();
+ return NULL;
+ }
+ mk_list_init(list);
+
+ /* Determinate the max split value based on it type */
+ if (map->type > FLB_CONFIG_MAP_CLIST && map->type < FLB_CONFIG_MAP_SLIST) {
+ type = FLB_CONFIG_MAP_CLIST;
+ max_split = (map->type - FLB_CONFIG_MAP_CLIST);
+ }
+ else if (map->type > FLB_CONFIG_MAP_SLIST) {
+ type = FLB_CONFIG_MAP_SLIST;
+ max_split = (map->type - FLB_CONFIG_MAP_SLIST);
+ }
+
+ if (type == FLB_CONFIG_MAP_CLIST) {
+ ret = flb_slist_split_string(list, str, ',', max_split);
+ }
+ else if (type == FLB_CONFIG_MAP_SLIST) {
+ ret = flb_slist_split_tokens(list, str, max_split);
+ }
+
+ if (ret == -1) {
+ flb_error("[config map] error reading list of options");
+ flb_free(list);
+ return NULL;
+ }
+
+ return list;
+}
+
+static int translate_default_value(struct flb_config_map *map, char *val)
+{
+ int ret;
+ struct flb_config_map_val *entry = NULL;
+ struct mk_list *list = NULL;
+
+ /* Prepare contexts if the map allows multiple entries */
+ if (map->flags & FLB_CONFIG_MAP_MULT) {
+ entry = flb_calloc(1, sizeof(struct flb_config_map_val));
+ if (!entry) {
+ flb_errno();
+ /*
+ * do not worry about 'list' allocation, it will be destroyed by the caller
+ * when it catches this error
+ */
+ return -1;
+ }
+ }
+ else {
+ entry = &map->value;
+ }
+
+ /* Based on specific data types, populate 'value' */
+ if (map->type == FLB_CONFIG_MAP_STR) {
+ /* Duplicate string as a flb_sds_t */
+ entry->val.str = flb_sds_create(val);
+
+ /* Validate new memory allocation */
+ if (!entry->val.str) {
+ goto error;
+ }
+ }
+ else if (map->type == FLB_CONFIG_MAP_STR_PREFIX) {
+ /*
+ * For prefixed string types we don't process them, just validate
+ * that no default value has been set.
+ */
+ if (val) {
+ flb_error("[config map] invalid default value for prefixed string '%s'",
+ map->name);
+ goto error;
+ }
+ }
+ else if (map->type == FLB_CONFIG_MAP_BOOL) {
+ ret = flb_utils_bool(val);
+ if (ret == -1) {
+ flb_error("[config map] invalid default value for boolean '%s=%s'",
+ map->name, val);
+ goto error;
+ }
+ entry->val.boolean = flb_utils_bool(val);
+ }
+ else if (map->type == FLB_CONFIG_MAP_INT) {
+ entry->val.i_num = atoi(val);
+ }
+ else if (map->type == FLB_CONFIG_MAP_DOUBLE) {
+ entry->val.d_num = atof(val);
+ }
+ else if (map->type == FLB_CONFIG_MAP_SIZE) {
+ entry->val.s_num = flb_utils_size_to_bytes(val);
+ }
+ else if (map->type == FLB_CONFIG_MAP_TIME) {
+ entry->val.i_num = flb_utils_time_to_seconds(val);
+ }
+ else if (map->type >= FLB_CONFIG_MAP_CLIST &&
+ map->type <= FLB_CONFIG_MAP_SLIST_4) {
+
+ list = parse_string_map_to_list(map, val);
+ if (!list) {
+ flb_error("[config map] cannot parse list of values '%s'", val);
+ goto error;
+ }
+
+ entry->val.list = list;
+ list = NULL;
+ }
+
+ if (map->flags & FLB_CONFIG_MAP_MULT) {
+ mk_list_add(&entry->_head, map->value.mult);
+ }
+
+ return 0;
+
+ error:
+ if (map->flags & FLB_CONFIG_MAP_MULT) {
+ flb_free(entry);
+ }
+ return -1;
+}
+
+static flb_sds_t helper_map_options(struct mk_list *map)
+{
+ flb_sds_t buf;
+ flb_sds_t tmp;
+ struct mk_list *head;
+ struct flb_config_map *m;
+
+ buf = flb_sds_create_size(256);
+ if (!buf) {
+ flb_errno();
+ return NULL;
+ }
+
+ tmp = flb_sds_printf(&buf, "The following properties are allowed: ");
+ if (!tmp) {
+ flb_errno();
+ flb_sds_destroy(buf);
+ return NULL;
+ }
+ buf = tmp;
+
+ mk_list_foreach(head, map) {
+ m = mk_list_entry(head, struct flb_config_map, _head);
+ if (head->next != map) {
+ tmp = flb_sds_printf(&buf, "%s, ", m->name);
+ }
+ else {
+ if (mk_list_size(map) == 1) {
+ tmp = flb_sds_printf(&buf, "%s.", m->name);
+ }
+ else {
+ tmp = flb_sds_printf(&buf, "and %s.", m->name);
+ }
+ }
+
+ if (!tmp) {
+ flb_errno();
+ flb_sds_destroy(buf);
+ return NULL;
+ }
+ buf = tmp;
+ }
+
+ return buf;
+}
+
+/*
+ * Given a static plugin configuration map, create a linked list representation. We use a
+ * linked list using heap memory instead of the stack since a plugin can be loaded multiple
+ * times.
+ *
+ * In addition, for default values, we process them and populate the 'value' field with
+ * proper data types.
+ */
+struct mk_list *flb_config_map_create(struct flb_config *config,
+ struct flb_config_map *map)
+{
+ int ret;
+ flb_sds_t env;
+ struct mk_list *tmp;
+ struct mk_list *list;
+ struct flb_config_map *new = NULL;
+ struct flb_config_map *m;
+
+ list = flb_malloc(sizeof(struct mk_list));
+ if (!list) {
+ flb_errno();
+ return NULL;
+ }
+ mk_list_init(list);
+
+ /*
+ * Read every property defined in the config map and create a new dynamic list
+ * with the same content.
+ *
+ * As an additional step, it populate the 'value' field using the given default
+ * value if any. Note that default values are strings so they are processed
+ * to fit into the proper data type of 'value'.
+ */
+ m = map;
+ while (m && m->name) {
+ /* Allocate map node */
+ new = flb_calloc(1, sizeof(struct flb_config_map));
+ if (!new) {
+ flb_errno();
+ flb_config_map_destroy(list);
+ return NULL;
+ }
+
+ new->type = m->type;
+ new->name = flb_sds_create(m->name);
+ if (new->name == NULL) {
+ flb_free(new);
+ flb_config_map_destroy(list);
+ return NULL;
+ }
+
+ /* Translate default value */
+ if (m->def_value) {
+ /*
+ * Before to translate any value, make sure to disable the warning
+ * about unused variables. This might happen if a default value is an
+ * environment variable and the user is not using it (which is ok for
+ * that specific use case).
+ */
+ flb_env_warn_unused(config->env, FLB_FALSE);
+
+ /* Translate the value */
+ env = flb_env_var_translate(config->env, m->def_value);
+ if (env == NULL) {
+ flb_errno();
+ flb_sds_destroy(new->name);
+ flb_free(new);
+ flb_config_map_destroy(list);
+ return NULL;
+ }
+ new->def_value = env;
+ flb_env_warn_unused(config->env, FLB_TRUE);
+ }
+
+ new->flags = m->flags;
+ new->set_property = m->set_property;
+ new->offset = m->offset;
+ new->value.mult = NULL;
+ new->desc = m->desc;
+ mk_list_add(&new->_head, list);
+
+ if (new->set_property == FLB_FALSE) {
+ m++;
+ continue;
+ }
+
+ /* If this is a multiple type of entries, initialize the main list */
+ if (new->flags & FLB_CONFIG_MAP_MULT) {
+ tmp = flb_malloc(sizeof(struct mk_list));
+ if (!tmp) {
+ flb_errno();
+ flb_config_map_destroy(list);
+ return NULL;
+ }
+ mk_list_init(tmp);
+ new->value.mult = tmp;
+ }
+
+ /*
+ * If there is no default value or the entry will not be set, just
+ * continue with the next map entry
+ */
+ if (!m->def_value) {
+ m++;
+ continue;
+ }
+
+ /* Assign value based on data type and multiple mode if set */
+ ret = translate_default_value(new, new->def_value);
+ if (ret == -1) {
+ flb_config_map_destroy(list);
+ return NULL;
+ }
+ m++;
+ }
+
+ return list;
+}
+
+static void destroy_map_val(int type, struct flb_config_map_val *value)
+{
+ if (type == FLB_CONFIG_MAP_STR && value->val.str) {
+ flb_sds_destroy(value->val.str);
+ }
+ else if ((type >= FLB_CONFIG_MAP_CLIST &&
+ type <= FLB_CONFIG_MAP_SLIST_4) &&
+ value->val.list) {
+ flb_slist_destroy(value->val.list);
+ flb_free(value->val.list);
+ }
+}
+
+/* Destroy a config map context */
+void flb_config_map_destroy(struct mk_list *list)
+{
+ struct mk_list *tmp;
+ struct mk_list *head;
+ struct mk_list *v_head;
+ struct mk_list *v_tmp;
+ struct flb_config_map *map;
+ struct flb_config_map_val *entry;
+
+ mk_list_foreach_safe(head, tmp, list) {
+ map = mk_list_entry(head, struct flb_config_map, _head);
+ mk_list_del(&map->_head);
+
+ if (map->flags & FLB_CONFIG_MAP_MULT && map->value.mult) {
+ mk_list_foreach_safe(v_head, v_tmp, map->value.mult) {
+ entry = mk_list_entry(v_head, struct flb_config_map_val, _head);
+ mk_list_del(&entry->_head);
+ destroy_map_val(map->type, entry);
+ flb_free(entry);
+ }
+ flb_free(map->value.mult);
+ }
+ else {
+ destroy_map_val(map->type, &map->value);
+ }
+ if (map->def_value) {
+ flb_sds_destroy(map->def_value);
+ }
+ flb_sds_destroy(map->name);
+ flb_free(map);
+ }
+ flb_free(list);
+}
+
+/* Count the number of times a property key exists */
+int property_count(char *key, int len, struct mk_list *properties)
+{
+ int count = 0;
+ struct mk_list *head;
+ struct flb_kv *kv;
+
+ mk_list_foreach(head, properties) {
+ kv = mk_list_entry(head, struct flb_kv, _head);
+ if (flb_sds_len(kv->key) != len) {
+ continue;
+ }
+
+ if (strncmp(kv->key, key, len) == 0) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/*
+ * If the property starts with '_debug.', it's an internal property for
+ * some component of Fluent Bit, not the plugin it self.
+ */
+static int is_internal_debug_property(char *prop_name)
+{
+#ifdef FLB_HAVE_HTTP_CLIENT_DEBUG
+ if (strncmp(prop_name, "_debug.http.", 12) == 0) {
+ return FLB_TRUE;
+ }
+#endif
+
+ return FLB_FALSE;
+}
+
+
+/* Validate that the incoming properties set by the caller are allowed by the plugin */
+int flb_config_map_properties_check(char *context_name,
+ struct mk_list *in_properties,
+ struct mk_list *map)
+{
+ int len;
+ int found;
+ int count = 0;
+ int ret;
+ flb_sds_t helper;
+ struct flb_kv *kv;
+ struct mk_list *head;
+ struct mk_list *m_head;
+ struct flb_config_map *m;
+
+ /* Iterate all incoming property list */
+ mk_list_foreach(head, in_properties) {
+ kv = mk_list_entry(head, struct flb_kv, _head);
+ found = FLB_FALSE;
+
+
+ ret = is_internal_debug_property(kv->key);
+ if (ret == FLB_TRUE) {
+ /* Skip the config map */
+ continue;
+ }
+
+ if (strcasecmp(kv->key, "active") == 0) {
+ /* Accept 'active' property ... */
+ continue;
+ }
+
+ /* Lookup the key into the provided map */
+ mk_list_foreach(m_head, map) {
+ m = mk_list_entry(m_head, struct flb_config_map, _head);
+
+ len = flb_sds_len(m->name);
+ if (m->type != FLB_CONFIG_MAP_STR_PREFIX) {
+ if (len != flb_sds_len(kv->key)) {
+ continue;
+ }
+ }
+
+ if (strncasecmp(kv->key, m->name, len) == 0) {
+ if (m->type == FLB_CONFIG_MAP_STR_PREFIX) {
+ if (flb_sds_len(kv->key) <= len) {
+ flb_error("[config] incomplete prefixed key '%s'", kv->key);
+ found = FLB_FALSE;
+ break;
+ }
+ }
+ else if(m->type == FLB_CONFIG_MAP_DEPRECATED) {
+ flb_warn("[config] %s: '%s' is deprecated",
+ context_name, kv->key);
+ }
+ found = FLB_TRUE;
+ break;
+ }
+ }
+
+ if (found == FLB_FALSE) {
+ helper = helper_map_options(map);
+ if (!helper) {
+ flb_error("[config] %s: unknown configuration property '%s'",
+ context_name, kv->key);
+ }
+ else {
+ flb_error("[config] %s: unknown configuration property '%s'. %s",
+ context_name, kv->key, helper);
+ flb_sds_destroy(helper);
+ }
+
+ return -1;
+ }
+
+ /* Validate number of times the property is set */
+ count = property_count(kv->key, flb_sds_len(kv->key), in_properties);
+ if ((m->flags & FLB_CONFIG_MAP_MULT) == 0) {
+ if (count > 1) {
+ flb_error("[config] %s: configuration property '%s' is set %i times",
+ context_name, kv->key, count);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Returns FLB_TRUE or FLB_FALSE if a property aims to override the default value
+ * assigned to the map key valled 'name'.
+ */
+static int properties_override_default(struct mk_list *properties, char *name)
+{
+ int len;
+ struct mk_list *head;
+ struct flb_kv *kv;
+
+ len = strlen(name);
+
+ mk_list_foreach(head, properties) {
+ kv = mk_list_entry(head, struct flb_kv, _head);
+ if (flb_sds_len(kv->key) != len) {
+ continue;
+ }
+
+ if (strcasecmp(kv->key, name) == 0) {
+ return FLB_TRUE;
+ }
+ }
+
+ return FLB_FALSE;
+}
+
+/*
+ * Return the number of expected values if the property type is from CLIST
+ * or SLIST family.
+ */
+int flb_config_map_expected_values(int type)
+{
+ if (type > FLB_CONFIG_MAP_CLIST && type < FLB_CONFIG_MAP_SLIST) {
+ return type - FLB_CONFIG_MAP_CLIST;
+ }
+ if (type > FLB_CONFIG_MAP_SLIST && type <= FLB_CONFIG_MAP_SLIST_4) {
+ return type - FLB_CONFIG_MAP_SLIST;
+ }
+ return -1;
+}
+
+
+/*
+ * Function used by plugins that needs to populate their context structure with the
+ * configuration properties already mapped.
+ */
+int flb_config_map_set(struct mk_list *properties, struct mk_list *map, void *context)
+{
+ int ret;
+ int len;
+ char *base;
+ char *m_bool;
+ int *m_i_num;
+ double *m_d_num;
+ size_t *m_s_num;
+ flb_sds_t *m_str;
+ struct flb_kv *kv;
+ struct mk_list *head;
+ struct mk_list *m_head;
+ struct mk_list **m_list;
+ struct mk_list *list;
+ struct flb_config_map *m = NULL;
+ struct flb_config_map_val *entry = NULL;
+
+ base = context;
+
+ /* Link 'already processed default values' into the caller context */
+ mk_list_foreach(m_head, map) {
+ m = mk_list_entry(m_head, struct flb_config_map, _head);
+
+ /*
+ * If the map type allows multiple entries, the user context is a pointer
+ * for a linked list. We just point their structure to our pre-processed
+ * list of entries.
+ */
+ if (m->flags & FLB_CONFIG_MAP_MULT && m->set_property == FLB_TRUE) {
+ m_list = (struct mk_list **) (base + m->offset);
+ *m_list = m->value.mult;
+ continue;
+ }
+
+ /*
+ * If no default value exists or the map will not write to the user
+ * context.. skip it.
+ */
+ if (!m->def_value || m->set_property == FLB_FALSE) {
+ continue;
+ }
+
+ /*
+ * If a property set by the user will override the default value, just
+ * do not put the default value into the context since it will be replaced
+ * later.
+ */
+ ret = properties_override_default(properties, m->name);
+ if (ret == FLB_TRUE) {
+ continue;
+ }
+
+ /* All the following steps are direct writes to the user context */
+ if (m->type == FLB_CONFIG_MAP_STR) {
+ m_str = (char **) (base + m->offset);
+ *m_str = m->value.val.str;
+ }
+ else if (m->type == FLB_CONFIG_MAP_INT) {
+ m_i_num = (int *) (base + m->offset);
+ *m_i_num = m->value.val.i_num;
+ }
+ else if (m->type == FLB_CONFIG_MAP_DOUBLE) {
+ m_d_num = (double *) (base + m->offset);
+ *m_d_num = m->value.val.d_num;
+ }
+ else if (m->type == FLB_CONFIG_MAP_SIZE) {
+ m_s_num = (size_t *) (base + m->offset);
+ *m_s_num = m->value.val.s_num;
+ }
+ else if (m->type == FLB_CONFIG_MAP_TIME) {
+ m_i_num = (int *) (base + m->offset);
+ *m_i_num = m->value.val.s_num;
+ }
+ else if (m->type == FLB_CONFIG_MAP_BOOL) {
+ m_bool = (char *) (base + m->offset);
+ *m_bool = m->value.val.boolean;
+ }
+ else if (m->type >= FLB_CONFIG_MAP_CLIST ||
+ m->type <= FLB_CONFIG_MAP_SLIST_4) {
+ m_list = (struct mk_list **) (base + m->offset);
+ *m_list = m->value.val.list;
+ }
+ }
+
+ /*
+ * Iterate all properties coming from the configuration reader. If a property overrides
+ * a default value already set in the previous step, just link to the new value.
+ */
+ mk_list_foreach(head, properties) {
+ kv = mk_list_entry(head, struct flb_kv, _head);
+ if (kv->val == NULL) {
+ continue;
+ }
+
+ mk_list_foreach(m_head, map) {
+ m = mk_list_entry(m_head, struct flb_config_map, _head);
+ if (flb_sds_len(kv->key) != flb_sds_len(m->name)) {
+ m = NULL;
+ continue;
+ }
+
+ if (strncasecmp(kv->key, m->name, flb_sds_len(m->name)) == 0) {
+ break;
+ }
+ m = NULL;
+ continue;
+
+ }
+
+ if (!m || m->set_property == FLB_FALSE) {
+ continue;
+ }
+
+ /* Check if the map allows multiple entries */
+ if (m->flags & FLB_CONFIG_MAP_MULT) {
+ /* Create node */
+ entry = flb_calloc(1, sizeof(struct flb_config_map_val));
+ if (!entry) {
+ flb_errno();
+ return -1;
+ }
+
+ /* Populate value */
+ if (m->type == FLB_CONFIG_MAP_STR) {
+ entry->val.str = flb_sds_create(kv->val);
+ }
+ else if (m->type == FLB_CONFIG_MAP_INT) {
+ entry->val.i_num = atoi(kv->val);
+ }
+ else if (m->type == FLB_CONFIG_MAP_DOUBLE) {
+ entry->val.d_num = atof(kv->val);
+ }
+ else if (m->type == FLB_CONFIG_MAP_SIZE) {
+ entry->val.s_num = flb_utils_size_to_bytes(kv->val);
+ }
+ else if (m->type == FLB_CONFIG_MAP_TIME) {
+ entry->val.i_num = flb_utils_time_to_seconds(kv->val);
+ }
+ else if (m->type == FLB_CONFIG_MAP_BOOL) {
+ ret = flb_utils_bool(kv->val);
+ if (ret == -1) {
+ flb_free(entry);
+ flb_error("[config map] invalid value for boolean property '%s=%s'",
+ m->name, kv->val);
+ return -1;
+ }
+ entry->val.boolean = ret;
+ }
+ else if (m->type >= FLB_CONFIG_MAP_CLIST ||
+ m->type <= FLB_CONFIG_MAP_SLIST_4) {
+
+ list = parse_string_map_to_list(m, kv->val);
+ if (!list) {
+ flb_error("[config map] cannot parse list of values '%s'", kv->val);
+ flb_free(entry);
+ return -1;
+ }
+ entry->val.list = list;
+
+ /* Validate the number of entries are the minimum expected */
+ len = mk_list_size(list);
+ ret = check_list_size(list, m->type);
+ if (ret == -1) {
+ flb_error("[config map] property '%s' expects %i values "
+ "(only %i were found)",
+ kv->key,
+ flb_config_map_expected_values(m->type), len);
+ /*
+ * Register the entry anyways, so on exit the resources will
+ * be released
+ */
+ mk_list_add(&entry->_head, m->value.mult);
+ return -1;
+ }
+ }
+
+ /* Add entry to the map 'mult' list tail */
+ mk_list_add(&entry->_head, m->value.mult);
+
+ /* Override user context */
+ m_list = (struct mk_list **) (base + m->offset);
+ *m_list = m->value.mult;
+ }
+ else if (map != NULL) {
+ /* Direct write to user context */
+ if (m->type == FLB_CONFIG_MAP_STR) {
+ m_str = (char **) (base + m->offset);
+ *m_str = kv->val;
+ }
+ else if (m->type == FLB_CONFIG_MAP_INT) {
+ m_i_num = (int *) (base + m->offset);
+ *m_i_num = atoi(kv->val);
+ }
+ else if (m->type == FLB_CONFIG_MAP_DOUBLE) {
+ m_d_num = (double *) (base + m->offset);
+ *m_d_num = atof(kv->val);
+ }
+ else if (m->type == FLB_CONFIG_MAP_BOOL) {
+ m_bool = (char *) (base + m->offset);
+ ret = flb_utils_bool(kv->val);
+ if (ret == -1) {
+ flb_error("[config map] invalid value for boolean property '%s=%s'",
+ m->name, kv->val);
+ return -1;
+ }
+ *m_bool = ret;
+ }
+ else if (m->type == FLB_CONFIG_MAP_SIZE) {
+ m_s_num = (size_t *) (base + m->offset);
+ *m_s_num = flb_utils_size_to_bytes(kv->val);
+ }
+ else if (m->type == FLB_CONFIG_MAP_TIME) {
+ m_i_num = (int *) (base + m->offset);
+ *m_i_num = flb_utils_time_to_seconds(kv->val);
+ }
+ else if (m->type >= FLB_CONFIG_MAP_CLIST ||
+ m->type <= FLB_CONFIG_MAP_SLIST_4) {
+ list = parse_string_map_to_list(m, kv->val);
+ if (!list) {
+ flb_error("[config map] cannot parse list of values '%s'", kv->val);
+ flb_free(entry);
+ return -1;
+ }
+
+ if (m->value.val.list) {
+ destroy_map_val(m->type, &m->value);
+ }
+
+ m->value.val.list = list;
+ m_list = (struct mk_list **) (base + m->offset);
+ *m_list = m->value.val.list;
+ }
+ }
+ }
+
+ return 0;
+}