xm/xend supports sysrq command. Add .domainSendKey function to support sending sysrq key. Signed-off-by: Chunyan Liu <cyliu@xxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list