X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fuci.git;a=blobdiff_plain;f=file.c;h=152d175da122a218b0828e8c2814abe19c82e363;hp=8e7f0ce82b2a2e6790bb0e8c762833df00953f3a;hb=f2520c27cd7942dc01d3386b4083b128648343c0;hpb=4b1ddfb8358bcd57560406db26d7041c9c0cb90b diff --git a/file.c b/file.c index 8e7f0ce..152d175 100644 --- a/file.c +++ b/file.c @@ -2,9 +2,9 @@ * libuci - Library for the Unified Configuration Interface * Copyright (C) 2008 Felix Fietkau * - * this program is free software; you can redistribute it and/or modify - * it under the terms of the gnu lesser general public license version 2.1 - * as published by the free software foundation + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,8 +16,10 @@ * This file contains the code for parsing uci config files */ +#define _GNU_SOURCE #include #include +#include #include #include #include @@ -208,6 +210,9 @@ static void parse_str(struct uci_context *ctx, char **str, char **target) case '"': parse_double_quote(ctx, str, target); break; + case '#': + **str = 0; + /* fall through */ case 0: goto done; case '\\': @@ -266,7 +271,7 @@ static void assert_eol(struct uci_context *ctx, char **str) char *tmp; tmp = next_arg(ctx, str, false, false); - if (tmp && *tmp) + if (tmp && *tmp && (ctx->flags & UCI_FLAG_STRICT)) uci_parse_error(ctx, *str, "too many arguments"); } @@ -373,7 +378,6 @@ static void uci_fixup_section(struct uci_context *ctx, struct uci_section *s) static void uci_parse_config(struct uci_context *ctx, char **str) { struct uci_parse_context *pctx = ctx->pctx; - struct uci_section *s; char *name = NULL; char *type = NULL; @@ -449,7 +453,12 @@ static void uci_parse_line(struct uci_context *ctx, bool single) char *pbrk = NULL; word = strtok_r(word, " \t", &pbrk); + if (!word) + continue; + switch(word[0]) { + case '#': + return; case 'p': if ((word[1] == 0) || !strcmp(word + 1, "ackage")) uci_parse_package(ctx, &word, single); @@ -524,7 +533,7 @@ static void uci_export_package(struct uci_package *p, FILE *stream, bool header) uci_foreach_element(&p->sections, s) { struct uci_section *sec = uci_to_section(s); fprintf(stream, "\nconfig '%s'", uci_escape(ctx, sec->type)); - if (!sec->anonymous) + if (!sec->anonymous || (ctx->flags & UCI_FLAG_EXPORT_NAME)) fprintf(stream, " '%s'", uci_escape(ctx, sec->e.name)); fprintf(stream, "\n"); uci_foreach_element(&sec->options, o) { @@ -575,8 +584,10 @@ int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct u * the appropriate 'package ' string to specify the config name * NB: the config file can still override the package name */ - if (name) + if (name) { + UCI_ASSERT(ctx, uci_validate_name(name)); pctx->name = name; + } while (!feof(pctx->file)) { uci_getln(ctx, 0); @@ -681,14 +692,14 @@ static void uci_parse_history_line(struct uci_context *ctx, struct uci_package * } UCI_INTERNAL(uci_parse_tuple, ctx, buf, &package, §ion, &option, &value); - if (!package || !section || (!delete && !value)) - goto error; - if (strcmp(package, p->e.name) != 0) + if (!package || (strcmp(package, p->e.name) != 0)) goto error; if (!uci_validate_name(section)) goto error; if (option && !uci_validate_name(option)) goto error; + if ((rename || !delete) && !uci_validate_name(value)) + goto error; if (rename) UCI_INTERNAL(uci_rename, ctx, p, section, option, value); @@ -733,23 +744,43 @@ error: uci_file_cleanup(ctx); } +static void uci_load_history_file(struct uci_context *ctx, struct uci_package *p, char *filename, FILE **f, bool flush) +{ + FILE *stream = NULL; + + UCI_TRAP_SAVE(ctx, done); + stream = uci_open_stream(ctx, filename, SEEK_SET, flush, false); + if (p) + uci_parse_history(ctx, stream, p); + UCI_TRAP_RESTORE(ctx); +done: + if (f) + *f = stream; + else if (stream) + uci_close_stream(stream); +} + static void uci_load_history(struct uci_context *ctx, struct uci_package *p, bool flush) { + struct uci_element *e; char *filename = NULL; FILE *f = NULL; if (!p->confdir) return; - if ((asprintf(&filename, "%s/%s", UCI_SAVEDIR, p->e.name) < 0) || !filename) - UCI_THROW(ctx, UCI_ERR_MEM); - UCI_TRAP_SAVE(ctx, done); - f = uci_open_stream(ctx, filename, SEEK_SET, flush, false); - if (p) - uci_parse_history(ctx, f, p); - UCI_TRAP_RESTORE(ctx); + uci_foreach_element(&ctx->history_path, e) { + if ((asprintf(&filename, "%s/%s", e->name, p->e.name) < 0) || !filename) + UCI_THROW(ctx, UCI_ERR_MEM); -done: + uci_load_history_file(ctx, p, filename, NULL, false); + free(filename); + } + + if ((asprintf(&filename, "%s/%s", ctx->savedir, p->e.name) < 0) || !filename) + UCI_THROW(ctx, UCI_ERR_MEM); + + uci_load_history_file(ctx, p, filename, &f, flush); if (flush && f) { rewind(f); ftruncate(fileno(f), 0); @@ -765,10 +796,9 @@ static char *uci_config_path(struct uci_context *ctx, const char *name) { char *filename; - if (strchr(name, '/')) - UCI_THROW(ctx, UCI_ERR_INVAL); - filename = uci_malloc(ctx, strlen(name) + sizeof(UCI_CONFDIR) + 2); - sprintf(filename, UCI_CONFDIR "/%s", name); + UCI_ASSERT(ctx, uci_validate_name(name)); + filename = uci_malloc(ctx, strlen(name) + strlen(ctx->confdir) + 2); + sprintf(filename, "%s/%s", ctx->confdir, name); return filename; } @@ -780,7 +810,6 @@ int uci_load(struct uci_context *ctx, const char *name, struct uci_package **pac FILE *file = NULL; UCI_HANDLE_ERR(ctx); - UCI_ASSERT(ctx, uci_validate_name(name)); switch (name[0]) { case '.': @@ -839,7 +868,7 @@ int uci_save(struct uci_context *ctx, struct uci_package *p) if (uci_list_empty(&p->history)) return 0; - if ((asprintf(&filename, "%s/%s", UCI_SAVEDIR, p->e.name) < 0) || !filename) + if ((asprintf(&filename, "%s/%s", ctx->savedir, p->e.name) < 0) || !filename) UCI_THROW(ctx, UCI_ERR_MEM); ctx->errno = 0; @@ -905,8 +934,14 @@ int uci_commit(struct uci_context *ctx, struct uci_package **package, bool overw if (!overwrite) { name = uci_strdup(ctx, p->e.name); path = uci_strdup(ctx, p->path); + /* dump our own changes to the history file */ if (!uci_list_empty(&p->history)) UCI_INTERNAL(uci_save, ctx, p); + + /* + * other processes might have modified the config + * as well. dump and reload + */ uci_free_package(&p); uci_file_cleanup(ctx); UCI_INTERNAL(uci_import, ctx, f, name, &p, true); @@ -968,10 +1003,13 @@ int uci_list_configs(struct uci_context *ctx, char ***list) glob_t globbuf; int size, i; char *buf; + char *dir; UCI_HANDLE_ERR(ctx); - if (glob(UCI_CONFDIR "/*", GLOB_MARK, NULL, &globbuf) != 0) + dir = uci_malloc(ctx, strlen(ctx->confdir) + 1 + sizeof("/*")); + sprintf(dir, "%s/*", ctx->confdir); + if (glob(dir, GLOB_MARK, NULL, &globbuf) != 0) UCI_THROW(ctx, UCI_ERR_NOTFOUND); size = sizeof(char *) * (globbuf.gl_pathc + 1); @@ -999,6 +1037,7 @@ int uci_list_configs(struct uci_context *ctx, char ***list) buf += strlen(buf) + 1; } *list = configs; + free(dir); return 0; }