diff mbox series

[4/5] parser: introduce links in sw-description

Message ID 20181101170635.13493-4-sbabic@denx.de
State Changes Requested
Headers show
Series [1/5] Factorize function to count elements in array of strings | expand

Commit Message

Stefano Babic Nov. 1, 2018, 5:06 p.m. UTC
There are a lot of use cases when special configurations are needed.
Current sw-description requires that each entry is full described and
does not allow to factorize some parts. This means that in most cases
entries are duplicated multiple times even if changes are minimal
between sections.

This patch introduce links for the root node. If the node is a string
instead of an object, it is interpreted as new link to be follow.
The parser tries to follow the links recursively (a maximum number of 10
links is introduce to avoid deadlocks).

The patch factorizes how to call find_node() for the specific parser.
Instead of using two mechanism (a formatted sting and an array of
strings) for libconfig and json, use an array of strings for both.

Signed-off-by: Stefano Babic <sbabic@denx.de>
---
 corelib/parsing_library.c           |  33 ++++
 corelib/parsing_library_libconfig.c |  73 +++++++++
 corelib/parsing_library_libjson.c   |  44 +++++
 include/parselib.h                  |   8 +
 parser/parser.c                     | 242 ++++++++++++++--------------
 5 files changed, 276 insertions(+), 124 deletions(-)
diff mbox series

Patch

diff --git a/corelib/parsing_library.c b/corelib/parsing_library.c
index 00463a7..5a8445a 100644
--- a/corelib/parsing_library.c
+++ b/corelib/parsing_library.c
@@ -153,6 +153,39 @@  int exist_field_string(parsertype p, void *e, const char *path)
 	return 0;
 }
 
+bool find_root(parsertype p, void *root, const char **nodes)
+{
+
+	switch (p) {
+	case LIBCFG_PARSER:
+		return find_root_libconfig((config_t *)root, nodes, MAX_LINKS_DEPTH);
+
+	case JSON_PARSER:
+		return find_root_json((json_object *)root, nodes, MAX_LINKS_DEPTH);
+	default:
+		(void)root;
+		(void)nodes;
+	}
+
+	return false;
+}
+
+void *get_node(parsertype p, void *root, const char **nodes)
+{
+
+	switch (p) {
+	case LIBCFG_PARSER:
+		return get_node_libconfig((config_t *)root, nodes);
+	case JSON_PARSER:
+		return get_node_json((json_object *)root, nodes);
+	default:
+		(void)root;
+		(void)nodes;
+	}
+
+	return NULL;
+}
+
 void get_hash_value(parsertype p, void *elem, unsigned char *hash)
 {
 	char hash_ascii[80];
diff --git a/corelib/parsing_library_libconfig.c b/corelib/parsing_library_libconfig.c
index 415116b..5763416 100644
--- a/corelib/parsing_library_libconfig.c
+++ b/corelib/parsing_library_libconfig.c
@@ -13,12 +13,34 @@ 
 #include <errno.h>
 #include <sys/stat.h>
 #include <assert.h>
+#include <stdbool.h>
 #include "generated/autoconf.h"
 #include "bsdqueue.h"
 #include "util.h"
 #include "swupdate.h"
 #include "parselib.h"
 
+static void path_libconfig(const char **nodes, char *root, unsigned int rootsize)
+{
+    const char **node;
+    int nbytes, left;
+    char *buf;
+    const char *concat;
+    bool first=true;
+
+    root[0] = '\0';
+
+    for (node = nodes, buf = root, left = rootsize; *node != NULL; node++) {
+        concat = first ? "" : ".";
+        nbytes = snprintf(buf, left, "%s%s", concat, *node);
+        buf += nbytes;
+        left -= nbytes;
+        first = false;
+        if (left ==0)
+            break;
+    }
+}
+
 void get_value_libconfig(const config_setting_t *e, void *dest)
 {
 	int type = config_setting_type(e);
@@ -108,3 +130,54 @@  const char *get_field_string_libconfig(config_setting_t *e, const char *path)
 
 	return NULL;
 }
+
+void *get_node_libconfig(config_t *cfg, const char **nodes)
+{
+	config_setting_t *setting;
+	char root[1024];
+
+	path_libconfig(nodes, root, sizeof(root));
+	setting = config_lookup(cfg, root);
+	if (setting)
+		return setting;
+
+	return NULL;
+}
+
+bool find_root_libconfig(config_t *cfg, const char **nodes, unsigned int depth)
+{
+	config_setting_t *elem;
+	const char *str;
+	char root[1024];
+	char **tmp = NULL;
+	bool result = false;
+
+	/*
+	 * check for deadlock links, block recursion
+	 */
+	if (!(--depth))
+		return false;
+
+	path_libconfig(nodes, root, sizeof(root));
+
+	/*
+	 * If this is root node for the device,
+	 * it is a group and lenght is not 0.
+	 * If it is a link, follow it
+	 */
+	elem = config_lookup(cfg, root);
+
+	if (elem && config_setting_length(elem) > 0)
+		return true;
+
+	if (!elem || config_setting_type(elem) != CONFIG_TYPE_STRING)
+		return false;
+	if ((str = config_setting_get_string(elem)) != NULL) {
+		if (!set_find_path(nodes, str, tmp))
+			return false;
+		result = find_root_libconfig(cfg, nodes, depth);
+		free_string_array(tmp);
+		return result;
+	}
+	return false;
+}
diff --git a/corelib/parsing_library_libjson.c b/corelib/parsing_library_libjson.c
index b1f5775..8cc3a4b 100644
--- a/corelib/parsing_library_libjson.c
+++ b/corelib/parsing_library_libjson.c
@@ -7,6 +7,7 @@ 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdbool.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -179,4 +180,47 @@  char *json_get_data_url(json_object *json_root, const char *key)
 		   : strndup(json_object_get_string(json_data), MAX_URL_LENGTH);
 }
 
