X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fuci.git;a=blobdiff_plain;f=file.c;h=4650a96cec17a300e84e2e271d43f75fe7339843;hp=470071e33e101f3ea22064bd7df35a26caaec9da;hb=3f1db94aaaf5a9020581c1d43c0d7660cfd74207;hpb=a5c84bef36cf36977a8271905f3c906bb612e484 diff --git a/file.c b/file.c index 470071e..4650a96 100644 --- a/file.c +++ b/file.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -274,6 +275,7 @@ static void assert_eol(struct uci_context *ctx, char **str) static void uci_switch_config(struct uci_context *ctx) { struct uci_parse_context *pctx; + struct uci_element *e; const char *name; pctx = ctx->pctx; @@ -295,7 +297,9 @@ static void uci_switch_config(struct uci_context *ctx) * ignore errors here, e.g. if the config was not found */ UCI_TRAP_SAVE(ctx, ignore); - uci_unload(ctx, name); + e = uci_lookup_list(ctx, &ctx->root, name); + if (e) + uci_unload(ctx, uci_to_package(e)); UCI_TRAP_RESTORE(ctx); ignore: ctx->errno = 0; @@ -529,23 +533,28 @@ int uci_load(struct uci_context *ctx, const char *name, struct uci_package **pac { struct stat statbuf; char *filename; - bool confpath; + bool confdir; FILE *file; + int fd; UCI_HANDLE_ERR(ctx); UCI_ASSERT(ctx, name != NULL); switch (name[0]) { case '.': + if (name[1] != '/') + UCI_THROW(ctx, UCI_ERR_NOTFOUND); + /* fall through */ case '/': /* absolute/relative path outside of /etc/config */ - filename = (char *) name; - confpath = false; + filename = uci_strdup(ctx, name); + name = strrchr(name, '/') + 1; + confdir = false; break; default: filename = uci_malloc(ctx, strlen(name) + sizeof(UCI_CONFDIR) + 2); sprintf(filename, UCI_CONFDIR "/%s", name); - confpath = true; + confdir = true; break; } @@ -554,13 +563,89 @@ int uci_load(struct uci_context *ctx, const char *name, struct uci_package **pac UCI_THROW(ctx, UCI_ERR_NOTFOUND); } - file = fopen(filename, "r"); - if (filename != name) - free(filename); + fd = open(filename, O_RDONLY); + if (fd <= 0) + UCI_THROW(ctx, UCI_ERR_IO); + + if (flock(fd, LOCK_SH) < 0) + UCI_THROW(ctx, UCI_ERR_IO); + file = fdopen(fd, "r"); if (!file) UCI_THROW(ctx, UCI_ERR_IO); - return uci_import(ctx, file, name, package); + ctx->errno = 0; + UCI_TRAP_SAVE(ctx, done); + uci_import(ctx, file, name, package); + UCI_TRAP_RESTORE(ctx); + + if (*package) { + (*package)->path = filename; + (*package)->confdir = confdir; + } + +done: + flock(fd, LOCK_UN); + fclose(file); + return ctx->errno; } +/* + * This function returns the filename by returning the string + * after the last '/' character. By checking for a non-'\0' + * character afterwards, directories are ignored (glob marks + * those with a trailing '/' + */ +static inline char *get_filename(char *path) +{ + char *p; + + p = strrchr(path, '/'); + p++; + if (!*p) + return NULL; + return p; +} + +char **uci_list_configs(struct uci_context *ctx) +{ + char **configs; + glob_t globbuf; + int size, i; + char *buf; + + if (glob(UCI_CONFDIR "/*", GLOB_MARK, NULL, &globbuf) != 0) + return NULL; + + size = sizeof(char *) * (globbuf.gl_pathc + 1); + for(i = 0; i < globbuf.gl_pathc; i++) { + char *p; + + p = get_filename(globbuf.gl_pathv[i]); + if (!p) + continue; + + size += strlen(p) + 1; + } + + configs = malloc(size); + if (!configs) + return NULL; + + memset(configs, 0, size); + buf = (char *) &configs[globbuf.gl_pathc + 1]; + for(i = 0; i < globbuf.gl_pathc; i++) { + char *p; + + p = get_filename(globbuf.gl_pathv[i]); + if (!p) + continue; + + configs[i] = buf; + strcpy(buf, p); + buf += strlen(buf) + 1; + } + return configs; +} + +