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