diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index cf2b20aee1..47cc185ad3 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -4507,6 +4507,104 @@ cleanup: } +int qemuMonitorJSONGetObjectListPaths(qemuMonitorPtr mon, + const char *path, + qemuMonitorJSONListPathPtr **paths) +{ + int ret; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + virJSONValuePtr data; + qemuMonitorJSONListPathPtr *pathlist = NULL; + int n = 0; + size_t i; + + *paths = NULL; + + if (!(cmd = qemuMonitorJSONMakeCommand("qom-list", + "s:path", path, + NULL))) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + if (ret < 0) + goto cleanup; + + ret = -1; + + if (!(data = virJSONValueObjectGet(reply, "return"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-list reply was missing return data")); + goto cleanup; + } + + if ((n = virJSONValueArraySize(data)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-list reply data was not an array")); + goto cleanup; + } + + /* null-terminated list */ + if (VIR_ALLOC_N(pathlist, n + 1) < 0) + goto cleanup; + + for (i = 0; i < n; i++) { + virJSONValuePtr child = virJSONValueArrayGet(data, i); + const char *tmp; + qemuMonitorJSONListPathPtr info; + + if (VIR_ALLOC(info) < 0) + goto cleanup; + + pathlist[i] = info; + + if (!(tmp = virJSONValueObjectGetString(child, "name"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-list reply data was missing 'name'")); + goto cleanup; + } + + if (VIR_STRDUP(info->name, tmp) < 0) + goto cleanup; + + if (virJSONValueObjectHasKey(child, "type")) { + if (!(tmp = virJSONValueObjectGetString(child, "type"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("qom-list reply has malformed 'type' data")); + goto cleanup; + } + if (VIR_STRDUP(info->type, tmp) < 0) + goto cleanup; + } + } + + ret = n; + *paths = pathlist; + +cleanup: + if (ret < 0 && pathlist) { + for (i = 0; i < n; i++) + qemuMonitorJSONListPathFree(pathlist[i]); + VIR_FREE(pathlist); + } + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + +void qemuMonitorJSONListPathFree(qemuMonitorJSONListPathPtr paths) +{ + if (!paths) + return; + VIR_FREE(paths->name); + VIR_FREE(paths->type); + VIR_FREE(paths); +} + int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon, const char *type, char ***props) diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 266077395c..f83db00058 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -332,6 +332,23 @@ int qemuMonitorJSONGetKVMState(qemuMonitorPtr mon, int qemuMonitorJSONGetObjectTypes(qemuMonitorPtr mon, char ***types) ATTRIBUTE_NONNULL(2); + +/* ListPath structures and API's are public only for qemumonitorjsontest */ +typedef struct _qemuMonitorJSONListPath qemuMonitorJSONListPath; +typedef qemuMonitorJSONListPath *qemuMonitorJSONListPathPtr; + +struct _qemuMonitorJSONListPath { + char *name; + char *type; +}; + +int qemuMonitorJSONGetObjectListPaths(qemuMonitorPtr mon, + const char *path, + qemuMonitorJSONListPathPtr **paths) + ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); + +void qemuMonitorJSONListPathFree(qemuMonitorJSONListPathPtr paths); + int qemuMonitorJSONGetObjectProps(qemuMonitorPtr mon, const char *type, char ***props) diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index 7edaf395d1..e3d08fc4d7 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -23,6 +23,7 @@ #include "testutilsqemu.h" #include "qemumonitortestutils.h" #include "qemu/qemu_conf.h" +#include "qemu/qemu_monitor_json.h" #include "virthread.h" #include "virerror.h" #include "virstring.h" @@ -699,6 +700,83 @@ cleanup: return ret; } +/* + * This test will request to return a list of paths for "/". It should be + * a simple list of 1 real element that being the "machine". The following + * is the execution and expected return: + * + * {"execute":"qom-list", "arguments": { "path": "/"}}" + * {"return": [{"name": "machine", "type": "child"}, \ + * {"name": "type", "type": "string"}]} + */ +static int +testQemuMonitorJSONGetListPaths(const void *data) +{ + const virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data; + qemuMonitorTestPtr test = qemuMonitorTestNew(true, xmlopt); + int ret = -1; + qemuMonitorJSONListPathPtr *paths; + int npaths = 0; + size_t i; + + if (!test) + return -1; + + if (qemuMonitorTestAddItem(test, "qom-list", + "{ " + " \"return\": [ " + " {\"name\": \"machine\", " + " \"type\": \"child\"}, " + " {\"name\": \"type\", " + " \"type\": \"string\"} " + " ]" + "}") < 0) + goto cleanup; + + /* present with path */ + if ((npaths = qemuMonitorJSONGetObjectListPaths( + qemuMonitorTestGetMonitor(test), + "/", + &paths)) < 0) + goto cleanup; + + if (npaths != 2) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "npaths was %d, expected 1", npaths); + goto cleanup; + } + +#define CHECK(i, wantname, wanttype) \ + do { \ + if (STRNEQ(paths[i]->name, (wantname))) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "name was %s, expected %s", \ + paths[i]->name, (wantname)); \ + goto cleanup; \ + } \ + if (STRNEQ_NULLABLE(paths[i]->type, (wanttype))) { \ + virReportError(VIR_ERR_INTERNAL_ERROR, \ + "type was %s, expected %s", \ + NULLSTR(paths[i]->type), (wanttype)); \ + goto cleanup; \ + } \ + } while (0) + + CHECK(0, "machine", "child"); + +#undef CHECK + + ret = 0; + +cleanup: + qemuMonitorTestFree(test); + for (i = 0; i < npaths; i++) + qemuMonitorJSONListPathFree(paths[i]); + VIR_FREE(paths); + return ret; +} + + static int mymain(void) { @@ -729,6 +807,7 @@ mymain(void) DO_TEST(GetCommandLineOptionParameters); DO_TEST(AttachChardev); DO_TEST(DetachChardev); + DO_TEST(GetListPaths); virObjectUnref(xmlopt);