From: Felix Fietkau Date: Fri, 17 Jan 2025 10:09:29 +0000 (+0100) Subject: add support for an override config directory X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=fb3c2343b17b759b175f11aec5b3fbb1cf48bbc3;p=project%2Fuci.git 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 --- 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 .
=\n" "\n" "Options:\n" - "\t-c set the search path for config files (default: /etc/config)\n" + "\t-c set the search path for config files (default: "UCI_CONFDIR")\n" + "\t-C set the search path for config override files (default: "UCI_CONF2DIR")\n" "\t-d set the delimiter for list values in uci show\n" "\t-f use 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 @@ -906,6 +906,26 @@ uci_lua_set_confdir(lua_State *L) return uci_push_status(L, ctx, false); } +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) { @@ -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 @@ -265,6 +266,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 @@ -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: */