libgluonutil: merge domain and site configs
This commit is contained in:
parent
a73ae6c16d
commit
0189f350f9
@ -16,7 +16,7 @@ define Package/libgluonutil
|
||||
SECTION:=libs
|
||||
CATEGORY:=Libraries
|
||||
TITLE:=Gluon utility library
|
||||
DEPENDS:=+libjson-c
|
||||
DEPENDS:=+libjson-c +libuci
|
||||
endef
|
||||
|
||||
CMAKE_OPTIONS += \
|
||||
|
@ -7,14 +7,15 @@ project(libgluonutil C)
|
||||
set(LIBDIR "lib${LIB_SUFFIX}")
|
||||
|
||||
find_package(JSON_C REQUIRED)
|
||||
find_package(UCI REQUIRED)
|
||||
|
||||
set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS _GNU_SOURCE)
|
||||
|
||||
add_library(gluonutil SHARED libgluonutil.c)
|
||||
set_property(TARGET gluonutil PROPERTY COMPILE_FLAGS "-Wall -std=c99 ${JSON_C_CFLAGS_OTHER}")
|
||||
set_property(TARGET gluonutil PROPERTY LINK_FLAGS "${JSON_C_LDFLAGS_OTHER}")
|
||||
set_property(TARGET gluonutil APPEND PROPERTY INCLUDE_DIRECTORIES ${JSON_C_INCLUDE_DIR})
|
||||
target_link_libraries(gluonutil ${JSON_C_LIBRARIES})
|
||||
set_property(TARGET gluonutil APPEND PROPERTY INCLUDE_DIRECTORIES ${JSON_C_INCLUDE_DIR} ${UCI_INCLUDE_DIR})
|
||||
target_link_libraries(gluonutil ${JSON_C_LIBRARIES} ${UCI_LIBRARIES})
|
||||
install(TARGETS gluonutil
|
||||
ARCHIVE DESTINATION ${LIBDIR}
|
||||
LIBRARY DESTINATION ${LIBDIR}
|
||||
|
21
package/libgluonutil/src/FindUCI.cmake
Normal file
21
package/libgluonutil/src/FindUCI.cmake
Normal file
@ -0,0 +1,21 @@
|
||||
# UCI_FOUND - true if library and headers were found
|
||||
# UCI_INCLUDE_DIRS - include directories
|
||||
# UCI_LIBRARIES - library directories
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_UCI QUIET uci)
|
||||
|
||||
find_path(UCI_INCLUDE_DIR uci.h
|
||||
HINTS ${PC_UCI_INCLUDEDIR} ${PC_UCI_INCLUDE_DIRS})
|
||||
|
||||
find_library(UCI_LIBRARY NAMES uci libuci
|
||||
HINTS ${PC_UCI_LIBDIR} ${PC_UCI_LIBRARY_DIRS})
|
||||
|
||||
set(UCI_LIBRARIES ${UCI_LIBRARY})
|
||||
set(UCI_INCLUDE_DIRS ${UCI_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(UCI DEFAULT_MSG UCI_LIBRARY UCI_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(UCI_INCLUDE_DIR UCI_LIBRARY)
|
@ -31,7 +31,41 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <uci.h>
|
||||
|
||||
/**
|
||||
* Merges two JSON objects
|
||||
*
|
||||
* On conflicts, object a will be preferred.
|
||||
*
|
||||
* Internally, this functions merges all entries from object a into object b,
|
||||
* so merging a small object a with a big object b is faster than vice-versa.
|
||||
*/
|
||||
static struct json_object * merge_json(struct json_object *a, struct json_object *b) {
|
||||
if (!json_object_is_type(a, json_type_object) || !json_object_is_type(b, json_type_object)) {
|
||||
json_object_put(b);
|
||||
return a;
|
||||
}
|
||||
|
||||
json_object_object_foreach(a, key, val_a) {
|
||||
struct json_object *val_b;
|
||||
|
||||
json_object_get(val_a);
|
||||
|
||||
if (!json_object_object_get_ex(b, key, &val_b)) {
|
||||
json_object_object_add(b, key, val_a);
|
||||
continue;
|
||||
}
|
||||
|
||||
json_object_get(val_b);
|
||||
|
||||
json_object_object_add(b, key, merge_json(val_a, val_b));
|
||||
}
|
||||
|
||||
json_object_put(a);
|
||||
return b;
|
||||
}
|
||||
|
||||
char * gluonutil_read_line(const char *filename) {
|
||||
FILE *f = fopen(filename, "r");
|
||||
@ -140,7 +174,122 @@ bool gluonutil_get_node_prefix6(struct in6_addr *prefix) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char * get_selected_domain_code(struct json_object * base) {
|
||||
char * domain_path_fmt = "/lib/gluon/domains/%s.json";
|
||||
char domain_path[strlen(domain_path_fmt) + 256];
|
||||
const char * domain_code;
|
||||
|
||||
struct uci_context *ctx = uci_alloc_context();
|
||||
if (!ctx)
|
||||
goto uci_fail;
|
||||
|
||||
ctx->flags &= ~UCI_FLAG_STRICT;
|
||||
|
||||
struct uci_package *p;
|
||||
if (uci_load(ctx, "gluon", &p))
|
||||
goto uci_fail;
|
||||
|
||||
struct uci_section *s = uci_lookup_section(ctx, p, "system");
|
||||
if (!s)
|
||||
goto uci_fail;
|
||||
|
||||
domain_code = uci_lookup_option_string(ctx, s, "domain_code");
|
||||
|
||||
if (!domain_code)
|
||||
goto uci_fail;
|
||||
|
||||
snprintf(domain_path, sizeof domain_path, domain_path_fmt, domain_code);
|
||||
|
||||
if (access(domain_path, R_OK) != -1) {
|
||||
// ${domain_code}.conf exists and is accessible
|
||||
char * domain_code_cpy = strndup(domain_code, 256); // copy before free
|
||||
uci_free_context(ctx);
|
||||
return domain_code_cpy;
|
||||
}
|
||||
|
||||
uci_fail:
|
||||
if (ctx)
|
||||
uci_free_context(ctx);
|
||||
|
||||
json_object * default_domain_code;
|
||||
|
||||
// it's okay to pass base == NULL to json_object_object_get_ex()
|
||||
if (!json_object_object_get_ex(base, "default_domain_code", &default_domain_code))
|
||||
return NULL;
|
||||
|
||||
domain_code = json_object_get_string(default_domain_code);
|
||||
|
||||
if (!domain_code)
|
||||
return NULL;
|
||||
|
||||
// the gluon build environment should ensure, that this filename exists,
|
||||
// but to be sure, we check here again.
|
||||
snprintf(domain_path, sizeof domain_path, domain_path_fmt, domain_code);
|
||||
|
||||
if (access(domain_path, R_OK) == -1)
|
||||
return NULL;
|
||||
|
||||
// create a copy so site could be freed before domain_code
|
||||
return strndup(domain_code, 256);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get selected domain code
|
||||
*
|
||||
* - If NULL is passed to the site parameter, internally only the base part
|
||||
* (without domain config) is loaded, which is more efficient than calling
|
||||
* gluonutil_load_site_config() for this job only. Nevertheless if you already
|
||||
* have an instance of a site object then you should pass it here.
|
||||
* - Returned domain code string has to be freed after use
|
||||
* - Returns NULL in case of error
|
||||
* - If a domain code is returned, it's ensured that the corresponding config
|
||||
* in /lib/gluon/domains/ exists.
|
||||
*/
|
||||
char * gluonutil_get_selected_domain_code(struct json_object * site) {
|
||||
if (site)
|
||||
// If the user already has allocated a whole site object, it makes no sense
|
||||
// to load the base object. Taking the site object (merged from domain and
|
||||
// base) should be fine here.
|
||||
return get_selected_domain_code(site);
|
||||
|
||||
// load base
|
||||
struct json_object * base = json_object_from_file("/lib/gluon/site.json");
|
||||
|
||||
if (!base)
|
||||
return NULL;
|
||||
|
||||
return get_selected_domain_code(base);
|
||||
}
|
||||
|
||||
struct json_object * gluonutil_load_site_config(void) {
|
||||
return json_object_from_file("/lib/gluon/site.json");
|
||||
// load base
|
||||
struct json_object * base = json_object_from_file("/lib/gluon/site.json");
|
||||
|
||||
if (!base)
|
||||
return NULL;
|
||||
|
||||
// load domain
|
||||
char * domain_path_fmt = "/lib/gluon/domains/%s.json";
|
||||
char domain_path[strlen(domain_path_fmt) + 256];
|
||||
char * domain_code = get_selected_domain_code(base);
|
||||
|
||||
if (!domain_code) {
|
||||
// something went horribly wrong here
|
||||
json_object_put(base); // free base
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(domain_path, sizeof domain_path, domain_path_fmt, domain_code);
|
||||
|
||||
free(domain_code);
|
||||
|
||||
struct json_object * domain = json_object_from_file(domain_path);
|
||||
|
||||
if (!domain) {
|
||||
json_object_put(base);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// finally merge them
|
||||
return merge_json(domain, base);
|
||||
}
|
||||
|
@ -42,4 +42,18 @@ struct json_object * gluonutil_wrap_and_free_string(char *str);
|
||||
|
||||
struct json_object * gluonutil_load_site_config(void);
|
||||
|
||||
/**
|
||||
* Get selected domain code
|
||||
*
|
||||
* - If NULL is passed to the site parameter, internally only the base part
|
||||
* (without domain config) is loaded, which is more efficient than calling
|
||||
* gluonutil_load_site_config() for this job only. Nevertheless if you already
|
||||
* have an instance of a site object then you should pass it here.
|
||||
* - Returned domain code string has to be freed after use
|
||||
* - Returns NULL in case of error
|
||||
* - If a domain code is returned, it's ensured that the corresponding config
|
||||
* in /lib/gluon/domains/ exists.
|
||||
*/
|
||||
char * gluonutil_get_selected_domain_code(struct json_object * site);
|
||||
|
||||
#endif /* _LIBGLUON_LIBGLUON_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user