2 * libuci - Library for the Unified Configuration Interface
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 * This file contains some common code for the uci library
20 #include <sys/types.h>
29 static const char *uci_errstr
[] = {
31 [UCI_ERR_MEM
] = "Out of memory",
32 [UCI_ERR_INVAL
] = "Invalid argument",
33 [UCI_ERR_NOTFOUND
] = "Entry not found",
34 [UCI_ERR_IO
] = "I/O error",
35 [UCI_ERR_PARSE
] = "Parse error",
36 [UCI_ERR_DUPLICATE
] = "Duplicate entry",
37 [UCI_ERR_UNKNOWN
] = "Unknown error",
40 static void uci_unload_plugin(struct uci_context
*ctx
, struct uci_plugin
*p
);
42 #include "uci_internal.h"
45 __private
const char *uci_confdir
= UCI_CONFDIR
;
46 __private
const char *uci_savedir
= UCI_SAVEDIR
;
48 /* exported functions */
49 struct uci_context
*uci_alloc_context(void)
51 struct uci_context
*ctx
;
53 ctx
= (struct uci_context
*) malloc(sizeof(struct uci_context
));
57 memset(ctx
, 0, sizeof(struct uci_context
));
58 uci_list_init(&ctx
->root
);
59 uci_list_init(&ctx
->delta_path
);
60 uci_list_init(&ctx
->backends
);
61 uci_list_init(&ctx
->hooks
);
62 uci_list_init(&ctx
->plugins
);
63 ctx
->flags
= UCI_FLAG_STRICT
| UCI_FLAG_SAVED_DELTA
;
65 ctx
->confdir
= (char *) uci_confdir
;
66 ctx
->savedir
= (char *) uci_savedir
;
68 uci_list_add(&ctx
->backends
, &uci_file_backend
.e
.list
);
69 ctx
->backend
= &uci_file_backend
;
74 void uci_free_context(struct uci_context
*ctx
)
76 struct uci_element
*e
, *tmp
;
78 if (ctx
->confdir
!= uci_confdir
)
80 if (ctx
->savedir
!= uci_savedir
)
84 UCI_TRAP_SAVE(ctx
, ignore
);
85 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
86 struct uci_package
*p
= uci_to_package(e
);
89 uci_foreach_element_safe(&ctx
->delta_path
, tmp
, e
) {
92 UCI_TRAP_RESTORE(ctx
);
93 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
94 uci_unload_plugin(ctx
, uci_to_plugin(e
));
102 int uci_set_confdir(struct uci_context
*ctx
, const char *dir
)
107 UCI_ASSERT(ctx
, dir
!= NULL
);
109 cdir
= uci_strdup(ctx
, dir
);
110 if (ctx
->confdir
!= uci_confdir
)
116 __private
void uci_cleanup(struct uci_context
*ctx
)
118 struct uci_parse_context
*pctx
;
132 uci_free_package(&pctx
->package
);
141 uci_perror(struct uci_context
*ctx
, const char *str
)
143 uci_get_errorstr(ctx
, NULL
, str
);
147 uci_get_errorstr(struct uci_context
*ctx
, char **dest
, const char *prefix
)
149 static char error_info
[128];
153 "%s%s" /* function */
164 if ((err
< 0) || (err
>= UCI_ERR_LAST
))
165 err
= UCI_ERR_UNKNOWN
;
170 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
);
178 err
= asprintf(dest
, format
,
179 (prefix
? prefix
: ""), (prefix
? ": " : ""),
180 (ctx
->func
? ctx
->func
: ""), (ctx
->func
? ": " : ""),
186 strcat(error_info
, "\n");
187 fprintf(stderr
, format
,
188 (prefix
? prefix
: ""), (prefix
? ": " : ""),
189 (ctx
->func
? ctx
->func
: ""), (ctx
->func
? ": " : ""),
195 int uci_list_configs(struct uci_context
*ctx
, char ***list
)
198 UCI_ASSERT(ctx
, list
!= NULL
);
199 UCI_ASSERT(ctx
, ctx
->backend
&& ctx
->backend
->list_configs
);
200 *list
= ctx
->backend
->list_configs(ctx
);
204 int uci_commit(struct uci_context
*ctx
, struct uci_package
**package
, bool overwrite
)
206 struct uci_package
*p
;
208 UCI_ASSERT(ctx
, package
!= NULL
);
210 UCI_ASSERT(ctx
, p
!= NULL
);
211 UCI_ASSERT(ctx
, p
->backend
&& p
->backend
->commit
);
212 p
->backend
->commit(ctx
, package
, overwrite
);
216 int uci_load(struct uci_context
*ctx
, const char *name
, struct uci_package
**package
)
218 struct uci_package
*p
;
219 struct uci_element
*e
;
222 UCI_ASSERT(ctx
, ctx
->backend
&& ctx
->backend
->load
);
223 p
= ctx
->backend
->load(ctx
, name
);
224 uci_foreach_element(&ctx
->hooks
, e
) {
225 struct uci_hook
*h
= uci_to_hook(e
);
227 h
->ops
->load(h
->ops
, p
);
235 #ifdef UCI_PLUGIN_SUPPORT
237 __plugin
int uci_add_backend(struct uci_context
*ctx
, struct uci_backend
*b
)
239 struct uci_element
*e
;
242 e
= uci_lookup_list(&ctx
->backends
, b
->e
.name
);
244 UCI_THROW(ctx
, UCI_ERR_DUPLICATE
);
246 e
= uci_malloc(ctx
, sizeof(struct uci_backend
));
247 memcpy(e
, b
, sizeof(struct uci_backend
));
249 uci_list_add(&ctx
->backends
, &e
->list
);
253 __plugin
int uci_del_backend(struct uci_context
*ctx
, struct uci_backend
*b
)
255 struct uci_element
*e
, *tmp
;
259 e
= uci_lookup_list(&ctx
->backends
, b
->e
.name
);
260 if (!e
|| uci_to_backend(e
)->ptr
!= b
->ptr
)
261 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
262 b
= uci_to_backend(e
);
264 if (ctx
->backend
&& ctx
->backend
->ptr
== b
->ptr
)
265 ctx
->backend
= &uci_file_backend
;
267 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
268 struct uci_package
*p
= uci_to_package(e
);
273 if (p
->backend
->ptr
== b
->ptr
)
274 UCI_INTERNAL(uci_unload
, ctx
, p
);
277 uci_list_del(&b
->e
.list
);
285 int uci_set_backend(struct uci_context
*ctx
, const char *name
)
287 struct uci_element
*e
;
290 UCI_ASSERT(ctx
, name
!= NULL
);
291 e
= uci_lookup_list(&ctx
->backends
, name
);
293 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
294 ctx
->backend
= uci_to_backend(e
);
298 int uci_add_hook(struct uci_context
*ctx
, const struct uci_hook_ops
*ops
)
300 struct uci_element
*e
;
305 /* check for duplicate elements */
306 uci_foreach_element(&ctx
->hooks
, e
) {
309 return UCI_ERR_INVAL
;
312 h
= uci_alloc_element(ctx
, hook
, "", 0);
314 uci_list_init(&h
->e
.list
);
315 uci_list_add(&ctx
->hooks
, &h
->e
.list
);
320 int uci_remove_hook(struct uci_context
*ctx
, const struct uci_hook_ops
*ops
)
322 struct uci_element
*e
;
324 uci_foreach_element(&ctx
->hooks
, e
) {
325 struct uci_hook
*h
= uci_to_hook(e
);
327 uci_list_del(&e
->list
);
331 return UCI_ERR_NOTFOUND
;
334 int uci_load_plugin(struct uci_context
*ctx
, const char *filename
)
336 struct uci_plugin
*p
;
337 const struct uci_plugin_ops
*ops
;
341 dlh
= dlopen(filename
, RTLD_GLOBAL
|RTLD_NOW
);
343 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
345 ops
= dlsym(dlh
, "uci_plugin");
346 if (!ops
|| !ops
->attach
|| (ops
->attach(ctx
) != 0)) {
348 fprintf(stderr
, "No ops\n");
349 else if (!ops
->attach
)
350 fprintf(stderr
, "No attach\n");
352 fprintf(stderr
, "Other weirdness\n");
354 UCI_THROW(ctx
, UCI_ERR_INVAL
);
357 p
= uci_alloc_element(ctx
, plugin
, filename
, 0);
360 uci_list_add(&ctx
->plugins
, &p
->e
.list
);
365 static void uci_unload_plugin(struct uci_context
*ctx
, struct uci_plugin
*p
)
370 uci_free_element(&p
->e
);
373 int uci_load_plugins(struct uci_context
*ctx
, const char *pattern
)
379 pattern
= UCI_PREFIX
"/lib/uci_*.so";
381 memset(&gl
, 0, sizeof(gl
));
382 glob(pattern
, 0, NULL
, &gl
);
383 for (i
= 0; i
< gl
.gl_pathc
; i
++)
384 uci_load_plugin(ctx
, gl
.gl_pathv
[i
]);