xm/xend supports sysrq command. Add .domainSendKey function to support
sending sysrq key.

Signed-off-by: Chunyan Liu <cyliu@suse.com>

Index: libvirt-1.2.5/src/xen/xen_driver.c
===================================================================
--- libvirt-1.2.5.orig/src/xen/xen_driver.c
+++ libvirt-1.2.5/src/xen/xen_driver.c
@@ -67,6 +67,7 @@
 #include "configmake.h"
 #include "virstring.h"
 #include "viraccessapicheck.h"
+#include "virkeycode.h"
 
 #define VIR_FROM_THIS VIR_FROM_XEN
 
@@ -2719,6 +2720,89 @@ xenUnifiedNodeSuspendForDuration(virConn
     return nodeSuspendForDuration(target, duration, flags);
 }
 
+typedef struct keyname_to_letter {
+   const char *keyname;
+   const char *letter;
+} keyname_to_letter;
+
+static const keyname_to_letter sysrq_keymap[] = {
+    {"KEY_0", "0"}, {"KEY_1", "1"}, {"KEY_2", "2"}, {"KEY_3", "3"},
+    {"KEY_4", "4"}, {"KEY_5", "5"}, {"KEY_6", "6"}, {"KEY_7", "7"},
+    {"KEY_8", "8"}, {"KEY_9", "9"}, {"KEY_B", "b"},
+    {"KEY_C", "c"}, {"KEY_D", "d"}, {"KEY_E", "e"}, {"KEY_F", "f"},
+    {"KEY_G", "g"}, {"KEY_H", "h"}, {"KEY_I", "i"}, {"KEY_J", "j"},
+    {"KEY_K", "k"}, {"KEY_L", "l"}, {"KEY_M", "m"}, {"KEY_N", "n"},
+    {"KEY_O", "o"}, {"KEY_P", "p"}, {"KEY_Q", "q"}, {"KEY_R", "r"},
+    {"KEY_S", "s"}, {"KEY_T", "t"}, {"KEY_U", "u"}, {"KEY_V", "v"},
+    {"KEY_W", "w"}, {"KEY_X", "x"}, {"KEY_Y", "y"}, {"KEY_Z", "z"},
+    {NULL, NULL}
+};
+
+static int
+xenUnifiedDomainSendKey(virDomainPtr dom,
+                        unsigned int codeset,
+                        unsigned int holdtime ATTRIBUTE_UNUSED,
+                        unsigned int *keycodes,
+                        int nkeycodes,
+                        unsigned int flags)
+{
+    int ret = -1;
+    virDomainDefPtr def;
+    const char *keyname0, *keyname1;
+
+    virCheckFlags(0, -1);
+
+    if (!(def = xenGetDomainDefForDom(dom)))
+        goto cleanup;
+
+    if (virDomainSendKeyEnsureACL(dom->conn, def) < 0)
+        goto cleanup;
+
+    /* check key, only support sending magic sysrq. Like:
+     * #virsh send-key guest1 KEY_LEFTALT KEY_SYSRQ KEY_H
+     */
+    if (nkeycodes < 3)
+        goto non_sysrq;
+
+    keyname0 = virKeynameFromKeycode(codeset, keycodes[0]);
+    keyname1 = virKeynameFromKeycode(codeset, keycodes[1]);
+    if (!keyname0 || !keyname1)
+        goto non_sysrq;
+
+    if ((STREQ(keyname0, "KEY_LEFTALT") && STREQ(keyname1, "KEY_SYSRQ")) ||
+        (STREQ(keyname1, "KEY_LEFTALT") && STREQ(keyname0, "KEY_SYSRQ"))) {
+        const keyname_to_letter *item = sysrq_keymap;
+        char *key = NULL;
+        const char *keyname = virKeynameFromKeycode(codeset, keycodes[2]);
+
+        while (item && item->keyname) {
+            if (keyname && STREQ(item->keyname, keyname)) {
+                if (VIR_STRDUP(key, item->letter) < 0)
+                    goto cleanup;
+                break;
+            }
+            item++;
+        }
+
+        if (!key)
+            goto non_sysrq;
+
+        ret = xenDaemonDomainSysrq(dom->conn, def, key);
+        VIR_FREE(key);
+        goto cleanup;
+
+    } else {
+        goto non_sysrq;
+    }
+
+ non_sysrq:
+    virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
+                   "%s", _("Sending non-sysrq keys is not supported"));
+
+ cleanup:
+    virDomainDefFree(def);
+    return ret;
+}
 
 /*----- Register with libvirt.c, and initialize Xen drivers. -----*/
 
@@ -2817,6 +2901,7 @@ static virDriver xenUnifiedDriver = {
     .nodeSuspendForDuration = xenUnifiedNodeSuspendForDuration, /* 0.9.8 */
     .nodeGetMemoryParameters = xenUnifiedNodeGetMemoryParameters, /* 0.10.2 */
     .nodeSetMemoryParameters = xenUnifiedNodeSetMemoryParameters, /* 0.10.2 */
+    .domainSendKey = xenUnifiedDomainSendKey, /* 1.2.12 */
 };
 
 /**
Index: libvirt-1.2.5/src/xen/xend_internal.c
===================================================================
--- libvirt-1.2.5.orig/src/xen/xend_internal.c
+++ libvirt-1.2.5/src/xen/xend_internal.c
@@ -1349,6 +1349,27 @@ xenDaemonDomainReboot(virConnectPtr conn
 }
 
 /**
+ * xenDaemonDomainSysrq:
+ * @conn: the connection object
+ * @def: the domain to destroy
+ *
+ * Send a sysrq to a domain.
+ *
+ * Returns 0 in case of success, -1 (with errno) in case of error.
+ */
+int
+xenDaemonDomainSysrq(virConnectPtr conn, virDomainDefPtr def, char *key)
+{
+    if (def->id < 0) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       _("Domain %s isn't running."), def->name);
+        return -1;
+    }
+
+    return xend_op(conn, def->name, "op", "sysrq", "key", key, NULL);
+}
+
+/**
  * xenDaemonDomainDestroy:
  * @conn: the connection object
  * @def: the domain to destroy
Index: libvirt-1.2.5/src/xen/xend_internal.h
===================================================================
--- libvirt-1.2.5.orig/src/xen/xend_internal.h
+++ libvirt-1.2.5/src/xen/xend_internal.h
@@ -213,5 +213,6 @@ int xenDaemonSetSchedulerParameters(virC
                                     virDomainDefPtr def,
                                     virTypedParameterPtr params,
                                     int nparams);
+int xenDaemonDomainSysrq(virConnectPtr conn, virDomainDefPtr def, char *key);
 
 #endif /* __XEND_INTERNAL_H_ */
