diff options
Diffstat (limited to 'src/libnetdata/config/appconfig_migrate.c')
-rw-r--r-- | src/libnetdata/config/appconfig_migrate.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/libnetdata/config/appconfig_migrate.c b/src/libnetdata/config/appconfig_migrate.c new file mode 100644 index 00000000..0c21ec06 --- /dev/null +++ b/src/libnetdata/config/appconfig_migrate.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "appconfig_internals.h" + +int appconfig_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new) { + struct config_option *opt_old, *opt_new; + int ret = -1; + + netdata_log_debug(D_CONFIG, "request to rename config in section '%s', old name '%s', to section '%s', new name '%s'", section_old, name_old, section_new, name_new); + + struct config_section *sect_old = appconfig_section_find(root, section_old); + if(!sect_old) return ret; + + struct config_section *sect_new = appconfig_section_find(root, section_new); + if(!sect_new) sect_new = appconfig_section_create(root, section_new); + + SECTION_LOCK(sect_old); + if(sect_old != sect_new) + SECTION_LOCK(sect_new); + + opt_old = appconfig_option_find(sect_old, name_old); + if(!opt_old) goto cleanup; + + opt_new = appconfig_option_find(sect_new, name_new); + if(opt_new) goto cleanup; + + if(unlikely(appconfig_option_del(sect_old, opt_old) != opt_old)) + netdata_log_error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted the wrong config entry.", + string2str(opt_old->name), string2str(sect_old->name)); + + // remember the old position of the item + struct config_option *opt_old_next = (sect_old == sect_new) ? opt_old->next : NULL; + + DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(sect_old->values, opt_old, prev, next); + + nd_log(NDLS_DAEMON, NDLP_WARNING, + "CONFIG: option '[%s].%s' has been migrated to '[%s].%s'.", + section_old, name_old, + section_new, name_new); + + if(!opt_old->migrated.name) { + string_freez(opt_old->migrated.section); + opt_old->migrated.section = string_dup(sect_old->name); + opt_old->migrated.name = opt_old->name; + } + else + string_freez(opt_old->name); + + opt_old->name = string_strdupz(name_new); + opt_old->flags |= CONFIG_VALUE_MIGRATED; + + opt_new = opt_old; + + // put in the list, but try to keep the order + if(opt_old_next && sect_old == sect_new) + DOUBLE_LINKED_LIST_INSERT_ITEM_BEFORE_UNSAFE(sect_new->values, opt_old_next, opt_new, prev, next); + else { + // we don't have the old next item (probably a different section?) + // find the last MIGRATED one + struct config_option *t = sect_new->values ? sect_new->values->prev : NULL; + for (; t && t != sect_new->values ; t = t->prev) { + if (t->flags & CONFIG_VALUE_MIGRATED) + break; + } + if (t == sect_new->values) + DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(sect_new->values, opt_new, prev, next); + else + DOUBLE_LINKED_LIST_INSERT_ITEM_AFTER_UNSAFE(sect_new->values, t, opt_new, prev, next); + } + + if(unlikely(appconfig_option_add(sect_new, opt_old) != opt_old)) + netdata_log_error("INTERNAL ERROR: re-indexing of config '%s' in section '%s', already exists.", + string2str(opt_old->name), string2str(sect_new->name)); + + ret = 0; + +cleanup: + if(sect_old != sect_new) + SECTION_UNLOCK(sect_new); + SECTION_UNLOCK(sect_old); + return ret; +} + +int appconfig_move_everywhere(struct config *root, const char *name_old, const char *name_new) { + int ret = -1; + APPCONFIG_LOCK(root); + struct config_section *sect; + for(sect = root->sections; sect; sect = sect->next) { + if(appconfig_move(root, string2str(sect->name), name_old, string2str(sect->name), name_new) == 0) + ret = 0; + } + APPCONFIG_UNLOCK(root); + return ret; +} + |