diff --git a/include/libvirt/libvirt-qemu.h b/include/libvirt/libvirt-qemu.h index 9c191c7f1b..9257c2f1eb 100644 --- a/include/libvirt/libvirt-qemu.h +++ b/include/libvirt/libvirt-qemu.h @@ -20,6 +20,11 @@ extern "C" { # endif +enum { + VIR_DOMAIN_QEMU_MONITOR_COMMAND_DEFAULT = 0, + VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP = (1 << 0), /* cmd is in HMP */ +} virDomainQemuMonitorCommandFlags; + int virDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd, char **result, unsigned int flags); diff --git a/src/internal.h b/src/internal.h index 11ba45f899..e263684839 100644 --- a/src/internal.h +++ b/src/internal.h @@ -38,6 +38,7 @@ # define N_(str) str # include "libvirt/libvirt.h" +# include "libvirt/libvirt-qemu.h" # include "libvirt/virterror.h" # include "libvirt_internal.h" diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d16a4ab6a9..b9367355a4 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -10242,8 +10242,9 @@ static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd, virDomainObjPtr vm = NULL; int ret = -1; qemuDomainObjPrivatePtr priv; + bool hmp; - virCheckFlags(0, -1); + virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1); qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, domain->uuid); @@ -10269,10 +10270,12 @@ static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd, priv->monitor_warned = 1; } + hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP); + if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0) goto cleanup; qemuDomainObjEnterMonitorWithDriver(driver, vm); - ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result); + ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp); qemuDomainObjExitMonitorWithDriver(driver, vm); if (qemuDomainObjEndJob(vm) == 0) { vm = NULL; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 0c142770d8..fdb6b79924 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -2007,14 +2007,17 @@ int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name) return ret; } -int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply) +int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, + const char *cmd, + char **reply, + bool hmp) { int ret; - DEBUG("mon=%p, cmd=%s, reply=%p", mon, cmd, reply); + DEBUG("mon=%p, cmd=%s, reply=%p, hmp=%d", mon, cmd, reply, hmp); if (mon->json) - ret = qemuMonitorJSONArbitraryCommand(mon, cmd, reply); + ret = qemuMonitorJSONArbitraryCommand(mon, cmd, reply, hmp); else ret = qemuMonitorTextArbitraryCommand(mon, cmd, reply); return ret; diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index 92c550bc18..0ea1330de0 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -397,7 +397,10 @@ int qemuMonitorCreateSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorLoadSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name); -int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, char **reply); +int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, + const char *cmd, + char **reply, + bool hmp); /** * When running two dd process and using <> redirection, we need a diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index ca06e7e8d2..d5e8d375e4 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -2457,22 +2457,44 @@ int qemuMonitorJSONDeleteSnapshot(qemuMonitorPtr mon, const char *name) int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, const char *cmd_str, - char **reply_str) + char **reply_str, + bool hmp) { virJSONValuePtr cmd = NULL; virJSONValuePtr reply = NULL; int ret = -1; - cmd = virJSONValueFromString(cmd_str); + if (!hmp) { + cmd = virJSONValueFromString(cmd_str); + } else { + cmd = qemuMonitorJSONMakeCommand("human-monitor-command", + "s:command-line", cmd_str, + NULL); + } + if (!cmd) return -1; if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) goto cleanup; - *reply_str = virJSONValueToString(reply); - if (!(*reply_str)) + if (!hmp) { + if (!(*reply_str = virJSONValueToString(reply))) + goto cleanup; + } else if (qemuMonitorJSONCheckError(cmd, reply)) { goto cleanup; + } else { + const char *data; + if (!(data = virJSONValueObjectGetString(reply, "return"))) { + qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("human monitor command was missing return data")); + goto cleanup; + } + if (!(*reply_str = strdup(data))) { + virReportOOMError(); + goto cleanup; + } + } ret = 0; diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 4c47f109db..4ae472a720 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -209,6 +209,7 @@ int qemuMonitorJSONDeleteSnapshot(qemuMonitorPtr mon, const char *name); int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, const char *cmd_str, - char **reply_str); + char **reply_str, + bool hmp); #endif /* QEMU_MONITOR_JSON_H */ diff --git a/tools/virsh.c b/tools/virsh.c index 59d099e491..1f820e8b39 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -10176,6 +10176,7 @@ static const vshCmdInfo info_qemu_monitor_command[] = { static const vshCmdOptDef opts_qemu_monitor_command[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"cmd", VSH_OT_DATA, VSH_OFLAG_REQ, N_("command")}, + {"hmp", VSH_OT_BOOL, 0, N_("command is in human monitor protocol")}, {NULL, 0, 0, NULL} }; @@ -10186,6 +10187,7 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd) int ret = FALSE; char *monitor_cmd; char *result = NULL; + unsigned int flags = 0; if (!vshConnectionUsability(ctl, ctl->conn)) goto cleanup; @@ -10200,7 +10202,10 @@ cmdQemuMonitorCommand(vshControl *ctl, const vshCmd *cmd) goto cleanup; } - if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, 0) < 0) + if (vshCommandOptBool(cmd, "hmp")) + flags |= VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP; + + if (virDomainQemuMonitorCommand(dom, monitor_cmd, &result, flags) < 0) goto cleanup; printf("%s\n", result); diff --git a/tools/virsh.pod b/tools/virsh.pod index d6a16f2d4f..bfaa67ec45 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1253,10 +1253,13 @@ problems to the libvirt developers; the reports will be ignored. =over 4 -=item B I I +=item B I I optional I<--hmp> Send an arbitrary monitor command I to domain I through the -qemu monitor. The results of the command will be printed on stdout. +qemu monitor. The results of the command will be printed on stdout. If +I<--hmp> is passed, the command is considered to be a human monitor command +and libvirt will automatically convert it into QMP if needed. In that case +the result will also be converted back from QMP. =back