[XEN PATCH v2 6/8] tools/libxenstat: Use json-c when available

Anthony PERARD posted 8 patches 5 days, 9 hours ago
[XEN PATCH v2 6/8] tools/libxenstat: Use json-c when available
Posted by Anthony PERARD 5 days, 9 hours ago
From: Anthony PERARD <anthony.perard@vates.tech>

This is mainly a copy of the existing code in yajl and use json-c
instead.

Signed-off-by: Anthony PERARD <anthony.perard@vates.tech>
Reviewed-by: Jason Andryuk <jason.andryuk@amd.com>
---

Notes:
    v2:
    - use new $(XEN_JSON_LIBS)

 tools/libs/stat/Makefile      |   2 +-
 tools/libs/stat/xenstat_qmp.c | 126 ++++++++++++++++++++++++++++++++--
 2 files changed, 120 insertions(+), 8 deletions(-)

diff --git a/tools/libs/stat/Makefile b/tools/libs/stat/Makefile
index a968eaff48..3151ee9f12 100644
--- a/tools/libs/stat/Makefile
+++ b/tools/libs/stat/Makefile
@@ -24,7 +24,7 @@ OBJS-$(CONFIG_SunOS) += xenstat_solaris.o
 OBJS-$(CONFIG_NetBSD) += xenstat_netbsd.o
 OBJS-$(CONFIG_FreeBSD) += xenstat_freebsd.o
 
-LDLIBS-y += -lyajl
+LDLIBS-y += $(XEN_JSON_LIBS)
 LDLIBS-$(CONFIG_SunOS) += -lkstat
 LDLIBS += $(LDLIBS-y)
 
diff --git a/tools/libs/stat/xenstat_qmp.c b/tools/libs/stat/xenstat_qmp.c
index 9909b9727e..21e321fffa 100644
--- a/tools/libs/stat/xenstat_qmp.c
+++ b/tools/libs/stat/xenstat_qmp.c
@@ -24,6 +24,10 @@
 
 #include "xenstat_priv.h"
 
+#ifdef HAVE_LIBJSONC
+#include <json-c/json.h>
+
+#elif defined(HAVE_LIBYAJL)
 #ifdef HAVE_YAJL_YAJL_VERSION_H
 #  include <yajl/yajl_version.h>
 #endif
@@ -32,11 +36,13 @@
 #if defined(YAJL_MAJOR) && (YAJL_MAJOR > 1)
 #  define HAVE_YAJL_V2 1
 #endif
+#endif
 
 #ifdef HAVE_YAJL_V2
-
 #include <yajl/yajl_tree.h>
+#endif
 
+#if defined(HAVE_LIBJSONC) || defined(HAVE_YAJL_V2)
 static unsigned char *qmp_query(int, const char *);
 
 enum query_blockstats {
@@ -76,9 +82,10 @@ enum query_block {
             "type": 'str'
           }]}
 */
-static char *qmp_get_block_image(xenstat_node *node, char *qmp_devname, int qfd)
+static char *qmp_get_block_image(xenstat_node *node, const char *qmp_devname, int qfd)
 {
-	char *tmp, *file = NULL;
+	const char *tmp;
+	char *file = NULL;
 	const char *query_block_cmd = "{ \"execute\": \"query-block\" }";
 	static const char *const qblock[] = {
 		[ QMP_BLOCK_RETURN  ] = "return",
@@ -88,13 +95,56 @@ static char *qmp_get_block_image(xenstat_node *node, char *qmp_devname, int qfd)
 	};
 	const char *ptr[] = {0, 0};
 	unsigned char *qmp_stats;
-	yajl_val info, ret_obj, dev_obj, n;
 	int i;
 
 	if ((qmp_stats = qmp_query(qfd, query_block_cmd)) == NULL)
 		return NULL;
 
+#ifdef HAVE_LIBJSONC
+	json_object *jso;
+	enum json_tokener_error error;
+	jso = json_tokener_parse_verbose((const char *)qmp_stats, &error);
+	free(qmp_stats);
+	if (jso == NULL)
+		return NULL;
+
+	ptr[0] = qblock[QMP_BLOCK_RETURN]; /* "return" */
+	json_object *ret_jso = json_object_object_get(jso, ptr[0]);
+	if (ret_jso == NULL)
+		goto done;
+
+	for (i=0; i<json_object_array_length(ret_jso); i++) {
+		json_object *n = json_object_array_get_idx(ret_jso, i);
+
+		ptr[0] = qblock[QMP_BLOCK_DEVICE]; /* "device" */
+		json_object *dev_jso = json_object_object_get(n, ptr[0]);
+		if (dev_jso) {
+			tmp = json_object_get_string(dev_jso);
+			if (!tmp || strcmp(qmp_devname, tmp))
+				continue;
+		} else {
+			continue;
+		}
+
+		ptr[0] = qblock[QMP_INSERTED]; /* "inserted" */
+		n = json_object_object_get(n, ptr[0]);
+		if (n) {
+			ptr[0] = qblock[QMP_FILE]; /* "file" */
+			n = json_object_object_get(n, ptr[0]);
+			if (n && json_object_is_type(n, json_type_string)) {
+				tmp = json_object_get_string(n);
+				file = malloc(strlen(tmp)+1);
+				if (file != NULL)
+					strcpy(file, tmp);
+				goto done;
+			}
+		}
+	}
+done:
+	json_object_put(jso);
+#elif defined(HAVE_LIBYAJL)
 	/* Use libyajl version 2.0.3 or newer for the tree parser feature with bug fixes */
+	yajl_val info, ret_obj, dev_obj, n;
 	info = yajl_tree_parse((char *)qmp_stats, NULL, 0);
 	free(qmp_stats);
 	if (info == NULL)
@@ -132,12 +182,13 @@ static char *qmp_get_block_image(xenstat_node *node, char *qmp_devname, int qfd)
 	}
 done:
 	yajl_tree_free(info);