+bool find_root_json(json_object *root, const char **nodes, unsigned int depth)
+{
+	json_object *node;
+	enum json_type type;
+	char **tmp = NULL;
+	bool result;
+	const char *str;
+
+	/*
+	 * check for deadlock links, block recursion
+	 */
+	if (!(--depth))
+		return false;
+
+	node = find_json_recursive_node(root, nodes);
+
+	if (node) {
+		type = json_object_get_type(node);
+
+		switch (type) {
+		case json_type_object:
+		case json_type_array:
+			return true;
+		case json_type_string:
+			str = json_object_get_string(node);
+			if (!set_find_path(nodes, str, tmp))
+				return false;
+			result = find_root_json(root, nodes, depth);
+			free_string_array(tmp);
+			return result;
+		default:
+			return false;
+		}
+	}
+
+	return false;
+}
+
+void *get_node_json(json_object *root, const char **nodes)
+{
+	return find_json_recursive_node(root, nodes);
+}
+
 
diff --git a/include/parselib.h b/include/parselib.h
index 2fca3b5..61ebce9 100644
--- a/include/parselib.h
+++ b/include/parselib.h
@@ -39,6 +39,8 @@  void *get_child_libconfig(void *e, const char *name);
 void iterate_field_libconfig(config_setting_t *e, iterate_callback cb,
 			     void *data);
 const char *get_field_string_libconfig(config_setting_t *e, const char *path);
+bool find_root_libconfig(config_t *cfg, const char **nodes, unsigned int depth);
+void *get_node_libconfig(config_t *cfg, const char **nodes);
 
 #else
 #define config_setting_get_elem(a,b)	(NULL)
@@ -49,6 +51,8 @@  const char *get_field_string_libconfig(config_setting_t *e, const char *path);
 #define get_child_libconfig(e, name)		(NULL)
 #define iterate_field_libconfig(e, cb, data)	{ }
 #define get_field_cfg(e, path, dest)
+#define find_root_libconfig(cfg, nodes, depth)		(false)
+#define get_node_libconfig(cfg, nodes)		(NULL)
 #endif
 
 #ifdef CONFIG_JSON
@@ -65,6 +69,8 @@  const char *json_get_value(struct json_object *json_root,
 			   const char *key);
 json_object *json_get_path_key(json_object *json_root, const char **json_path);
 char *json_get_data_url(json_object *json_root, const char *key);
+bool find_root_json(json_object *root, const char **nodes, unsigned int depth);
+void *get_node_json(json_object *root, const char **nodes);
 
 #else
 #define find_node_json(a, b, c)		(NULL)
@@ -75,6 +81,8 @@  char *json_get_data_url(json_object *json_root, const char *key);
 #define json_object_object_get_ex(a,b,c) (0)
 #define json_object_array_get_idx(a, b)	(0)
 #define json_object_array_length(a)	(0)
