[RFC PATCH 2/7] lib: Add libxml2 support

Samuel Mendoza-Jonas sam.mj at au1.ibm.com
Mon Nov 30 14:13:15 AEDT 2015


Definitions for attribute overrides on OpenPower machines will be read
from a static XML file written into the Skiroot initramfs. Add basic
support to parse an XML file using libxml2.

TODO: Update build rules to make libxml2 support optional
Signed-off-by: Samuel Mendoza-Jonas <sam.mj at au1.ibm.com>
---
 lib/Makefile.am   |  11 +++-
 lib/types/types.c |  63 ++++++++++++++++++++++
 lib/types/types.h |   3 ++
 lib/xml/xml.c     | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/xml/xml.h     |  19 +++++++
 5 files changed, 249 insertions(+), 2 deletions(-)
 create mode 100644 lib/xml/xml.c
 create mode 100644 lib/xml/xml.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
index a2421a5..1d55914 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -18,7 +18,11 @@ noinst_LTLIBRARIES += $(core_lib)
 
 lib_libpbcore_la_CPPFLAGS = \
 	$(AM_CPPFLAGS) \
-	-DPREFIX='"$(prefix)"'
+	-DPREFIX='"$(prefix)"' \
+	`xml2-config --cflags`
+
+lib_libpbcore_la_LDFLAGS = \
+	`xml2-config --libs`
 
 lib_libpbcore_la_SOURCES = \
 	lib/file/file.h \
@@ -41,6 +45,7 @@ lib_libpbcore_la_SOURCES = \
 	lib/process/process.h \
 	lib/types/types.c \
 	lib/types/types.h \
+	lib/types/types.c \
 	lib/talloc/talloc.c \
 	lib/talloc/talloc.h \
 	lib/system/system.c \
@@ -48,4 +53,6 @@ lib_libpbcore_la_SOURCES = \
 	lib/url/url.c \
 	lib/url/url.h \
 	lib/util/util.c \
-	lib/util/util.h
+	lib/util/util.h \
+	lib/xml/xml.c \
+	lib/xml/xml.h
diff --git a/lib/types/types.c b/lib/types/types.c
index 63045e1..818c7b7 100644
--- a/lib/types/types.c
+++ b/lib/types/types.c
@@ -1,6 +1,8 @@
 #include <string.h>
 #include <types/types.h>
 #include <i18n/i18n.h>
+#include <talloc/talloc.h>
+#include <log/log.h>
 
 const char *ipmi_bootdev_display_name(enum ipmi_bootdev bootdev)
 {
@@ -75,3 +77,64 @@ enum device_type find_device_type(const char *str)
 
 	return DEVICE_TYPE_UNKNOWN;
 }
+/* Hostboot debugging */
+
+void dump_firmware_config(struct firmware_option *opts,
+				 int n_opts, int level)
+{
+	unsigned int j;
+	int i;
+	char *prefix;
+
+	prefix = talloc_array(opts, char, level + 2);
+	prefix[0] = '>';
+	if (level) memset(&prefix[1], '\t', level);
+	prefix[level + 1] = '\0';
+
+	for (i = 0; i < n_opts; i++) {
+		if (opts[i].type == FIRMWARE_GROUP ) {
+			pb_log("%sGroup: %s\n", prefix, opts[i].name);
+			dump_firmware_config(opts[i].opts,
+					     opts[i].n_opts, level + 1);
+			continue;
+		}
+
+		struct firmware_attr *attr = opts[i].attr;
+		if (opts[i].name)
+			pb_log("%sAttribute: %s\n", prefix, opts[i].name);
+		else
+			pb_log("%sUnnamed Attribute\n", prefix);
+		pb_log("%sid: %s\n", prefix, attr->id);
+		pb_log("%snumeric-id: %s\n", prefix, attr->numeric_id);
+		pb_log("%ssigned: %s\n", prefix, attr->is_signed ? "true" : "false");
+		pb_log("%ssize: %x\n", prefix, attr->size);
+
+		pb_log("%sdefault-val: %s\n", prefix, attr->value);
+		pb_log("%sdisplay-name: %s\n", prefix, attr->display_name);
+		pb_log("%sdescription: %s\n", prefix, attr->description);
+
+		if (attr->limit == LIMIT_NONE) {
+			pb_log("%sNo limit specified\n", prefix);
+			continue;
+		}
+
+		if (attr->limit == LIMIT_RANGE) {
+			pb_log("%sRange limit: <%d,%d>\n", prefix,
+			       attr->range[0], attr->range[1]);
+			continue;
+		}
+
+		pb_log("%s%u enumerations specified\n",
+		       prefix, attr->n_range);
+		for (j = 0; j < attr->n_range; j++) {
+			pb_log("%s\tdisplay-name: %s\n",
+			       prefix, attr->enums[j].display_name);
+			pb_log("%s\tdescription: %s\n",
+			       prefix, attr->enums[j].description);
+			pb_log("%s\tvalue (hex): %x\n",
+			       prefix, attr->enums[j].value);
+		}
+	}
+
+	talloc_free(prefix);
+}
diff --git a/lib/types/types.h b/lib/types/types.h
index 8c9d552..dd3a849 100644
--- a/lib/types/types.h
+++ b/lib/types/types.h
@@ -217,4 +217,7 @@ struct config {
 	bool			debug;
 };
 
+void dump_firmware_config(struct firmware_option *opts,
+				 int n_opts, int level);
+
 #endif /* _TYPES_H */
