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, §or_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
© 2016 - 2025 Red Hat, Inc.