xm/xend supports sysrq command. Add .domainSendKey function to support
sending sysrq key.
Signed-off-by: Chunyan Liu <cyliu(a)suse.com>
---
src/xen/xen_driver.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++
src/xen/xend_internal.c | 21 ++++++++++++
src/xen/xend_internal.h | 1 +
3 files changed, 107 insertions(+)
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index c9f4159..434236e 100644
--- a/src/xen/xen_driver.c
+++ b/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
@@ -2738,6 +2739,89 @@ xenUnifiedNodeSuspendForDuration(virConnectPtr conn,
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_A", "a"}, {"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. -----*/
@@ -2836,6 +2920,7 @@ static virHypervisorDriver xenUnifiedDriver = {
.nodeSuspendForDuration = xenUnifiedNodeSuspendForDuration, /* 0.9.8 */
.nodeGetMemoryParameters = xenUnifiedNodeGetMemoryParameters, /* 0.10.2 */
.nodeSetMemoryParameters = xenUnifiedNodeSetMemoryParameters, /* 0.10.2 */
+ .domainSendKey = xenUnifiedDomainSendKey, /* 1.2.11 */
};
/**
diff --git a/src/xen/xend_internal.c b/src/xen/xend_internal.c
index b233b6b..eabb6ed 100644
--- a/src/xen/xend_internal.c
+++ b/src/xen/xend_internal.c
@@ -1349,6 +1349,27 @@ xenDaemonDomainReboot(virConnectPtr conn, virDomainDefPtr def)
}
/**
+ * 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
diff --git a/src/xen/xend_internal.h b/src/xen/xend_internal.h
index 814330d..6706394 100644
--- a/src/xen/xend_internal.h
+++ b/src/xen/xend_internal.h
@@ -213,5 +213,6 @@ int xenDaemonSetSchedulerParameters(virConnectPtr conn,
virDomainDefPtr def,
virTypedParameterPtr params,
int nparams);
+int xenDaemonDomainSysrq(virConnectPtr conn, virDomainDefPtr def, char *key);
#endif /* __XEND_INTERNAL_H_ */
--
1.8.4.5