diff --git a/lib/xml/xml.c b/lib/xml/xml.c
new file mode 100644
index 0000000..990b1bd
--- /dev/null
+++ b/lib/xml/xml.c
@@ -0,0 +1,155 @@
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <string.h>
+
+#include <talloc/talloc.h>
+#include <log/log.h>
+
+#include "xml/xml.h"
+
+xmlDocPtr readXMLFile(const char *path)
+{
+	xmlParserCtxtPtr ctxt;
+	xmlDocPtr doc = NULL;
+
+	if (!path)
+		goto out;
+
+	LIBXML_TEST_VERSION;
+
+	ctxt = xmlNewParserCtxt();
+	if (!ctxt)
+		goto out;
+
+	doc = xmlCtxtReadFile(ctxt, path, NULL, 0);
+	/*
+	 * Future hostboot xmls will include or reference a DTD, which
+	 * we should use
+	 * doc = xmlCtxtReadFile(ctxt, path, NULL, XML_PARSE_DTDVALID);
+	 */
+	if (!doc) {
+		pb_log("Failed to parse XML file '%s'\n", path);
+		goto out;
+	}
+
+	if (!ctxt->valid) {
+		pb_log("XML file '%s' failed DTD check\n", path);
+		xmlFreeDoc(doc);
+		doc = NULL;
+	}
+
+	xmlFreeParserCtxt(ctxt);
+out:
+	return doc;
+	//on some error paths we may as well cleanup the library
+}
+
+xmlNodePtr findXMLRoot(xmlDocPtr doc, const char *name)
+{
+	xmlNodePtr node, root = NULL;
+
+	for (node = xmlDocGetRootElement(doc); node; node = node->next)
+		if (node->type == XML_ELEMENT_NODE)
+			if (!xmlStrcmp(node->name, (const xmlChar *)name)) {
+				root = node;
+				break;
+			}
+	return root;
+}
+
+
+/* Return first child node matching name */
+xmlNodePtr findChildNode(xmlNodePtr root, xmlElementType type,
+			 const char *name)
+{
+	xmlNodePtr cur;
+
+	for (cur = root->children; cur; cur = cur->next)
+		if (!type || cur->type == type)
+			if (!xmlStrcmp(cur->name, (const xmlChar *)name))
+			    return cur;
+	return NULL;
+}
+
+/*
+ * We probably won't end up looping through attributes like we do with
+ * elements since they will be fairly specific, but here's an
+ * illustrative example
+ */
+void printAttrs(xmlDocPtr doc, xmlNodePtr node, const char *prefix)
+{
+	xmlAttrPtr attr;
+	xmlChar *key = NULL;
+
+	for (attr = node->properties; attr; attr = attr->next) {
+		key = xmlNodeListGetString(doc, attr->xmlChildrenNode, 1);
+		pb_log("%s'%s'->'%s'\n", prefix, attr->name, key);
+		xmlFree(key);
+	}
+}
+
+char *nodeAttribute(void *ctx, xmlNodePtr node, const char *name)
+{
+	xmlChar *tmp;
+	char *attr;
+
+	tmp = xmlGetProp(node, (xmlChar *) name);
+	attr = talloc_strdup(ctx, (char *) tmp);
+
+	xmlFree(tmp);
+	return attr;
+}
+
+
+/* Allocate content under context, return NULL for whitespace-only results */
+char *nodeContent(void *ctx, xmlDocPtr doc, xmlNodePtr node)
+{
+	char *content;
+	xmlChar *tmp = xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
+	/* xmlNodeGetContent aggregates empty fields */
+
+	content = talloc_strdup(ctx, (char *)tmp);
+	xmlFree(tmp);
+
+	return content;
+}
+
+bool hasChildren(xmlNodePtr node, xmlElementType type)
+{
+	xmlNodePtr cur;
+	int n = 0;
+
+	for (cur = node->children; cur; cur = cur->next)
+		if (!type || cur->type == type)
+			n++;
+
+	return n;
+}
+
+/* Return child nodes, optionally filtering by type */
+int nodeChildren(void *ctx, xmlNodePtr **nodes, xmlNodePtr node,
+		 xmlElementType type)
+{
+	xmlNodePtr cur, *children = NULL;
+	int n = 0;
+
+	for (cur = node->children; cur; cur = cur->next) {
+		if (!type || cur->type == type) {
+			children = talloc_realloc(ctx, children,
+						xmlNodePtr, n + 1);
+			children[n++] = cur;
+		}
+	}
+
+	*nodes = children;
+	return n;
+}
+
+/*
+ * This should only be called once we are completely finished with the library.
+ */
+void finaliseXML(xmlDocPtr doc)
+{
+	xmlFreeDoc(doc);
+	xmlCleanupParser();
+}
diff --git a/lib/xml/xml.h b/lib/xml/xml.h
new file mode 100644
index 0000000..91cc8d3
--- /dev/null
+++ b/lib/xml/xml.h
@@ -0,0 +1,19 @@
+#ifndef _XML_H
+#define _XML_H
+
+#include <libxml/tree.h>
+
+xmlDocPtr readXMLFile(const char *path);
+xmlNodePtr findXMLRoot(xmlDocPtr doc, const char *root_name);
+xmlNodePtr findChildNode(xmlNodePtr root, xmlElementType type,
+			 const char *name);
+int nodeChildren(void *ctx, xmlNodePtr **nodes, xmlNodePtr node,
+		 xmlElementType type);
+bool hasChildren(xmlNodePtr node, xmlElementType type);
+
+char *nodeContent(void *ctx, xmlDocPtr doc, xmlNodePtr node);
+char *nodeAttribute(void *ctx, xmlNodePtr node, const char *name);
+void printAttrs(xmlDocPtr doc, xmlNodePtr node, const char *prefix);
+void finaliseXML(xmlDocPtr doc);
+
+#endif /* _XML_H */
-- 
2.6.2



More information about the Petitboot mailing list