summaryrefslogtreecommitdiffhomepage
path: root/lib/uci.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2023-04-03 11:33:49 +0200
committerJo-Philipp Wich <jo@mein.io>2023-04-03 12:58:52 +0200
commit5c7d07773a597b54bee5d8d1ec5609ceee83025e (patch)
treebe20d93585bbbac92dde8c17d1812cb2ee08e154 /lib/uci.c
parent51f4dba6731333c92217503fac15ad03f86d675f (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.c70
1 files changed, 44 insertions, 26 deletions
diff --git a/lib/uci.c b/lib/uci.c
index b88dabd..b7319bf 100644
--- a/lib/uci.c
+++ b/lib/uci.c
@@ -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)