+#define find_root_json(root, nodes, depth)	(false)
+#define get_node_json(root, nodes)	(NULL)
 #endif
 
 typedef int (*settings_callback)(void *elem, void *data);
diff --git a/parser/parser.c b/parser/parser.c
index 19181d1..4588f5d 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -11,6 +11,7 @@ 
 #include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <stdbool.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <sys/stat.h>
@@ -29,115 +30,136 @@ 
 #define NODEROOT (!strlen(CONFIG_PARSERROOT) ? \
 			"software" : CONFIG_PARSERROOT)
 
-#ifdef CONFIG_LIBCONFIG
-static config_setting_t *find_node_libconfig(config_t *cfg,
-					const char *field, struct swupdate_cfg *swcfg)
+#if defined(CONFIG_LIBCONFIG) || defined(CONFIG_JSON)
+
+static bool path_append(const char **nodes, const char *field)
 {
-	config_setting_t *setting;
-	struct hw_type *hardware;
+	unsigned int count = 0;
+
+	count = count_string_array(nodes);
+
+	if (count >= MAX_PARSED_NODES)
+		return false;
+
+	nodes[count++] = field;
+	nodes[count] = NULL;
 
-	char node[1024];
+	return true;
+}
+
+static void *find_node_common(parsertype p, void *root, const char *field,
+			struct swupdate_cfg *swcfg, bool followlinks)
+{
+
+	struct hw_type *hardware;
+	const char **nodes;
+	int i;
 
 	if (!field)
 		return NULL;
 
 	hardware = &swcfg->hw;
 
-	if (strlen(swcfg->running_mode) && strlen(swcfg->software_set)) {
-		/* Try with both software set and board name */
-		if (strlen(hardware->boardname)) {
-			snprintf(node, sizeof(node), "%s.%s.%s.%s.%s",
-				NODEROOT,
-				hardware->boardname,
-				swcfg->software_set,
-				swcfg->running_mode,
-				field);
-			setting = config_lookup(cfg, node);
-			if (setting)
-				return setting;
+	nodes = (const char **)calloc(MAX_PARSED_NODES, sizeof(*nodes));
+
+	for (i = 0; i < 4; i++) {
+		nodes[0] = NULL;
+		switch(i) {
+		case 0:
+	        	if (strlen(swcfg->running_mode) && strlen(swcfg->software_set) &&
+		        		strlen(hardware->boardname)) {
+				nodes[0] = NODEROOT;
+				nodes[1] = hardware->boardname;
+				nodes[2] = swcfg->software_set;
+				nodes[3] = swcfg->running_mode;
+				nodes[4] = NULL;
+			}
+			break;
+		case 1:
+			/* try with software set and mode */
+			if (strlen(swcfg->running_mode) && strlen(swcfg->software_set)) {
+				nodes[0] = NODEROOT;
+				nodes[1] = swcfg->software_set;
+				nodes[2] = swcfg->running_mode;
+				nodes[3] = NULL;
+			}
+			break;
+		case 2:
+			/* Try with board name */
+			if (strlen(hardware->boardname)) {
+				nodes[0] = NODEROOT;
+				nodes[1] = hardware->boardname;
+				nodes[2] = NULL;
+			}
+			break;
+		case 3:
+			/* Fall back without board entry */
+			nodes[0] = NODEROOT;
+			nodes[1] = NULL;
+			break;
 		}
-		/* still here, try with software set and mode */
-		snprintf(node, sizeof(node), "%s.%s.%s.%s",
-			NODEROOT,
-			swcfg->software_set,
-			swcfg->running_mode,
-			field);
-		setting = config_lookup(cfg, node);
-		if (setting)
-			return setting;
 
-	}
+		/*
+		 * If conditions are not set,
+		 * skip to the next option
+		 */
+		if (!nodes[0])
+			continue;
 
-	/* Try with board name */
-	if (strlen(hardware->boardname)) {
-		snprintf(node, sizeof(node), "%s.%s.%s",
-			NODEROOT,
-			hardware->boardname,
-			field);
-		setting = config_lookup(cfg, node);
-		if (setting)
-			return setting;
+		if (find_root(p, root, nodes)) {
+			void *node = NULL;
+			if (!path_append(nodes, field))
+				return NULL;
+			if (!followlinks) {
+				node = get_node(p, root, nodes);
+			} else {
+				if (find_root(p, root, nodes))
+					node = get_node(p, root, nodes);
+			}
+
+			if (node) {
+				free(nodes);
+				return node;
+			}
+		}
 	}
-	/* Fall back without board entry */
-	snprintf(node, sizeof(node), "%s.%s",
-		NODEROOT,
-		field);
-	return config_lookup(cfg, node);
+
+	free(nodes);
+
+	return NULL;
 }
 
-#endif
+static void *find_node_element(parsertype p, void *root, const char *field,
+			struct swupdate_cfg *swcfg)
+{
+	return find_node_common(p, root, field, swcfg, false);
+}
 
-#ifdef CONFIG_JSON
-static json_object *find_node_json(json_object *root, const char *node,
+static void *find_node_group(parsertype p, void *root, const char *field,
 			struct swupdate_cfg *swcfg)
 {
-	json_object *jnode = NULL;
-	const char *simple_nodes[] = {NODEROOT, node, NULL};
-	struct hw_type *hardware;
+	return find_node_common(p, root, field, swcfg, true);
+}
 
-	hardware = &swcfg->hw;
+static bool get_common_fields(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
+{
 
-	if (strlen(swcfg->running_mode) && strlen(swcfg->software_set)) {
-		if (strlen(hardware->boardname)) {
-			const char *nodes[] = {NODEROOT, hardware->boardname,
-				swcfg->software_set, swcfg->running_mode,
-				node, NULL};
-			jnode = find_json_recursive_node(root, nodes);
-			if (jnode)
-				return jnode;
-		} else {
-			const char *nodes[] = {NODEROOT, swcfg->software_set,
-				swcfg->running_mode, node, NULL};
-			jnode = find_json_recursive_node(root, nodes);
-			if (jnode)
-				return jnode;
-		}
-	}
+	void *setting;
 
-	if (strlen(hardware->boardname)) {
-		const char *nodes[] = {NODEROOT, hardware->boardname, node,
-					NULL};
-		jnode = find_json_recursive_node(root, nodes);
-		if (jnode)
-			return jnode;
+	if((setting = find_node_element(p, cfg, "version", swcfg)) == NULL) {
+		ERROR("Missing version in configuration file");
+		return false;
 	}
+	
+	GET_FIELD_STRING(p, setting, NULL, swcfg->version);
+	TRACE("Version %s", swcfg->version);
 
-	return find_json_recursive_node(root, simple_nodes);
-}
-#endif
-
-#if defined(CONFIG_LIBCONFIG) || defined(CONFIG_JSON)
-static void *find_node(parsertype p, void *root, const char *node,
-			struct swupdate_cfg *swcfg)
-{
-	switch (p) {
-	case LIBCFG_PARSER:
-		return find_node_libconfig((config_t *)root, node, swcfg);
-	case JSON_PARSER:
-		return find_node_json((json_object *)root, node, swcfg);
+	if((setting = find_node_element(p, cfg, "description", swcfg)) != NULL) {
+		GET_FIELD_STRING(p, setting, NULL, swcfg->description);
+		TRACE("Description %s", swcfg->description);
 	}
 
-	return NULL;
+	return true;
 }
 
 static void add_properties_cb(const char *name, const char *value, void *data)
@@ -175,7 +197,7 @@  static int parse_hw_compatibility(parsertype p, void *cfg, struct swupdate_cfg *
 	char s[SWUPDATE_GENERAL_STRING_SIZE];
 	struct hw_type *hwrev;
 
-	setting = find_node(p, cfg, "hardware-compatibility", swcfg);
+	setting = find_node_element(p, cfg, "hardware-compatibility", swcfg);
 	if (setting == NULL) {
 		ERROR("HW compatibility not found");
 		return -1;
@@ -273,7 +295,7 @@  static int parse_partitions(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
 	int count, i;
 	struct img_type *partition;
 
-	setting = find_node(p, cfg, "partitions", swcfg);
+	setting = find_node_group(p, cfg, "partitions", swcfg);
 
 	if (setting == NULL)
 		return 0;
@@ -330,7 +352,7 @@  static int parse_scripts(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lu
 	int count, i, skip;
 	struct img_type *script;
 
-	setting = find_node(p, cfg, "scripts", swcfg);
+	setting = find_node_group(p, cfg, "scripts", swcfg);
 
 	if (setting == NULL)
 		return 0;
@@ -401,10 +423,10 @@  static int parse_bootloader(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
 	char name[32];
 	char value[255];
 
-	setting = find_node(p, cfg, "uboot", swcfg);
+	setting = find_node_group(p, cfg, "uboot", swcfg);
 
 	if (setting == NULL) {
-		setting = find_node(p, cfg, "bootenv", swcfg);
+		setting = find_node_group(p, cfg, "bootenv", swcfg);
 		if (setting == NULL)
 			return 0;
 	}
@@ -468,7 +490,7 @@  static int parse_images(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lua
 	int count, i, skip;
 	struct img_type *image;
 
-	setting = find_node(p, cfg, "images", swcfg);
+	setting = find_node_group(p, cfg, "images", swcfg);
 
 	if (setting == NULL)
 		return 0;
@@ -550,7 +572,7 @@  static int parse_files(parsertype p, void *cfg, struct swupdate_cfg *swcfg, lua_
 	int count, i, skip;
 	struct img_type *file;
 
-	setting = find_node(p, cfg, "files", swcfg);
+	setting = find_node_group(p, cfg, "files", swcfg);
 
 	if (setting == NULL)
 		return 0;
@@ -625,7 +647,7 @@  static int parser(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
 	int ret;
 
 	swcfg->embscript = NULL;
-	scriptnode = find_node(p, cfg, "embedded-script", swcfg);
+	scriptnode = find_node_element(p, cfg, "embedded-script", swcfg);
 	if (scriptnode) {
 		TRACE("Getting script");
 		swcfg->embscript = get_field_string(p, scriptnode, NULL);
@@ -672,11 +694,8 @@  static int parser(parsertype p, void *cfg, struct swupdate_cfg *swcfg)
 int parse_cfg (struct swupdate_cfg *swcfg, const char *filename)
 {
 	config_t cfg;
-	const char *str;
-	char node[128];
 	parsertype p = LIBCFG_PARSER;
 	int ret;
-	config_setting_t *setting;
 
 	memset(&cfg, 0, sizeof(cfg));
 	config_init(&cfg);
@@ -694,24 +713,8 @@  int parse_cfg (struct swupdate_cfg *swcfg, const char *filename)
 		return -1;
 	}
 
-	if((setting = find_node(p, &cfg, "version", swcfg)) == NULL) {
-		ERROR("Missing version in configuration file");
+	if (!get_common_fields(p, &cfg, swcfg))
 		return -1;
-	} else {
-		GET_FIELD_STRING(p, setting, NULL, swcfg->version);
-		TRACE("Version %s", swcfg->version);
-	}
-
-	if((setting = find_node(p, &cfg, "description", swcfg)) != NULL) {
-		GET_FIELD_STRING(p, setting, NULL, swcfg->description);
-		TRACE("Description %s", swcfg->description);
-	}
-
-	snprintf(node, sizeof(node), "%s.embedded-script",
-			NODEROOT);
-	if (config_lookup_string(&cfg, node, &str)) {
-		TRACE("Found Lua Software:\n%s", str);
-	}
 
 	ret = parser(p, &cfg, swcfg);
 
@@ -734,7 +737,7 @@  int parse_json(struct swupdate_cfg *swcfg, const char *filename)
 	struct stat stbuf;
 	unsigned int size;
 	char *string;
-	json_object *cfg, *setting;
+	json_object *cfg;
 	parsertype p = JSON_PARSER;
 
 	/* Read the file. If there is an error, report it and exit. */
@@ -764,18 +767,9 @@  int parse_json(struct swupdate_cfg *swcfg, const char *filename)
 		return -1;
 	}
 
-	if((setting = find_node(p, cfg, "version", swcfg)) == NULL) {
-		ERROR("Missing version in configuration file");
+	if (!get_common_fields(p, cfg, swcfg)) {
 		free(string);
 		return -1;
-	} else {
-		GET_FIELD_STRING(p, setting, NULL, swcfg->version);
-		TRACE("Version %s", swcfg->version);
-	}
-
-	if((setting = find_node(p, cfg, "description", swcfg)) != NULL) {
-		GET_FIELD_STRING(p, setting, NULL, swcfg->description);
-		TRACE("Description %s", swcfg->description);
 	}
 
 	ret = parser(p, cfg, swcfg);