a1fd92a1277713da3449bfb65e2bb84b1fdc57cc
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
));
61 memset(ctx
, 0, sizeof(struct uci_context
));
62 uci_list_init(&ctx
->root
);
63 uci_list_init(&ctx
->history_path
);
64 uci_list_init(&ctx
->backends
);
65 uci_list_init(&ctx
->hooks
);
66 uci_list_init(&ctx
->plugins
);
67 ctx
->flags
= UCI_FLAG_STRICT
| UCI_FLAG_SAVED_HISTORY
;
69 ctx
->confdir
= (char *) uci_confdir
;
70 ctx
->savedir
= (char *) uci_savedir
;
72 uci_list_add(&ctx
->backends
, &uci_file_backend
.e
.list
);
73 ctx
->backend
= &uci_file_backend
;
78 void uci_free_context(struct uci_context
*ctx
)
80 struct uci_element
*e
, *tmp
;
82 if (ctx
->confdir
!= uci_confdir
)
84 if (ctx
->savedir
!= uci_savedir
)
88 UCI_TRAP_SAVE(ctx
, ignore
);
89 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
90 struct uci_package
*p
= uci_to_package(e
);
93 uci_foreach_element_safe(&ctx
->history_path
, tmp
, e
) {
96 UCI_TRAP_RESTORE(ctx
);
97 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
98 uci_unload_plugin(ctx
, uci_to_plugin(e
));
106 int uci_set_confdir(struct uci_context
*ctx
, const char *dir
)
111 UCI_ASSERT(ctx
, dir
!= NULL
);
113 cdir
= uci_strdup(ctx
, dir
);
114 if (ctx
->confdir
!= uci_confdir
)
120 static void uci_cleanup(struct uci_context
*ctx
)
122 struct uci_parse_context
*pctx
;
136 uci_free_package(&pctx
->package
);
145 uci_perror(struct uci_context
*ctx
, const char *str
)
147 uci_get_errorstr(ctx
, NULL
, str
);
151 uci_get_errorstr(struct uci_context
*ctx
, char **dest
, const char *prefix
)
153 static char error_info
[128];
157 "%s%s" /* function */
168 if ((err
< 0) || (err
>= UCI_ERR_LAST
))
169 err
= UCI_ERR_UNKNOWN
;
174 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
);
182 err
= asprintf(dest
, format
,
183 (prefix
? prefix
: ""), (prefix
? ": " : ""),
184 (ctx
->func
? ctx
->func
: ""), (ctx
->func
? ": " : ""),
190 strcat(error_info
, "\n");
191 fprintf(stderr
, format
,
192 (prefix
? prefix
: ""), (prefix
? ": " : ""),
193 (ctx
->func
? ctx
->func
: ""), (ctx
->func
? ": " : ""),
199 int uci_list_configs(struct uci_context
*ctx
, char ***list
)
202 UCI_ASSERT(ctx
, list
!= NULL
);
203 UCI_ASSERT(ctx
, ctx
->backend
&& ctx
->backend
->list_configs
);
204 *list
= ctx
->backend
->list_configs(ctx
);
208 int uci_commit(struct uci_context
*ctx
, struct uci_package
**package
, bool overwrite
)
210 struct uci_package
*p
;
212 UCI_ASSERT(ctx
, package
!= NULL
);
214 UCI_ASSERT(ctx
, p
!= NULL
);
215 UCI_ASSERT(ctx
, p
->backend
&& p
->backend
->commit
);
216 p
->backend
->commit(ctx
, package
, overwrite
);
220 int uci_load(struct uci_context
*ctx
, const char *name
, struct uci_package
**package
)
222 struct uci_package
*p
;
223 struct uci_element
*e
;
226 UCI_ASSERT(ctx
, ctx
->backend
&& ctx
->backend
->load
);
227 p
= ctx
->backend
->load(ctx
, name
);
228 uci_foreach_element(&ctx
->hooks
, e
) {
229 struct uci_hook
*h
= uci_to_hook(e
);
231 h
->ops
->load(h
->ops
, p
);
239 #ifdef UCI_PLUGIN_SUPPORT
241 __plugin
int uci_add_backend(struct uci_context
*ctx
, struct uci_backend
*b
)
243 struct uci_element
*e
;
246 e
= uci_lookup_list(&ctx
->backends
, b
->e
.name
);
248 UCI_THROW(ctx
, UCI_ERR_DUPLICATE
);
250 e
= uci_malloc(ctx
, sizeof(struct uci_backend
));
251 memcpy(e
, b
, sizeof(struct uci_backend
));
253 uci_list_add(&ctx
->backends
, &e
->list
);
257 __plugin
int uci_del_backend(struct uci_context
*ctx
, struct uci_backend
*b
)
259 struct uci_element
*e
, *tmp
;
263 e
= uci_lookup_list(&ctx
->backends
, b
->e
.name
);
264 if (!e
|| uci_to_backend(e
)->ptr
!= b
->ptr
)
265 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
266 b
= uci_to_backend(e
);
268 if (ctx
->backend
&& ctx
->backend
->ptr
== b
->ptr
)
269 ctx
->backend
= &uci_file_backend
;
271 uci_foreach_element_safe(&ctx
->root
, tmp
, e
) {
272 struct uci_package
*p
= uci_to_package(e
);
277 if (p
->backend
->ptr
== b
->ptr
)
278 UCI_INTERNAL(uci_unload
, ctx
, p
);
281 uci_list_del(&b
->e
.list
);
289 int uci_set_backend(struct uci_context
*ctx
, const char *name
)
291 struct uci_element
*e
;
294 UCI_ASSERT(ctx
, name
!= NULL
);
295 e
= uci_lookup_list(&ctx
->backends
, name
);
297 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
298 ctx
->backend
= uci_to_backend(e
);
302 int uci_add_hook(struct uci_context
*ctx
, const struct uci_hook_ops
*ops
)
304 struct uci_element
*e
;
309 /* check for duplicate elements */
310 uci_foreach_element(&ctx
->hooks
, e
) {
313 return UCI_ERR_INVAL
;
316 h
= uci_alloc_element(ctx
, hook
, "", 0);
318 uci_list_init(&h
->e
.list
);
319 uci_list_add(&ctx
->hooks
, &h
->e
.list
);
324 int uci_remove_hook(struct uci_context
*ctx
, const struct uci_hook_ops
*ops
)
326 struct uci_element
*e
;
328 uci_foreach_element(&ctx
->hooks
, e
) {
329 struct uci_hook
*h
= uci_to_hook(e
);
331 uci_list_del(&e
->list
);
335 return UCI_ERR_NOTFOUND
;
338 int uci_load_plugin(struct uci_context
*ctx
, const char *filename
)
340 struct uci_plugin
*p
;
341 const struct uci_plugin_ops
*ops
;
345 dlh
= dlopen(filename
, RTLD_GLOBAL
|RTLD_NOW
);
347 UCI_THROW(ctx
, UCI_ERR_NOTFOUND
);
349 ops
= dlsym(dlh
, "uci_plugin");
350 if (!ops
|| !ops
->attach
|| (ops
->attach(ctx
) != 0)) {
352 fprintf(stderr
, "No ops\n");
353 else if (!ops
->attach
)
354 fprintf(stderr
, "No attach\n");
356 fprintf(stderr
, "Other weirdness\n");
358 UCI_THROW(ctx
, UCI_ERR_INVAL
);
361 p
= uci_alloc_element(ctx
, plugin
, filename
, 0);
364 uci_list_add(&ctx
->plugins
, &p
->e
.list
);
369 static void uci_unload_plugin(struct uci_context
*ctx
, struct uci_plugin
*p
)
374 uci_free_element(&p
->e
);
377 int uci_load_plugins(struct uci_context
*ctx
, const char *pattern
)
383 pattern
= UCI_PREFIX
"/lib/uci_*.so";
385 memset(&gl
, 0, sizeof(gl
));
386 glob(pattern
, 0, NULL
, &gl
);
387 for (i
= 0; i
< gl
.gl_pathc
; i
++)
388 uci_load_plugin(ctx
, gl
.gl_pathv
[i
]);