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_unload_plugin(struct uci_context
*ctx
, struct uci_plugin
*p
);
45 #include "uci_internal.h"
50 /* exported functions */
51 struct uci_context
*uci_alloc_context(void)
53 struct uci_context
*ctx
;
55 ctx
= (struct uci_context
*) malloc(sizeof(struct uci_context
));
59 memset(ctx
, 0, sizeof(struct uci_context
));
60 uci_list_init(&ctx
->root
);
61 uci_list_init(&ctx
->history_path
);
62 uci_list_init(&ctx
->backends
);
63 uci_list_init(&ctx
->hooks
);
64 uci_list_init(&ctx
->plugins
);
65 ctx
->flags
= UCI_FLAG_STRICT
| UCI_FLAG_SAVED_HISTORY
;
67 ctx
->confdir
= (char *) uci_confdir
;
68 ctx
->savedir
= (char *) uci_savedir
;
70 uci_list_add(&ctx
->backends
, &uci_file_backend
.e
.list
);
71 ctx
->backend
= &uci_file_backend
;
76 void uci_free_context(struct uci_context
*ctx
)
78 struct uci_element
*e
, *tmp
;
80 if (ctx
->confdir
!= uci_confdir
)
82 if (ctx
->savedir
!= uci_savedir
)
86 UCI_TRAP_SAVE(ctx
, ignore
);
87 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
88 struct uci_package
*p
= uci_to_package(e
);
91 uci_foreach_element_safe(&ctx
->history_path
, tmp
, e
) {
94 UCI_TRAP_RESTORE(ctx
);
95 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
96 uci_unload_plugin(ctx
, uci_to_plugin(e
));
104 int uci_set_confdir(struct uci_context
*ctx
, const char *dir
)
109 UCI_ASSERT(ctx
, dir
!= NULL
);
111 cdir
= uci_strdup(ctx
, dir
);
112 if (ctx
->confdir
!= uci_confdir
)
118 __private
void uci_cleanup(struct uci_context
*ctx
)
120 struct uci_parse_context
*pctx
;
134 uci_free_package(&pctx
->package
);
143 uci_perror(struct uci_context
*ctx
, const char *str
)
145 uci_get_errorstr(ctx
, NULL
, str
);
149 uci_get_errorstr(struct uci_context
*ctx
, char **dest
, const char *prefix
)
151 static char error_info
[128];
155 "%s%s" /* function */
166 if ((err
< 0) || (err
>= UCI_ERR_LAST
))
167 err
= UCI_ERR_UNKNOWN
;
172 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
);
180 err
= asprintf(dest
, format
,
181 (prefix
? prefix
: ""), (prefix
? ": " : ""),
182 (ctx
->func
? ctx
->func
: ""), (ctx
->func
? ": " : ""),
188 strcat(error_info
, "\n");
189 fprintf(stderr
, format
,
190 (prefix
? prefix
: ""), (prefix
? ": " : ""),
191 (ctx
->func
? ctx
->func
: ""), (ctx
->func
? ": " : ""),
197 int uci_list_configs(struct uci_context
*ctx
, char ***list
)
200 UCI_ASSERT(ctx
, list
!= NULL
);
201 UCI_ASSERT(ctx
, ctx
->backend
&& ctx
->backend
->list_configs
);
202 *list
= ctx
->backend
->list_configs(ctx
);
206 int uci_commit(struct uci_context
*ctx
, struct uci_package
**package
, bool overwrite
)
208 struct uci_package
*p
;
210 UCI_ASSERT(ctx
, package
!= NULL
);
212 UCI_ASSERT(ctx
, p
!= NULL
);
213 UCI_ASSERT(ctx
, p
->backend
&& p
->backend
->commit
);
214 p
->backend
->commit(ctx
, package
, overwrite
);
218 int uci_load(struct uci_context
*ctx
, const char *name
, struct uci_package
**package
)
220 struct uci_package
*p
;
221 struct uci_element
*e
;
224 UCI_ASSERT(ctx
, ctx
->backend
&& ctx
->backend
->load
);
225 p
= ctx
->backend
->load(ctx
, name
);
226 uci_foreach_element(&ctx
->hooks
, e
) {
227 struct uci_hook
*h
= uci_to_hook(e
);
229 h
->ops
->load(h
->ops
, p
);
237 #ifdef UCI_PLUGIN_SUPPORT
239 __plugin
int uci_add_backend(struct uci_context
*ctx
, struct uci_backend
*b
)
241 struct uci_element
*e
;
244 e
= uci_lookup_list(&ctx
->backends
, b
->e
.name
);
246 UCI_THROW(ctx
, UCI_ERR_DUPLICATE
);
248 e
= uci_malloc(ctx
, sizeof(struct uci_backend
));
249 memcpy(e
, b
, sizeof(struct uci_backend
));
251 uci_list_add(&ctx
->backends
, &e
->list
);
255 __plugin
int uci_del_backend(struct uci_context
*ctx
, struct uci_backend
*b
)
257 struct uci_element
*e
, *tmp
;
261 e
= uci_lookup_list(&ctx
->backends
, b
->e
.name
);
262 if (!e
|| uci_to_backend(e
)->ptr
!= b
->ptr
)
263 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
264 b
= uci_to_backend(e
);
266 if (ctx
->backend
&& ctx
->backend
->ptr
== b
->ptr
)
267 ctx
->backend
= &uci_file_backend
;
269 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
270 struct uci_package
*p
= uci_to_package(e
);
275 if (p
->backend
->ptr
== b
->ptr
)
276 UCI_INTERNAL(uci_unload
, ctx
, p
);
279 uci_list_del(&b
->e
.list
);
287 int uci_set_backend(struct uci_context
*ctx
, const char *name
)
289 struct uci_element
*e
;
292 UCI_ASSERT(ctx
, name
!= NULL
);
293 e
= uci_lookup_list(&ctx
->backends
, name
);
295 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
296 ctx
->backend
= uci_to_backend(e
);
300 int uci_add_hook(struct uci_context
*ctx
, const struct uci_hook_ops
*ops
)
302 struct uci_element
*e
;
307 /* check for duplicate elements */
308 uci_foreach_element(&ctx
->hooks
, e
) {
311 return UCI_ERR_INVAL
;
314 h
= uci_alloc_element(ctx
, hook
, "", 0);
316 uci_list_init(&h
->e
.list
);
317 uci_list_add(&ctx
->hooks
, &h
->e
.list
);
322 int uci_remove_hook(struct uci_context
*ctx
, const struct uci_hook_ops
*ops
)
324 struct uci_element
*e
;
326 uci_foreach_element(&ctx
->hooks
, e
) {
327 struct uci_hook
*h
= uci_to_hook(e
);
329 uci_list_del(&e
->list
);
333 return UCI_ERR_NOTFOUND
;
336 int uci_load_plugin(struct uci_context
*ctx
, const char *filename
)
338 struct uci_plugin
*p
;
339 const struct uci_plugin_ops
*ops
;
343 dlh
= dlopen(filename
, RTLD_GLOBAL
|RTLD_NOW
);
345 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
347 ops
= dlsym(dlh
, "uci_plugin");
348 if (!ops
|| !ops
->attach
|| (ops
->attach(ctx
) != 0)) {
350 fprintf(stderr
, "No ops\n");
351 else if (!ops
->attach
)
352 fprintf(stderr
, "No attach\n");
354 fprintf(stderr
, "Other weirdness\n");
356 UCI_THROW(ctx
, UCI_ERR_INVAL
);
359 p
= uci_alloc_element(ctx
, plugin
, filename
, 0);
362 uci_list_add(&ctx
->plugins
, &p
->e
.list
);
367 static void uci_unload_plugin(struct uci_context
*ctx
, struct uci_plugin
*p
)
372 uci_free_element(&p
->e
);
375 int uci_load_plugins(struct uci_context
*ctx
, const char *pattern
)
381 pattern
= UCI_PREFIX
"/lib/uci_*.so";
383 memset(&gl
, 0, sizeof(gl
));
384 glob(pattern
, 0, NULL
, &gl
);
385 for (i
= 0; i
< gl
.gl_pathc
; i
++)
386 uci_load_plugin(ctx
, gl
.gl_pathv
[i
]);