@@ -113,11 +113,69 @@ static QDict *va_ping(const QDict *params)
return va_server_format_response(NULL, 0, NULL);
}
+/* va_shutdown(): initiate guest shutdown
+ * params/response qdict format:
+ * params{shutdown_mode}: "reboot"|"powerdown"|"shutdown"
+ * response{error}: <error code>
+ * response{errstr}: <error description>
+ */
+static QDict *va_shutdown(const QDict *params)
+{
+ int ret;
+ const char *shutdown_mode, *shutdown_flag;
+
+ shutdown_mode = qdict_get_try_str(params, "shutdown_mode");
+ SLOG("va_shutdown(), shutdown_mode:%s", shutdown_mode);
+
+ if (!shutdown_mode) {
+ ret = -EINVAL;
+ LOG("missing shutdown argument");
+ goto out;
+ } else if (strcmp(shutdown_mode, "halt") == 0) {
+ shutdown_flag = "-H";
+ } else if (strcmp(shutdown_mode, "powerdown") == 0) {
+ shutdown_flag = "-P";
+ } else if (strcmp(shutdown_mode, "reboot") == 0) {
+ shutdown_flag = "-r";
+ } else {
+ ret = -EINVAL;
+ LOG("invalid shutdown argument");
+ goto out;
+ }
+
+ ret = fork();
+ if (ret == 0) {
+ /* child, start the shutdown */
+ setsid();
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+
+ sleep(5);
+ ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
+ "hypervisor initiated shutdown", (char*)NULL);
+ if (ret < 0) {
+ LOG("execl() failed: %s", strerror(errno));
+ exit(1);
+ }
+ exit(0);
+ } else if (ret < 0) {
+ LOG("fork() failed: %s", strerror(errno));
+ } else {
+ ret = 0;
+ }
+
+out:
+ return va_server_format_response(NULL, ret, strerror(errno));
+}
+
static VARPCFunction guest_functions[] = {
{ .func = va_capabilities,
.func_name = "capabilities" },
{ .func = va_ping,
.func_name = "ping" },
+ { .func = va_shutdown,
+ .func_name = "shutdown" },
{ NULL, NULL }
};
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com> --- virtagent-server.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 58 insertions(+), 0 deletions(-)