X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuci.git;a=blobdiff_plain;f=libuci.c;h=a1fd92a1277713da3449bfb65e2bb84b1fdc57cc;hp=59e2ea96c42fd4dcf1fabe3b2b5df2e35f6b4390;hb=96aa070d01e676a6c7f48ff533e219f63da4fd65;hpb=7cefa00eadb4292d2c915a38a86e588c6e539d26 diff --git a/libuci.c b/libuci.c index 59e2ea9..a1fd92a 100644 --- a/libuci.c +++ b/libuci.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "uci.h" static const char *uci_confdir = UCI_CONFDIR; @@ -39,6 +41,7 @@ static const char *uci_errstr[] = { }; static void uci_cleanup(struct uci_context *ctx); +static void uci_unload_plugin(struct uci_context *ctx, struct uci_plugin *p); #include "uci_internal.h" #include "util.c" @@ -52,11 +55,16 @@ struct uci_context *uci_alloc_context(void) struct uci_context *ctx; ctx = (struct uci_context *) malloc(sizeof(struct uci_context)); + if (!ctx) + return NULL; + memset(ctx, 0, sizeof(struct uci_context)); uci_list_init(&ctx->root); uci_list_init(&ctx->history_path); uci_list_init(&ctx->backends); - ctx->flags = UCI_FLAG_STRICT; + uci_list_init(&ctx->hooks); + uci_list_init(&ctx->plugins); + ctx->flags = UCI_FLAG_STRICT | UCI_FLAG_SAVED_HISTORY; ctx->confdir = (char *) uci_confdir; ctx->savedir = (char *) uci_savedir; @@ -85,8 +93,11 @@ void uci_free_context(struct uci_context *ctx) uci_foreach_element_safe(&ctx->history_path, tmp, e) { uci_free_element(e); } - free(ctx); UCI_TRAP_RESTORE(ctx); + uci_foreach_element_safe(&ctx->root, tmp, e) { + uci_unload_plugin(ctx, uci_to_plugin(e)); + } + free(ctx); ignore: return; @@ -130,34 +141,59 @@ static void uci_cleanup(struct uci_context *ctx) free(pctx); } -void uci_perror(struct uci_context *ctx, const char *prefix) +void +uci_perror(struct uci_context *ctx, const char *str) +{ + uci_get_errorstr(ctx, NULL, str); +} + +void +uci_get_errorstr(struct uci_context *ctx, char **dest, const char *prefix) { + static char error_info[128]; int err; + const char *format = + "%s%s" /* prefix */ + "%s%s" /* function */ + "%s" /* error */ + "%s"; /* details */ + + error_info[0] = 0; if (!ctx) err = UCI_ERR_INVAL; else - err = ctx->errno; + err = ctx->err; if ((err < 0) || (err >= UCI_ERR_LAST)) err = UCI_ERR_UNKNOWN; - if (prefix) - fprintf(stderr, "%s: ", prefix); - if (ctx->func) - fprintf(stderr, "%s: ", ctx->func); - switch (err) { case UCI_ERR_PARSE: if (ctx->pctx) { - fprintf(stderr, "%s (%s) at line %d, byte %d\n", uci_errstr[err], (ctx->pctx->reason ? ctx->pctx->reason : "unknown"), ctx->pctx->line, ctx->pctx->byte); + snprintf(error_info, sizeof(error_info) - 1, " (%s) at line %d, byte %d", (ctx->pctx->reason ? ctx->pctx->reason : "unknown"), ctx->pctx->line, ctx->pctx->byte); break; } - /* fall through */ + break; default: - fprintf(stderr, "%s\n", uci_errstr[err]); break; } + if (dest) { + err = asprintf(dest, format, + (prefix ? prefix : ""), (prefix ? ": " : ""), + (ctx->func ? ctx->func : ""), (ctx->func ? ": " : ""), + uci_errstr[err], + error_info); + if (err < 0) + *dest = NULL; + } else { + strcat(error_info, "\n"); + fprintf(stderr, format, + (prefix ? prefix : ""), (prefix ? ": " : ""), + (ctx->func ? ctx->func : ""), (ctx->func ? ": " : ""), + uci_errstr[err], + error_info); + } } int uci_list_configs(struct uci_context *ctx, char ***list) @@ -184,9 +220,16 @@ int uci_commit(struct uci_context *ctx, struct uci_package **package, bool overw int uci_load(struct uci_context *ctx, const char *name, struct uci_package **package) { struct uci_package *p; + struct uci_element *e; + UCI_HANDLE_ERR(ctx); UCI_ASSERT(ctx, ctx->backend && ctx->backend->load); p = ctx->backend->load(ctx, name); + uci_foreach_element(&ctx->hooks, e) { + struct uci_hook *h = uci_to_hook(e); + if (h->ops->load) + h->ops->load(h->ops, p); + } if (package) *package = p; @@ -255,3 +298,94 @@ int uci_set_backend(struct uci_context *ctx, const char *name) ctx->backend = uci_to_backend(e); return 0; } + +int uci_add_hook(struct uci_context *ctx, const struct uci_hook_ops *ops) +{ + struct uci_element *e; + struct uci_hook *h; + + UCI_HANDLE_ERR(ctx); + + /* check for duplicate elements */ + uci_foreach_element(&ctx->hooks, e) { + h = uci_to_hook(e); + if (h->ops == ops) + return UCI_ERR_INVAL; + } + + h = uci_alloc_element(ctx, hook, "", 0); + h->ops = ops; + uci_list_init(&h->e.list); + uci_list_add(&ctx->hooks, &h->e.list); + + return 0; +} + +int uci_remove_hook(struct uci_context *ctx, const struct uci_hook_ops *ops) +{ + struct uci_element *e; + + uci_foreach_element(&ctx->hooks, e) { + struct uci_hook *h = uci_to_hook(e); + if (h->ops == ops) { + uci_list_del(&e->list); + return 0; + } + } + return UCI_ERR_NOTFOUND; +} + +int uci_load_plugin(struct uci_context *ctx, const char *filename) +{ + struct uci_plugin *p; + const struct uci_plugin_ops *ops; + void *dlh; + + UCI_HANDLE_ERR(ctx); + dlh = dlopen(filename, RTLD_GLOBAL|RTLD_NOW); + if (!dlh) + UCI_THROW(ctx, UCI_ERR_NOTFOUND); + + ops = dlsym(dlh, "uci_plugin"); + if (!ops || !ops->attach || (ops->attach(ctx) != 0)) { + if (!ops) + fprintf(stderr, "No ops\n"); + else if (!ops->attach) + fprintf(stderr, "No attach\n"); + else + fprintf(stderr, "Other weirdness\n"); + dlclose(dlh); + UCI_THROW(ctx, UCI_ERR_INVAL); + } + + p = uci_alloc_element(ctx, plugin, filename, 0); + p->dlh = dlh; + p->ops = ops; + uci_list_add(&ctx->plugins, &p->e.list); + + return 0; +} + +static void uci_unload_plugin(struct uci_context *ctx, struct uci_plugin *p) +{ + if (p->ops->detach) + p->ops->detach(ctx); + dlclose(p->dlh); + uci_free_element(&p->e); +} + +int uci_load_plugins(struct uci_context *ctx, const char *pattern) +{ + glob_t gl; + int i; + + if (!pattern) + pattern = UCI_PREFIX "/lib/uci_*.so"; + + memset(&gl, 0, sizeof(gl)); + glob(pattern, 0, NULL, &gl); + for (i = 0; i < gl.gl_pathc; i++) + uci_load_plugin(ctx, gl.gl_pathv[i]); + + return 0; +}