+#endif
 	return file;
 }
 
 
 /* Given a QMP device name, lookup the associated xenstore qdisk device id */
-static void lookup_xenstore_devid(xenstat_node * node, unsigned int domid, char *qmp_devname,
+static void lookup_xenstore_devid(xenstat_node * node, unsigned int domid, const char *qmp_devname,
 	int qfd, unsigned int *dev, unsigned int *sector_size)
 {
 	char **dev_ids, *tmp, *ptr, *image, path[80];
@@ -191,7 +242,7 @@ static void lookup_xenstore_devid(xenstat_node * node, unsigned int domid, char
 /* Parse the stats buffer which contains I/O data for all the disks belonging to domid */
 static void qmp_parse_stats(xenstat_node *node, unsigned int domid, unsigned char *stats_buf, int qfd)
 {
-	char *qmp_devname;
+	const char *qmp_devname;
 	static const char *const qstats[] = {
 		[ QMP_STATS_RETURN  ] = "return",
 		[ QMP_STATS_DEVICE  ] = "device",
@@ -202,12 +253,72 @@ static void qmp_parse_stats(xenstat_node *node, unsigned int domid, unsigned cha
 		[ QMP_WR_OPERATIONS ] = "wr_operations",
 	};
 	const char *ptr[] = {0, 0};
-	yajl_val info, ret_obj, stats_obj, n;
 	xenstat_vbd vbd;
 	xenstat_domain *domain;
 	unsigned int sector_size = 512;
 	int i, j;
 
+#ifdef HAVE_LIBJSONC
+	json_object *jso, *ret_jso, *stats_obj, *n;
+	enum json_tokener_error error;
+
+	jso = json_tokener_parse_verbose((const char *)stats_buf, &error);
+	if (jso == NULL)
+		return;
+
+	ptr[0] = qstats[QMP_STATS_RETURN]; /* "return" */
+	ret_jso = json_object_object_get(jso, ptr[0]);
+	if (ret_jso == NULL)
+		goto done;
+
+	/* Array of devices */
+	for (i=0; i<json_object_array_length(ret_jso); i++) {
+		memset(&vbd, 0, sizeof(xenstat_vbd));
+		qmp_devname = NULL;
+		stats_obj = json_object_array_get_idx(ret_jso, i);
+
+		ptr[0] = qstats[QMP_STATS_DEVICE]; /* "device" */
+		n = json_object_object_get(stats_obj, ptr[0]);
+		if (n)
+			qmp_devname = json_object_get_string(n);
+
+		ptr[0] = qstats[QMP_STATS]; /* "stats" */
+		stats_obj = json_object_object_get(stats_obj, ptr[0]);
+		if (stats_obj && json_object_is_type(stats_obj, json_type_object)) {
+			for (j=3; j<7; j++) {
+				ptr[0] = qstats[j];
+				n = json_object_object_get(stats_obj, ptr[0]);
+				if (n && json_object_is_type(n, json_type_int)) {
+					switch(j) {
+					case QMP_RD_BYTES: /* "rd_bytes" */
+						vbd.rd_sects = json_object_get_int64(n) / sector_size;
+						break;
+					case QMP_WR_BYTES: /* "wr_bytes" */
+						vbd.wr_sects = json_object_get_int64(n) / sector_size;
+						break;
+					case QMP_RD_OPERATIONS: /* "rd_operations" */
+						vbd.rd_reqs = json_object_get_int64(n);
+						break;
+					case QMP_WR_OPERATIONS: /* "wr_operations" */
+						vbd.wr_reqs = json_object_get_int64(n);
+						break;
+					}
+				}
+			}
+			/* With the QMP device name, lookup the xenstore qdisk device ID and set vdb.dev */
+			if (qmp_devname)
+				lookup_xenstore_devid(node, domid, qmp_devname, qfd, &vbd.dev, &sector_size);
+			if ((domain = xenstat_node_domain(node, domid)) == NULL)
+				continue;
+			if ((xenstat_save_vbd(domain, &vbd)) == NULL)
+				goto done;
+		}
+	}
+done:
+	json_object_put(jso);
+#elif defined(HAVE_LIBYAJL)
+	yajl_val info, ret_obj, stats_obj, n;
+
 	/* Use libyajl version 2.0.3 or newer for the tree parser feature */
 	if ((info = yajl_tree_parse((char *)stats_buf, NULL, 0)) == NULL)
 		return;
@@ -260,6 +371,7 @@ static void qmp_parse_stats(xenstat_node *node, unsigned int domid, unsigned cha
 	}
 done:
 	yajl_tree_free(info);
+#endif
 }
 
 /* Write a command via the QMP. Returns number of bytes written */
-- 
Anthony PERARD