Signed-off-by: Lai Jiangshan <laijs(a)fujitsu.com>
---
src/qemu/qemu_driver.c | 50 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor.c | 28 +++++++++++++++++++++++
src/qemu/qemu_monitor.h | 6 +++++
src/qemu/qemu_monitor_json.c | 15 ++++++++++++
src/qemu/qemu_monitor_json.h | 5 ++++
src/qemu/qemu_monitor_text.c | 48 ++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 5 ++++
7 files changed, 157 insertions(+), 0 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 691965d..f7e21bf 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1753,6 +1753,55 @@ cleanup:
return ret;
}
+static int qemuDomainSendKey(virDomainPtr domain,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes,
+ unsigned int flags)
+{
+ struct qemud_driver *driver = domain->conn->privateData;
+ virDomainObjPtr vm = NULL;
+ int ret = -1;
+ qemuDomainObjPrivatePtr priv;
+
+ virCheckFlags(0, -1);
+
+ qemuDriverLock(driver);
+ vm = virDomainFindByUUID(&driver->domains, domain->uuid);
+ if (!vm) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(domain->uuid, uuidstr);
+ qemuReportError(VIR_ERR_NO_DOMAIN,
+ _("no domain with matching uuid '%s'"),
uuidstr);
+ goto cleanup;
+ }
+
+ if (!virDomainObjIsActive(vm)) {
+ qemuReportError(VIR_ERR_OPERATION_INVALID,
+ "%s", _("domain is not running"));
+ goto cleanup;
+ }
+
+ priv = vm->privateData;
+
+ if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
+ goto cleanup;
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
+ ret = qemuMonitorSendKey(priv->mon, codeset, holdtime, nkeycodes, keycodes);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
+ if (qemuDomainObjEndJob(vm) == 0) {
+ vm = NULL;
+ goto cleanup;
+ }
+
+cleanup:
+ if (vm)
+ virDomainObjUnlock(vm);
+ qemuDriverUnlock(driver);
+ return ret;
+}
+
static int qemudDomainGetInfo(virDomainPtr dom,
virDomainInfoPtr info)
{
@@ -7746,6 +7795,7 @@ static virDriver qemuDriver = {
.domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */
.domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */
.domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */
+ .domainSendKey = qemuDomainSendKey, /* 0.9.2 */
};
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 5186f99..c0688fd 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -38,6 +38,8 @@
#include "logging.h"
#include "files.h"
+#include <libvirt/virtkeys.h>
+
#define VIR_FROM_THIS VIR_FROM_QEMU
#define DEBUG_IO 0
@@ -2294,6 +2296,32 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon)
return ret;
}
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes)
+{
+ int ret;
+
+ VIR_DEBUG("mon=%p, codeset=%u, holdtime=%u, nkeycodes=%u",
+ mon, codeset, holdtime, nkeycodes);
+
+ if (!(codeset == LIBVIRT_KEYCODE_DRIVER_DEFAULT
+ || codeset == LIBVIRT_KEYCODE_XT)) {
+ qemuReportError(VIR_ERR_NO_SUPPORT,
+ "qemu monitor can not support the codeset: %d",
+ codeset);
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONSendKey(mon, holdtime, nkeycodes, keycodes);
+ else
+ ret = qemuMonitorTextSendKey(mon, holdtime, nkeycodes, keycodes);
+ return ret;
+}
+
int qemuMonitorScreendump(qemuMonitorPtr mon,
const char *file)
{
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 05c3359..76a849a 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -435,6 +435,12 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon);
int qemuMonitorScreendump(qemuMonitorPtr mon,
const char *file);
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+ unsigned int codeset,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes);
+
/**
* When running two dd process and using <> redirection, we need a
* shell that will not truncate files. These two strings serve that
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 2d8a390..a547f1d 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2615,6 +2615,21 @@ cleanup:
return ret;
}
+int qemuMonitorJSONSendKey(qemuMonitorPtr mon,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes)
+{
+ /*
+ * FIXME: qmp sendkey has not been implemented yet,
+ * and qmp API of it can not be anticipated, so we use hmp temporary.
+ */
+ if (qemuMonitorCheckHMP(mon, "sendkey")) {
+ return qemuMonitorTextSendKey(mon, holdtime, nkeycodes, keycodes);
+ } else
+ return -1;
+}
+
int qemuMonitorJSONScreendump(qemuMonitorPtr mon,
const char *file)
{
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index ec79b03..89d7515 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -214,6 +214,11 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon);
+int qemuMonitorJSONSendKey(qemuMonitorPtr mon,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes);
+
int qemuMonitorJSONScreendump(qemuMonitorPtr mon,
const char *file);
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 106f2d3..433cde1 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2717,6 +2717,54 @@ fail:
return -1;
}
+int qemuMonitorTextSendKey(qemuMonitorPtr mon,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes)
+{
+ int i;
+ int pos = strlen("sendkey ");
+ int cmd_len = pos + nkeycodes * strlen("0xFF-") + 12 +
sizeof('\0');
+ char *cmd, *reply = NULL;
+
+ if (nkeycodes > 16 || nkeycodes == 0)
+ return -1;
+
+ if (VIR_ALLOC_N(cmd, cmd_len) < 0)
+ return -1;
+
+ memcpy(cmd, "sendkey ", pos);
+ for (i = 0; i < nkeycodes; i++) {
+ if (keycodes[i] > 255) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("the %dth keycode is invalid: 0x%02X"),
+ i, keycodes[i]);
+ VIR_FREE(cmd);
+ return -1;
+ }
+
+ pos += sprintf(cmd + pos, "0x%02X-", keycodes[i]);
+ }
+ cmd[pos - 1] = ' '; // the last '-' --> ' '
+
+ if (holdtime)
+ sprintf(cmd + pos, "%u", holdtime);
+
+ if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0)
+ goto fail;
+
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ return 0;
+
+fail:
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("failed to send key using command '%s'"),
+ cmd);
+ VIR_FREE(cmd);
+ return -1;
+}
+
/* Returns -1 on error, -2 if not supported */
int qemuMonitorTextScreendump(qemuMonitorPtr mon, const char *file)
{
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 8a69105..971de83 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -208,6 +208,11 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char
*cmd,
int qemuMonitorTextInjectNMI(qemuMonitorPtr mon);
+int qemuMonitorTextSendKey(qemuMonitorPtr mon,
+ unsigned int holdtime,
+ unsigned int nkeycodes,
+ unsigned int *keycodes);
+
int qemuMonitorTextScreendump(qemuMonitorPtr mon, const char *file);
#endif /* QEMU_MONITOR_TEXT_H */
--
1.7.4.4