diff options
author | Jo-Philipp Wich <jo@mein.io> | 2023-04-03 11:33:49 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2023-04-03 12:58:52 +0200 |
commit | 5c7d07773a597b54bee5d8d1ec5609ceee83025e (patch) | |
tree | be20d93585bbbac92dde8c17d1812cb2ee08e154 /lib/uci.c | |
parent | 51f4dba6731333c92217503fac15ad03f86d675f (diff) |
uci: fix ctx.commit() without arguments
A uci commit operation may invalidate the package pointer, leading to an
infinite loop while iterating the packages to commit.
Refactor the code to first build a string list of configurations, then
iterating it in order to avoid the iterator invalidation.
While we're at it, also allow restricting save and revert operations to
single configs, which was rejected as invalid before.
Fixes: #146
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'lib/uci.c')
-rw-r--r-- | lib/uci.c | 70 |
1 files changed, 44 insertions, 26 deletions
@@ -698,48 +698,66 @@ uc_uci_reorder(uc_vm_t *vm, size_t nargs) return ucv_boolean_new(true); } +static int +uc_uci_pkg_command_single(struct uci_context *ctx, enum pkg_cmd cmd, + struct uci_package *pkg) +{ + struct uci_ptr ptr = { 0 }; + + switch (cmd) { + case CMD_COMMIT: + return uci_commit(ctx, &pkg, false); + + case CMD_SAVE: + return uci_save(ctx, pkg); + + case CMD_REVERT: + ptr.p = pkg; + + return uci_revert(ctx, &ptr); + + default: + return UCI_ERR_INVAL; + } +} + static uc_value_t * uc_uci_pkg_command(uc_vm_t *vm, size_t nargs, enum pkg_cmd cmd) { struct uci_context **c = uc_fn_this("uci.cursor"); uc_value_t *conf = uc_fn_arg(0); - struct uci_element *e, *tmp; struct uci_package *p; - struct uci_ptr ptr = { 0 }; + char **configs = NULL; int rv, res = UCI_OK; + size_t i; - if (cmd != CMD_REVERT && conf) - err_return(UCI_ERR_INVAL); - - if (conf && ucv_type(conf) != UC_STRING) - err_return(UCI_ERR_INVAL); + if (conf) { + if (ucv_type(conf) != UC_STRING) + err_return(UCI_ERR_INVAL); - uci_foreach_element_safe(&(*c)->root, tmp, e) { - p = uci_to_package(e); + if (!(p = uci_lookup_package(*c, ucv_string_get(conf)))) + err_return(UCI_ERR_NOTFOUND); - if (conf && strcmp(e->name, ucv_string_get(conf))) - continue; + res = uc_uci_pkg_command_single(*c, cmd, p); + } + else { + if (uci_list_configs(*c, &configs)) + err_return((*c)->err); - switch (cmd) { - case CMD_COMMIT: - rv = uci_commit(*c, &p, false); - break; + if (!configs || !configs[0]) + err_return(UCI_ERR_NOTFOUND); - case CMD_SAVE: - rv = uci_save(*c, p); - break; + for (i = 0; configs[i]; i++) { + if (!(p = uci_lookup_package(*c, configs[i]))) + continue; - case CMD_REVERT: - ptr.p = p; - rv = uci_revert(*c, &ptr); - break; + rv = uc_uci_pkg_command_single(*c, cmd, p); - default: - rv = UCI_ERR_INVAL; + if (rv != UCI_OK) + res = rv; } - if (rv != UCI_OK) - res = rv; + free(configs); } if (res != UCI_OK) |