summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau2025-01-17 10:09:29 +0000
committerFelix Fietkau2025-01-17 10:25:08 +0000
commitfb3c2343b17b759b175f11aec5b3fbb1cf48bbc3 (patch)
treec5c3f8158f7ce002cc88d0f91aecfd9644473b28
parent10f7996ec29449915640acca5d65b592365a4b14 (diff)
downloaduci-fb3c2343b17b759b175f11aec5b3fbb1cf48bbc3.tar.gz
add support for an override config directory
This can be used to override specific config files at runtime without touching them on primary storage. It is used by default for both reading and updating. The primary use case for this is adding a config management system which generates and manages uci files at run time without overwriting existing config files on flash. Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r--cli.c8
-rw-r--r--file.c37
-rw-r--r--libuci.c18
-rw-r--r--lua/uci.c22
-rw-r--r--uci.h11
5 files changed, 81 insertions, 15 deletions
diff --git a/cli.c b/cli.c
index f169e42..36c21e4 100644
--- a/cli.c
+++ b/cli.c
@@ -159,7 +159,8 @@ static void uci_usage(void)
"\treorder <config>.<section>=<position>\n"
"\n"
"Options:\n"
- "\t-c <path> set the search path for config files (default: /etc/config)\n"
+ "\t-c <path> set the search path for config files (default: "UCI_CONFDIR")\n"
+ "\t-C <path> set the search path for config override files (default: "UCI_CONF2DIR")\n"
"\t-d <str> set the delimiter for list values in uci show\n"
"\t-f <file> use <file> as input instead of stdin\n"
"\t-m when importing, merge data into an existing package\n"
@@ -690,11 +691,14 @@ int main(int argc, char **argv)
return 1;
}
- while((c = getopt(argc, argv, "c:d:f:LmnNp:P:qsSt:X")) != -1) {
+ while((c = getopt(argc, argv, "c:C:d:f:LmnNp:P:qsSt:X")) != -1) {
switch(c) {
case 'c':
uci_set_confdir(ctx, optarg);
break;
+ case 'C':
+ uci_set_conf2dir(ctx, optarg);
+ break;
case 'd':
delimiter = optarg;
break;
diff --git a/file.c b/file.c
index 9db8dbd..6840cfc 100644
--- a/file.c
+++ b/file.c
@@ -719,13 +719,16 @@ error:
}
-static char *uci_config_path(struct uci_context *ctx, const char *name)
+static char *uci_config_path(struct uci_context *ctx, const char *name, bool conf2)
{
+ const char *confdir = conf2 ? ctx->conf2dir : ctx->confdir;
char *filename;
UCI_ASSERT(ctx, uci_validate_package(name));
- filename = uci_malloc(ctx, strlen(name) + strlen(ctx->confdir) + 2);
- sprintf(filename, "%s/%s", ctx->confdir, name);
+ if (!confdir)
+ return NULL;
+ filename = uci_malloc(ctx, strlen(name) + strlen(confdir) + 2);
+ sprintf(filename, "%s/%s", confdir, name);
return filename;
}
@@ -739,18 +742,18 @@ static void uci_file_commit(struct uci_context *ctx, struct uci_package **packag
char *filename = NULL;
struct stat statbuf;
volatile bool do_rename = false;
+ const char *confdir;
int fd, sz;
- if (!p->path) {
- if (overwrite)
- p->path = uci_config_path(ctx, p->e.name);
- else
- UCI_THROW(ctx, UCI_ERR_INVAL);
- }
+ if (!p->path && overwrite)
+ p->path = uci_config_path(ctx, p->e.name, p->uses_conf2);
+ if (!p->path)
+ UCI_THROW(ctx, UCI_ERR_INVAL);
- sz = snprintf(NULL, 0, "%s/.%s.uci-XXXXXX", ctx->confdir, p->e.name);
+ confdir = p->uses_conf2 ? ctx->conf2dir : ctx->confdir;
+ sz = snprintf(NULL, 0, "%s/.%s.uci-XXXXXX", confdir, p->e.name);
filename = alloca(sz + 1);
- snprintf(filename, sz + 1, "%s/.%s.uci-XXXXXX", ctx->confdir, p->e.name);
+ snprintf(filename, sz + 1, "%s/.%s.uci-XXXXXX", confdir, p->e.name);
/* open the config file for writing now, so that it is locked */
f1 = uci_open_stream(ctx, p->path, NULL, SEEK_SET, true, true);
@@ -910,6 +913,8 @@ static struct uci_package *uci_file_load(struct uci_context *ctx,
char *filename;
bool confdir;
FILE *volatile file = NULL;
+ struct stat st;
+ bool conf2;
switch (name[0]) {
case '.':
@@ -922,10 +927,17 @@ static struct uci_package *uci_file_load(struct uci_context *ctx,
filename = uci_strdup(ctx, name);
name = strrchr(name, '/') + 1;
confdir = false;
+ conf2 = false;
break;
default:
/* config in /etc/config */
- filename = uci_config_path(ctx, name);
+ conf2 = true;
+ filename = uci_config_path(ctx, name, conf2);
+ if (!filename || stat(filename, &st) != 0) {
+ conf2 = false;
+ free(filename);
+ filename = uci_config_path(ctx, name, conf2);
+ }
confdir = true;
break;
}
@@ -937,6 +949,7 @@ static struct uci_package *uci_file_load(struct uci_context *ctx,
UCI_TRAP_RESTORE(ctx);
if (package) {
+ package->uses_conf2 = conf2;
package->path = filename;
package->has_delta = confdir;
uci_load_delta(ctx, package, false);
diff --git a/libuci.c b/libuci.c
index ae4c964..cffb916 100644
--- a/libuci.c
+++ b/libuci.c
@@ -41,6 +41,7 @@ static const char *uci_errstr[] = {
#include "list.c"
__private const char *uci_confdir = UCI_CONFDIR;
+__private const char *uci_conf2dir = UCI_CONF2DIR;
__private const char *uci_savedir = UCI_SAVEDIR;
/* exported functions */
@@ -58,6 +59,7 @@ struct uci_context *uci_alloc_context(void)
ctx->flags = UCI_FLAG_STRICT | UCI_FLAG_SAVED_DELTA;
ctx->confdir = (char *) uci_confdir;
+ ctx->conf2dir = (char *) uci_conf2dir;
ctx->savedir = (char *) uci_savedir;
uci_add_delta_path(ctx, uci_savedir);
@@ -92,6 +94,22 @@ ignore:
return;
}
+int uci_set_conf2dir(struct uci_context *ctx, const char *dir)
+{
+ char *cdir;
+
+ UCI_HANDLE_ERR(ctx);
+ if (dir && !dir[0])
+ dir = NULL;
+
+ cdir = dir ? uci_strdup(ctx, dir) : NULL;
+ if (ctx->conf2dir != uci_conf2dir)
+ free(ctx->conf2dir);
+ ctx->conf2dir = cdir;
+
+ return 0;
+}
+
int uci_set_confdir(struct uci_context *ctx, const char *dir)
{
char *cdir;
diff --git a/lua/uci.c b/lua/uci.c
index 78b5e1f..5957f30 100644
--- a/lua/uci.c
+++ b/lua/uci.c
@@ -907,6 +907,26 @@ uci_lua_set_confdir(lua_State *L)
}
static int
+uci_lua_get_conf2dir(lua_State *L)
+{
+ struct uci_context *ctx = find_context(L, NULL);
+ lua_pushstring(L, ctx->conf2dir ? ctx->conf2dir : "");
+ return 1;
+}
+
+static int
+uci_lua_set_conf2dir(lua_State *L)
+{
+ struct uci_context *ctx;
+ int offset = 0;
+
+ ctx = find_context(L, &offset);
+ luaL_checkstring(L, 1 + offset);
+ uci_set_conf2dir(ctx, lua_tostring(L, -1));
+ return uci_push_status(L, ctx, false);
+}
+
+static int
uci_lua_get_savedir(lua_State *L)
{
struct uci_context *ctx = find_context(L, NULL);
@@ -1029,6 +1049,8 @@ static const luaL_Reg uci[] = {
{ "add_delta", uci_lua_add_delta },
{ "get_confdir", uci_lua_get_confdir },
{ "set_confdir", uci_lua_set_confdir },
+ { "get_conf2dir", uci_lua_get_conf2dir },
+ { "set_conf2dir", uci_lua_set_conf2dir },
{ "get_savedir", uci_lua_get_savedir },
{ "set_savedir", uci_lua_set_savedir },
{ "list_configs", uci_lua_list_configs },
diff --git a/uci.h b/uci.h
index d0374f2..b3ffdf9 100644
--- a/uci.h
+++ b/uci.h
@@ -38,6 +38,7 @@ extern "C" {
#define UCI_CONFDIR "/etc/config"
#define UCI_SAVEDIR "/tmp/.uci"
+#define UCI_CONF2DIR "/var/run/uci"
#define UCI_DIRMODE 0700
#define UCI_FILEMODE 0600
@@ -266,6 +267,13 @@ extern int uci_set_savedir(struct uci_context *ctx, const char *dir);
extern int uci_set_confdir(struct uci_context *ctx, const char *dir);
/**
+ * uci_set_conf2dir: change the override config storage directory
+ * @ctx: uci context
+ * @dir: directory name (can be NULL to disable config override)
+ */
+extern int uci_set_conf2dir(struct uci_context *ctx, const char *dir);
+
+/**
* uci_add_delta_path: add a directory to the search path for change delta files
* @ctx: uci context
* @dir: directory name
@@ -411,6 +419,7 @@ struct uci_context
char *confdir;
char *savedir;
+ char *conf2dir;
/* search path for delta files */
struct uci_list delta_path;
@@ -429,7 +438,7 @@ struct uci_package
struct uci_element e;
struct uci_list sections;
struct uci_context *ctx;
- bool has_delta;
+ bool has_delta, uses_conf2;
char *path;
/* private: */