[libvirt] [PATCH 4/4 V4] qemu:send-key: Implement the driver methods

Lai Jiangshan laijs at cn.fujitsu.com
Thu Jul 14 03:32:18 UTC 2011


qemu driver just accept xt_kbd codeset's keycode, so the lib virtkey
is used for translating keycodes from other codesets.

Signed-off-by: Lai Jiangshan <laijs at cn.fujitsu.com>
---
 src/qemu/qemu_driver.c       |   71 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_monitor.c      |   17 ++++++++++
 src/qemu/qemu_monitor.h      |    5 +++
 src/qemu/qemu_monitor_json.c |   15 +++++++++
 src/qemu/qemu_monitor_json.h |    5 +++
 src/qemu/qemu_monitor_text.c |   49 +++++++++++++++++++++++++++++
 src/qemu/qemu_monitor_text.h |    5 +++
 7 files changed, 167 insertions(+), 0 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0ea182d..c93885b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -87,6 +87,7 @@
 #include "configmake.h"
 #include "threadpool.h"
 #include "locking/lock_manager.h"
+#include "virtkey.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -1843,6 +1844,75 @@ cleanup:
     return ret;
 }
 
+static int qemuDomainSendKey(virDomainPtr domain,
+                             unsigned int codeset,
+                             unsigned int holdtime,
+                             unsigned int *keycodes,
+                             int nkeycodes,
+                             unsigned int flags)
+{
+    struct qemud_driver *driver = domain->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int ret = -1;
+    qemuDomainObjPrivatePtr priv;
+
+    virCheckFlags(0, -1);
+
+    /* translate the keycode to XT_KBD for qemu driver */
+    if (codeset != VIR_KEYCODE_SET_XT_KBD) {
+        int i;
+        int keycode;
+
+        for (i = 0; i < nkeycodes; i++) {
+            keycode = virTranslateKeyCode(codeset, VIR_KEYCODE_SET_XT_KBD,
+                                          keycodes[i]);
+            if (keycode < 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, "can not translate "
+                                "keycode %u of %s codeset to xt_kbd codeset "
+                                "keycode", keycodes[i],
+                                virKeycodeSetTypeToString(codeset));
+                return -1;
+            }
+            keycodes[i] = keycode;
+        }
+    }
+
+    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;
+    }
+
+    priv = vm->privateData;
+
+    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemuReportError(VIR_ERR_OPERATION_INVALID,
+                        "%s", _("domain is not running"));
+        goto cleanup;
+    }
+
+    qemuDomainObjEnterMonitorWithDriver(driver, vm);
+    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
+    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)
 {
@@ -8646,6 +8716,7 @@ static virDriver qemuDriver = {
     .domainMigratePerform3 = qemuDomainMigratePerform3, /* 0.9.2 */
     .domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */
     .domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */
+    .domainSendKey = qemuDomainSendKey, /* 0.9.3 */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index e593642..35fb999 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -2398,6 +2398,23 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon)
     return ret;
 }
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+                       unsigned int holdtime,
+                       unsigned int *keycodes,
+                       unsigned int nkeycodes)
+{
+    int ret;
+
+    VIR_DEBUG("mon=%p, holdtime=%u, nkeycodes=%u",
+              mon, holdtime, nkeycodes);
+
+    if (mon->json)
+        ret = qemuMonitorJSONSendKey(mon, holdtime, keycodes, nkeycodes);
+    else
+        ret = qemuMonitorTextSendKey(mon, holdtime, keycodes, nkeycodes);
+    return ret;
+}
+
 int qemuMonitorScreendump(qemuMonitorPtr mon,
                           const char *file)
 {
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 893f3e9..73a95f1 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -444,6 +444,11 @@ int qemuMonitorInjectNMI(qemuMonitorPtr mon);
 int qemuMonitorScreendump(qemuMonitorPtr mon,
                           const char *file);
 
+int qemuMonitorSendKey(qemuMonitorPtr mon,
+                       unsigned int holdtime,
+                       unsigned int *keycodes,
+                       unsigned int nkeycodes);
+
 /**
  * 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 4db2b78..8385085 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -2695,6 +2695,21 @@ cleanup:
     return ret;
 }
 
+int qemuMonitorJSONSendKey(qemuMonitorPtr mon,
+                           unsigned int holdtime,
+                           unsigned int *keycodes,
+                           unsigned int nkeycodes)
+{
+    /*
+     * 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, keycodes, nkeycodes);
+    } 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 380e26a..ddd121e 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -217,6 +217,11 @@ int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
 
 int qemuMonitorJSONInjectNMI(qemuMonitorPtr mon);
 
+int qemuMonitorJSONSendKey(qemuMonitorPtr mon,
+                           unsigned int holdtime,
+                           unsigned int *keycodes,
+                           unsigned int nkeycodes);
+
 int qemuMonitorJSONScreendump(qemuMonitorPtr mon,
                               const char *file);
 
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 0965a08..52b9a34 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -2755,6 +2755,55 @@ fail:
     return -1;
 }
 
+int qemuMonitorTextSendKey(qemuMonitorPtr mon,
+                           unsigned int holdtime,
+                           unsigned int *keycodes,
+                           unsigned int nkeycodes)
+{
+    int i;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *cmd, *reply = NULL;
+
+    if (nkeycodes > VIR_DOMAIN_SEND_KEY_MAX_KEYS || nkeycodes == 0)
+        return -1;
+
+    virBufferAddLit(&buf, "sendkey ");
+    for (i = 0; i < nkeycodes; i++) {
+        if (keycodes[i] > 0xffff) {
+            qemuReportError(VIR_ERR_OPERATION_FAILED,
+                            _("keycode %d is invalid: 0x%X"),
+                            i, keycodes[i]);
+            virBufferFreeAndReset(&buf);
+            return -1;
+        }
+
+        if (i)
+            virBufferAddChar(&buf, '-');
+        virBufferAsprintf(&buf, "0x%02X", keycodes[i]);
+    }
+
+    if (holdtime)
+        virBufferAsprintf(&buf, " %u", holdtime);
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        return -1;
+    }
+
+    cmd = virBufferContentAndReset(&buf);
+    if (qemuMonitorHMPCommand(mon, cmd, &reply) < 0) {
+        qemuReportError(VIR_ERR_OPERATION_FAILED,
+                         _("failed to send key using command '%s'"),
+                         cmd);
+        VIR_FREE(cmd);
+        return -1;
+    }
+
+    VIR_FREE(cmd);
+    VIR_FREE(reply);
+    return 0;
+}
+
 /* 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 e53f693..042e581 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -211,6 +211,11 @@ int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
 
 int qemuMonitorTextInjectNMI(qemuMonitorPtr mon);
 
+int qemuMonitorTextSendKey(qemuMonitorPtr mon,
+                           unsigned int holdtime,
+                           unsigned int *keycodes,
+                           unsigned int nkeycodes);
+
 int qemuMonitorTextScreendump(qemuMonitorPtr mon, const char *file);
 
 #endif /* QEMU_MONITOR_TEXT_H */
-- 
1.7.4.4




More information about the libvir-list mailing list