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_confdir
= UCI_CONFDIR
;
30 static const char *uci_savedir
= UCI_SAVEDIR
;
32 static const char *uci_errstr
[] = {
34 [UCI_ERR_MEM
] = "Out of memory",
35 [UCI_ERR_INVAL
] = "Invalid argument",
36 [UCI_ERR_NOTFOUND
] = "Entry not found",
37 [UCI_ERR_IO
] = "I/O error",
38 [UCI_ERR_PARSE
] = "Parse error",
39 [UCI_ERR_DUPLICATE
] = "Duplicate entry",
40 [UCI_ERR_UNKNOWN
] = "Unknown error",
43 static void uci_cleanup(struct uci_context
*ctx
);
44 static void uci_unload_plugin(struct uci_context
*ctx
, struct uci_plugin
*p
);
46 #include "uci_internal.h"
52 /* exported functions */
53 struct uci_context
*uci_alloc_context(void)
55 struct uci_context
*ctx
;
57 ctx
= (struct uci_context
*) malloc(sizeof(struct uci_context
));
58 memset(ctx
, 0, sizeof(struct uci_context
));
59 uci_list_init(&ctx
->root
);
60 uci_list_init(&ctx
->history_path
);
61 uci_list_init(&ctx
->backends
);
62 uci_list_init(&ctx
->hooks
);
63 uci_list_init(&ctx
->plugins
);
64 ctx
->flags
= UCI_FLAG_STRICT
| UCI_FLAG_SAVED_HISTORY
;
66 ctx
->confdir
= (char *) uci_confdir
;
67 ctx
->savedir
= (char *) uci_savedir
;
69 uci_list_add(&ctx
->backends
, &uci_file_backend
.e
.list
);
70 ctx
->backend
= &uci_file_backend
;
75 void uci_free_context(struct uci_context
*ctx
)
77 struct uci_element
*e
, *tmp
;
79 if (ctx
->confdir
!= uci_confdir
)
81 if (ctx
->savedir
!= uci_savedir
)
85 UCI_TRAP_SAVE(ctx
, ignore
);
86 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
87 struct uci_package
*p
= uci_to_package(e
);
90 uci_foreach_element_safe(&ctx
->history_path
, tmp
, e
) {
93 UCI_TRAP_RESTORE(ctx
);
94 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
95 uci_unload_plugin(ctx
, uci_to_plugin(e
));
103 int uci_set_confdir(struct uci_context
*ctx
, const char *dir
)
108 UCI_ASSERT(ctx
, dir
!= NULL
);
110 cdir
= uci_strdup(ctx
, dir
);
111 if (ctx
->confdir
!= uci_confdir
)
117 static void uci_cleanup(struct uci_context
*ctx
)
119 struct uci_parse_context
*pctx
;
133 uci_free_package(&pctx
->package
);
142 uci_perror(struct uci_context
*ctx
, const char *str
)
144 uci_get_errorstr(ctx
, NULL
, str
);
148 uci_get_errorstr(struct uci_context
*ctx
, char **dest
, const char *prefix
)
150 static char error_info
[128];
154 "%s%s" /* function */
165 if ((err
< 0) || (err
>= UCI_ERR_LAST
))
166 err
= UCI_ERR_UNKNOWN
;
171 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
);
179 err
= asprintf(dest
, format
,
180 (prefix
? prefix
: ""), (prefix
? ": " : ""),
181 (ctx
->func
? ctx
->func
: ""), (ctx
->func
? ": " : ""),
187 strcat(error_info
, "\n");
188 fprintf(stderr
, format
,
189 (prefix
? prefix
: ""), (prefix
? ": " : ""),
190 (ctx
->func
? ctx
->func
: ""), (ctx
->func
? ": " : ""),
196 int uci_list_configs(struct uci_context
*ctx
, char ***list
)
199 UCI_ASSERT(ctx
, list
!= NULL
);
200 UCI_ASSERT(ctx
, ctx
->backend
&& ctx
->backend
->list_configs
);
201 *list
= ctx
->backend
->list_configs(ctx
);
205 int uci_commit(struct uci_context
*ctx
, struct uci_package
**package
, bool overwrite
)
207 struct uci_package
*p
;
209 UCI_ASSERT(ctx
, package
!= NULL
);
211 UCI_ASSERT(ctx
, p
!= NULL
);
212 UCI_ASSERT(ctx
, p
->backend
&& p
->backend
->commit
);
213 p
->backend
->commit(ctx
, package
, overwrite
);
217 int uci_load(struct uci_context
*ctx
, const char *name
, struct uci_package
**package
)
219 struct uci_package
*p
;
220 struct uci_element
*e
;
223 UCI_ASSERT(ctx
, ctx
->backend
&& ctx
->backend
->load
);
224 p
= ctx
->backend
->load(ctx
, name
);
225 uci_foreach_element(&ctx
->hooks
, e
) {
226 struct uci_hook
*h
= uci_to_hook(e
);
228 h
->ops
->load(h
->ops
, p
);
236 #ifdef UCI_PLUGIN_SUPPORT
238 __plugin
int uci_add_backend(struct uci_context
*ctx
, struct uci_backend
*b
)
240 struct uci_element
*e
;
243 e
= uci_lookup_list(&ctx
->backends
, b
->e
.name
);
245 UCI_THROW(ctx
, UCI_ERR_DUPLICATE
);
247 e
= uci_malloc(ctx
, sizeof(struct uci_backend
));
248 memcpy(e
, b
, sizeof(struct uci_backend
));
250 uci_list_add(&ctx
->backends
, &e
->list
);
254 __plugin
int uci_del_backend(struct uci_context
*ctx
, struct uci_backend
*b
)
256 struct uci_element
*e
, *tmp
;
260 e
= uci_lookup_list(&ctx
->backends
, b
->e
.name
);
261 if (!e
|| uci_to_backend(e
)->ptr
!= b
->ptr
)
262 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
263 b
= uci_to_backend(e
);
265 if (ctx
->backend
&& ctx
->backend
->ptr
== b
->ptr
)
266 ctx
->backend
= &uci_file_backend
;
268 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
269 struct uci_package
*p
= uci_to_package(e
);
274 if (p
->backend
->ptr
== b
->ptr
)
275 UCI_INTERNAL(uci_unload
, ctx
, p
);
278 uci_list_del(&b
->e
.list
);
286 int uci_set_backend(struct uci_context
*ctx
, const char *name
)
288 struct uci_element
*e
;
291 UCI_ASSERT(ctx
, name
!= NULL
);
292 e
= uci_lookup_list(&ctx
->backends
, name
);
294 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
295 ctx
->backend
= uci_to_backend(e
);
299 int uci_add_hook(struct uci_context
*ctx
, const struct uci_hook_ops
*ops
)
301 struct uci_element
*e
;
306 /* check for duplicate elements */
307 uci_foreach_element(&ctx
->hooks
, e
) {
310 return UCI_ERR_INVAL
;
313 h
= uci_alloc_element(ctx
, hook
, "", 0);
315 uci_list_init(&h
->e
.list
);
316 uci_list_add(&ctx
->hooks
, &h
->e
.list
);
321 int uci_remove_hook(struct uci_context
*ctx
, const struct uci_hook_ops
*ops
)
323 struct uci_element
*e
;
325 uci_foreach_element(&ctx
->hooks
, e
) {
326 struct uci_hook
*h
= uci_to_hook(e
);
328 uci_list_del(&e
->list
);
332 return UCI_ERR_NOTFOUND
;
335 int uci_load_plugin(struct uci_context
*ctx
, const char *filename
)
337 struct uci_plugin
*p
;
338 const struct uci_plugin_ops
*ops
;
342 dlh
= dlopen(filename
, RTLD_GLOBAL
|RTLD_NOW
);
344 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
346 ops
= dlsym(dlh
, "uci_plugin");
347 if (!ops
|| !ops
->attach
|| (ops
->attach(ctx
) != 0)) {
349 fprintf(stderr
, "No ops\n");
350 else if (!ops
->attach
)
351 fprintf(stderr
, "No attach\n");
353 fprintf(stderr
, "Other weirdness\n");
355 UCI_THROW(ctx
, UCI_ERR_INVAL
);
358 p
= uci_alloc_element(ctx
, plugin
, filename
, 0);
361 uci_list_add(&ctx
->plugins
, &p
->e
.list
);
366 static void uci_unload_plugin(struct uci_context
*ctx
, struct uci_plugin
*p
)
371 uci_free_element(&p
->e
);
374 int uci_load_plugins(struct uci_context
*ctx
, const char *pattern
)
380 pattern
= UCI_PREFIX
"/lib/uci_*.so";
382 memset(&gl
, 0, sizeof(gl
));
383 glob(pattern
, 0, NULL
, &gl
);
384 for (i
= 0; i
< gl
.gl_pathc
; i
++)
385 uci_load_plugin(ctx
, gl
.gl_pathv
[i
]);