| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #include "inicfg_internals.h" |
| 4 | |
| 5 | int inicfg_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new) { |
| 6 | struct config_option *opt_old, *opt_new; |
| 7 | int ret = -1; |
| 8 | |
| 9 | 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); |
| 10 | |
| 11 | struct config_section *sect_old = inicfg_section_find(root, section_old); |
| 12 | if(!sect_old) return ret; |
| 13 | |
| 14 | struct config_section *sect_new = inicfg_section_find(root, section_new); |
| 15 | if(!sect_new) sect_new = inicfg_section_create(root, section_new); |
| 16 | |
| 17 | SECTION_LOCK(sect_old); |
| 18 | if(sect_old != sect_new) |
| 19 | SECTION_LOCK(sect_new); |
| 20 | |
| 21 | opt_old = inicfg_option_find(sect_old, name_old); |
| 22 | if(!opt_old) goto cleanup; |
| 23 | |
| 24 | opt_new = inicfg_option_find(sect_new, name_new); |
| 25 | if(opt_new) goto cleanup; |
| 26 | |
| 27 | if(unlikely(inicfg_option_del(sect_old, opt_old) != opt_old)) |
| 28 | netdata_log_error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted the wrong config entry.", |
| 29 | string2str(opt_old->name), string2str(sect_old->name)); |
| 30 | |
| 31 | // remember the old position of the item |
| 32 | struct config_option *opt_old_next = (sect_old == sect_new) ? opt_old->next : NULL; |
| 33 | |
| 34 | DOUBLE_LINKED_LIST_REMOVE_ITEM_UNSAFE(sect_old->values, opt_old, prev, next); |
| 35 | |
| 36 | // nd_log(NDLS_DAEMON, NDLP_WARNING, |
| 37 | // "CONFIG: option '[%s].%s' has been migrated to '[%s].%s'.", |
| 38 | // section_old, name_old, |
| 39 | // section_new, name_new); |
| 40 | |
| 41 | if(!opt_old->migrated.name) { |
| 42 | string_freez(opt_old->migrated.section); |
| 43 | opt_old->migrated.section = string_dup(sect_old->name); |
| 44 | opt_old->migrated.name = opt_old->name; |
| 45 | } |
| 46 | else |
| 47 | string_freez(opt_old->name); |
| 48 | |
| 49 | opt_old->name = string_strdupz(name_new); |
| 50 | opt_old->flags |= CONFIG_VALUE_MIGRATED; |
| 51 | |
| 52 | opt_new = opt_old; |
| 53 | |
| 54 | // put in the list, but try to keep the order |
| 55 | if(opt_old_next && sect_old == sect_new) |
| 56 | DOUBLE_LINKED_LIST_INSERT_ITEM_BEFORE_UNSAFE(sect_new->values, opt_old_next, opt_new, prev, next); |
| 57 | else { |
| 58 | // we don't have the old next item (probably a different section?) |
| 59 | // find the last MIGRATED one |
| 60 | struct config_option *t = sect_new->values ? sect_new->values->prev : NULL; |
| 61 | for (; t && t != sect_new->values ; t = t->prev) { |
| 62 | if (t->flags & CONFIG_VALUE_MIGRATED) |
| 63 | break; |
| 64 | } |
| 65 | if (t == sect_new->values) |
| 66 | DOUBLE_LINKED_LIST_PREPEND_ITEM_UNSAFE(sect_new->values, opt_new, prev, next); |
| 67 | else |
| 68 | DOUBLE_LINKED_LIST_INSERT_ITEM_AFTER_UNSAFE(sect_new->values, t, opt_new, prev, next); |
| 69 | } |
| 70 | |
| 71 | if(unlikely(inicfg_option_add(sect_new, opt_old) != opt_old)) |
| 72 | netdata_log_error("INTERNAL ERROR: re-indexing of config '%s' in section '%s', already exists.", |
| 73 | string2str(opt_old->name), string2str(sect_new->name)); |
| 74 | |
| 75 | ret = 0; |
| 76 | |
| 77 | cleanup: |
| 78 | if(sect_old != sect_new) |
| 79 | SECTION_UNLOCK(sect_new); |
| 80 | SECTION_UNLOCK(sect_old); |
| 81 | return ret; |
| 82 | } |
| 83 | |
| 84 | int inicfg_move_everywhere(struct config *root, const char *name_old, const char *name_new) { |
| 85 | int ret = -1; |
| 86 | APPCONFIG_LOCK(root); |
| 87 | struct config_section *sect; |
| 88 | for(sect = root->sections; sect; sect = sect->next) { |
| 89 | if(inicfg_move(root, string2str(sect->name), name_old, string2str(sect->name), name_new) == 0) |
| 90 | ret = 0; |
| 91 | } |
| 92 | APPCONFIG_UNLOCK(root); |
| 93 | return ret; |
| 94 | } |
| 95 |