From db336caa581fedbc729f4e177fa858968564db86 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 14 Apr 2010 16:02:37 +0100 Subject: [PATCH] Update QEMU device_add command in JSON mode The device_add command was added in JSON mode in a way I didn't expect. Instead of passing the normal device string to the JSON command: { "execute": "device_add", "arguments": { "device": "ne2k_pci,id=nic.1,netdev=net.1" } } We need to split up the device string into a full JSON object { "execute": "device_add", "arguments": { "driver": "ne2k_pci", "id": "nic.1", "netdev": "net.1" } } * src/qemu/qemu_conf.h, src/qemu/qemu_conf.c: Rename the qemuCommandLineParseKeywords method to qemuParseKeywords and export it to monitor * src/qemu/qemu_monitor_json.c: Split up device string into a JSON object for device_add command --- src/qemu/qemu_conf.c | 30 +++++++------- src/qemu/qemu_conf.h | 6 +++ src/qemu/qemu_monitor_json.c | 78 ++++++++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 19 deletions(-) diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index e23b322937..1a8b4aabb2 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -4771,11 +4771,11 @@ static const char *qemuFindEnv(const char **progenv, * the "=value" part is optional and if a key with no value is found, * NULL is be placed into corresponding place in retvalues. */ -static int -qemuParseCommandLineKeywords(const char *str, - char ***retkeywords, - char ***retvalues, - int allowEmptyValue) +int +qemuParseKeywords(const char *str, + char ***retkeywords, + char ***retvalues, + int allowEmptyValue) { int keywordCount = 0; int keywordAlloc = 0; @@ -4874,9 +4874,9 @@ qemuParseCommandLineDisk(const char *val, int busid = -1; int unitid = -1; - if ((nkeywords = qemuParseCommandLineKeywords(val, - &keywords, - &values, 0)) < 0) + if ((nkeywords = qemuParseKeywords(val, + &keywords, + &values, 0)) < 0) return NULL; if (VIR_ALLOC(def) < 0) { @@ -5114,9 +5114,9 @@ qemuParseCommandLineNet(virCapsPtr caps, tmp = strchr(val, ','); if (tmp) { - if ((nkeywords = qemuParseCommandLineKeywords(tmp+1, - &keywords, - &values, 0)) < 0) + if ((nkeywords = qemuParseKeywords(tmp+1, + &keywords, + &values, 0)) < 0) return NULL; } else { nkeywords = 0; @@ -5186,9 +5186,9 @@ qemuParseCommandLineNet(virCapsPtr caps, VIR_FREE(values); if (STRPREFIX(nic, "nic,")) { - if ((nkeywords = qemuParseCommandLineKeywords(nic + strlen("nic,"), - &keywords, - &values, 0)) < 0) { + if ((nkeywords = qemuParseKeywords(nic + strlen("nic,"), + &keywords, + &values, 0)) < 0) { virDomainNetDefFree(def); def = NULL; goto cleanup; @@ -5596,7 +5596,7 @@ qemuParseCommandLineSmp(virDomainDefPtr dom, char *end; int ret; - nkws = qemuParseCommandLineKeywords(val, &kws, &vals, 1); + nkws = qemuParseKeywords(val, &kws, &vals, 1); if (nkws < 0) return -1; diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index e0666cb313..574709eb07 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -311,5 +311,11 @@ int qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, unsigned long long qemuCm int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr net, int idx); int qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller); +int +qemuParseKeywords(const char *str, + char ***retkeywords, + char ***retvalues, + int allowEmptyValue); + #endif /* __QEMUD_CONF_H */ diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index f5c73f724e..de59b2b9ee 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1961,24 +1961,94 @@ int qemuMonitorJSONDelDevice(qemuMonitorPtr mon, } +static void +qemuFreeKeywords(int nkeywords, char **keywords, char **values) +{ + int i; + for (i = 0 ; i < nkeywords ; i++) { + VIR_FREE(keywords[i]); + VIR_FREE(values[i]); + } + VIR_FREE(keywords); + VIR_FREE(values); +} + +static virJSONValuePtr +qemuMonitorJSONKeywordStringToJSON(const char *str, const char *firstkeyword) +{ + virJSONValuePtr ret = NULL; + char **keywords = NULL; + char **values = NULL; + int nkeywords = 0; + int i; + + if (!(ret = virJSONValueNewObject())) + goto no_memory; + + nkeywords = qemuParseKeywords(str, &keywords, &values, 1); + + if (nkeywords < 0) + goto error; + + for (i = 0 ; i < nkeywords ; i++) { + if (values[i] == NULL) { + if (i != 0) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected empty keyword in %s"), str); + goto error; + } else { + /* This 3rd arg isn't a typo - the way the parser works is + * that the value ended up in the keyword field */ + if (virJSONValueObjectAppendString(ret, firstkeyword, keywords[i]) < 0) + goto no_memory; + } + } else { + if (virJSONValueObjectAppendString(ret, keywords[i], values[i]) < 0) + goto no_memory; + } + } + + qemuFreeKeywords(nkeywords, keywords, values); + return ret; + +no_memory: + virReportOOMError(); +error: + qemuFreeKeywords(nkeywords, keywords, values); + virJSONValueFree(ret); + return NULL; +} + + int qemuMonitorJSONAddDevice(qemuMonitorPtr mon, const char *devicestr) { - int ret; + int ret = -1; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; + virJSONValuePtr args; - cmd = qemuMonitorJSONMakeCommand("device_add", - "s:config", devicestr, - NULL); + cmd = qemuMonitorJSONMakeCommand("device_add", NULL); if (!cmd) return -1; + args = qemuMonitorJSONKeywordStringToJSON(devicestr, "driver"); + if (!args) + goto cleanup; + + if (virJSONValueObjectAppend(cmd, "arguments", args) < 0) { + virReportOOMError(); + goto cleanup; + } + args = NULL; /* obj owns reference to args now */ + ret = qemuMonitorJSONCommand(mon, cmd, &reply); if (ret == 0) ret = qemuMonitorJSONCheckError(cmd, reply); +cleanup: + virJSONValueFree(args); virJSONValueFree(cmd); virJSONValueFree(reply); return ret;