#include <stdio.h>
#include <ctype.h>
-/*
- * Clean up all extra memory used by the parser and exporter
- */
-static void uci_file_cleanup(struct uci_context *ctx)
-{
- struct uci_parse_context *pctx;
-
- if (ctx->buf) {
- free(ctx->buf);
- ctx->buf = NULL;
- ctx->bufsz = 0;
- }
-
- pctx = ctx->pctx;
- if (!pctx)
- return;
-
- ctx->pctx = NULL;
- if (pctx->package)
- uci_free_package(&pctx->package);
-
- if (pctx->buf)
- free(pctx->buf);
-
- free(pctx);
-}
-
+static struct uci_backend uci_file_backend;
/*
* verify that the end of the line or command is reached.
/* add the last config to main config file list */
if (pctx->package) {
+ pctx->package->backend = ctx->backend;
uci_list_add(&ctx->root, &pctx->package->e.list);
pctx->package = NULL;
* if an older config under the same name exists, unload it
* ignore errors here, e.g. if the config was not found
*/
- e = uci_lookup_list(ctx, &ctx->root, name);
+ e = uci_lookup_list(&ctx->root, name);
if (e)
UCI_THROW(ctx, UCI_ERR_DUPLICATE);
pctx->package = uci_alloc_package(ctx, name);
if (pctx->merge) {
UCI_TRAP_SAVE(ctx, error);
- uci_set(ctx, pctx->package, name, NULL, type, NULL);
+ if (uci_set(ctx, pctx->package, name, NULL, type, NULL) != UCI_OK)
+ goto error;
UCI_TRAP_RESTORE(ctx);
return;
error:
UCI_HANDLE_ERR(ctx);
/* make sure no memory from previous parse attempts is leaked */
- uci_file_cleanup(ctx);
+ uci_cleanup(ctx);
uci_alloc_parse_context(ctx);
pctx = ctx->pctx;
}
uci_fixup_section(ctx, ctx->pctx->section);
+ if (!pctx->package && name)
+ uci_switch_config(ctx);
if (package)
*package = pctx->package;
if (pctx->merge)
uci_switch_config(ctx);
/* no error happened, we can get rid of the parser context now */
- uci_file_cleanup(ctx);
+ uci_cleanup(ctx);
return 0;
}
return filename;
}
-int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package)
-{
- char *filename;
- bool confdir;
- FILE *file = NULL;
-
- UCI_HANDLE_ERR(ctx);
-
- switch (name[0]) {
- case '.':
- /* relative path outside of /etc/config */
- if (name[1] != '/')
- UCI_THROW(ctx, UCI_ERR_NOTFOUND);
- /* fall through */
- case '/':
- /* absolute path outside of /etc/config */
- filename = uci_strdup(ctx, name);
- name = strrchr(name, '/') + 1;
- confdir = false;
- break;
- default:
- /* config in /etc/config */
- filename = uci_config_path(ctx, name);
- confdir = true;
- break;
- }
-
- file = uci_open_stream(ctx, filename, SEEK_SET, false, false);
- ctx->errno = 0;
- UCI_TRAP_SAVE(ctx, done);
- UCI_INTERNAL(uci_import, ctx, file, name, package, true);
- UCI_TRAP_RESTORE(ctx);
-
- if (*package) {
- (*package)->path = filename;
- (*package)->confdir = confdir;
- uci_load_history(ctx, *package, false);
- }
-
-done:
- uci_close_stream(file);
- return ctx->errno;
-}
-
-int uci_commit(struct uci_context *ctx, struct uci_package **package, bool overwrite)
+void uci_file_commit(struct uci_context *ctx, struct uci_package **package, bool overwrite)
{
- struct uci_package *p;
+ struct uci_package *p = *package;
FILE *f = NULL;
char *name = NULL;
char *path = NULL;
- UCI_HANDLE_ERR(ctx);
- UCI_ASSERT(ctx, package != NULL);
- p = *package;
-
- UCI_ASSERT(ctx, p != NULL);
if (!p->path) {
if (overwrite)
p->path = uci_config_path(ctx, p->e.name);
UCI_THROW(ctx, UCI_ERR_INVAL);
}
-
/* open the config file for writing now, so that it is locked */
f = uci_open_stream(ctx, p->path, SEEK_SET, true, true);
/* flush unsaved changes and reload from history file */
UCI_TRAP_SAVE(ctx, done);
- if (p->confdir) {
+ if (p->has_history) {
if (!overwrite) {
name = uci_strdup(ctx, p->e.name);
path = uci_strdup(ctx, p->path);
* as well. dump and reload
*/
uci_free_package(&p);
- uci_file_cleanup(ctx);
+ uci_cleanup(ctx);
UCI_INTERNAL(uci_import, ctx, f, name, &p, true);
p->path = path;
- p->confdir = true;
+ p->has_history = true;
*package = p;
/* freed together with the uci_package */
uci_close_stream(f);
if (ctx->errno)
UCI_THROW(ctx, ctx->errno);
-
- return 0;
}
return p;
}
-int uci_list_configs(struct uci_context *ctx, char ***list)
+static char **uci_list_config_files(struct uci_context *ctx)
{
char **configs;
glob_t globbuf;
char *buf;
char *dir;
- UCI_HANDLE_ERR(ctx);
-
dir = uci_malloc(ctx, strlen(ctx->confdir) + 1 + sizeof("/*"));
sprintf(dir, "%s/*", ctx->confdir);
if (glob(dir, GLOB_MARK, NULL, &globbuf) != 0)
strcpy(buf, p);
buf += strlen(buf) + 1;
}
- *list = configs;
free(dir);
+ return configs;
+}
- return 0;
+static struct uci_package *uci_file_load(struct uci_context *ctx, const char *name)
+{
+ struct uci_package *package = NULL;
+ char *filename;
+ bool confdir;
+ FILE *file = NULL;
+
+ switch (name[0]) {
+ case '.':
+ /* relative path outside of /etc/config */
+ if (name[1] != '/')
+ UCI_THROW(ctx, UCI_ERR_NOTFOUND);
+ /* fall through */
+ case '/':
+ /* absolute path outside of /etc/config */
+ filename = uci_strdup(ctx, name);
+ name = strrchr(name, '/') + 1;
+ confdir = false;
+ break;
+ default:
+ /* config in /etc/config */
+ filename = uci_config_path(ctx, name);
+ confdir = true;
+ break;
+ }
+
+ file = uci_open_stream(ctx, filename, SEEK_SET, false, false);
+ ctx->errno = 0;
+ UCI_TRAP_SAVE(ctx, done);
+ UCI_INTERNAL(uci_import, ctx, file, name, &package, true);
+ UCI_TRAP_RESTORE(ctx);
+
+ if (package) {
+ package->path = filename;
+ package->has_history = confdir;
+ uci_load_history(ctx, package, false);
+ }
+
+done:
+ uci_close_stream(file);
+ if (ctx->errno)
+ UCI_THROW(ctx, ctx->errno);
+ return package;
}
+static UCI_BACKEND(uci_file_backend, "file",
+ .load = uci_file_load,
+ .commit = uci_file_commit,
+ .list_configs = uci_list_config_files,
+);