mirror of
https://git.openwrt.org/project/uci.git
synced 2025-12-20 00:53:58 +08:00
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>
This commit is contained in:
8
cli.c
8
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;
|
||||
|
||||
37
file.c
37
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);
|
||||
|
||||
18
libuci.c
18
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;
|
||||
|
||||
22
lua/uci.c
22
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 },
|
||||
|
||||
11
uci.h
11
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: */
|
||||
|
||||
Reference in New Issue
Block a user