From b255a024007eb236745b703586a2fed8bdedae6c Mon Sep 17 00:00:00 2001
From: AlexChen <alex.chen@huawei.com>
Date: Tue, 19 Oct 2021 22:11:45 +0800
Subject: [PATCH] hotpatch: Implement qemuDomainHotpatchManage

Signed-off-by: Hao Wang <wanghao232@huawei.com>
Signed-off-by: Bihong Yu <yubihong@huawei.com>
Signed-off-by: AlexChen <alex.chen@huawei.com>
---
 src/qemu/Makefile.inc.am |   2 +
 src/qemu/qemu_driver.c   |  48 +++++++++++
 src/qemu/qemu_hotpatch.c | 182 +++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_hotpatch.h |  36 ++++++++
 4 files changed, 268 insertions(+)
 create mode 100644 src/qemu/qemu_hotpatch.c
 create mode 100644 src/qemu/qemu_hotpatch.h

diff --git a/src/qemu/Makefile.inc.am b/src/qemu/Makefile.inc.am
index 51cd79879d..a1a8bfa17c 100644
--- a/src/qemu/Makefile.inc.am
+++ b/src/qemu/Makefile.inc.am
@@ -73,6 +73,8 @@ QEMU_DRIVER_SOURCES = \
 	qemu/qemu_checkpoint.h \
 	qemu/qemu_backup.c \
 	qemu/qemu_backup.h \
+	qemu/qemu_hotpatch.c \
+	qemu/qemu_hotpatch.h \
 	$(NULL)
 
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 5901f922bf..f6d99957a5 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -50,6 +50,7 @@
 #include "qemu_security.h"
 #include "qemu_checkpoint.h"
 #include "qemu_backup.h"
+#include "qemu_hotpatch.h"
 
 #include "virerror.h"
 #include "virlog.h"
@@ -23171,6 +23172,52 @@ qemuDomainAgentSetResponseTimeout(virDomainPtr dom,
     return ret;
 }
 
+static char *
+qemuDomainHotpatchManage(virDomainPtr domain,
+                         int action,
+                         const char *patch,
+                         const char *id,
+                         unsigned int flags)
+{
+    virDomainObjPtr vm;
+    char *ret = NULL;
+    size_t len;
+
+    virCheckFlags(0, NULL);
+
+    if (!(vm = qemuDomainObjFromDomain(domain)))
+        goto cleanup;
+
+    switch (action) {
+    case VIR_DOMAIN_HOTPATCH_APPLY:
+        ret = qemuDomainHotpatchApply(vm, patch);
+        break;
+
+    case VIR_DOMAIN_HOTPATCH_UNAPPLY:
+        ret = qemuDomainHotpatchUnapply(vm, id);
+        break;
+
+    case VIR_DOMAIN_HOTPATCH_QUERY:
+        ret = qemuDomainHotpatchQuery(vm);
+        break;
+
+    default:
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("Unknow hotpatch action"));
+    }
+
+    if (!ret)
+        goto endjob;
+
+    /* Wipeout redundant empty line */
+    len = strlen(ret);
+    if (len > 0)
+        ret[len - 1] = '\0';
+
+ cleanup:
+    virDomainObjEndAPI(&vm);
+    return ret;
+}
 
 static virHypervisorDriver qemuHypervisorDriver = {
     .name = QEMU_DRIVER_NAME,
@@ -23411,6 +23458,7 @@ static virHypervisorDriver qemuHypervisorDriver = {
     .domainAgentSetResponseTimeout = qemuDomainAgentSetResponseTimeout, /* 5.10.0 */
     .domainBackupBegin = qemuDomainBackupBegin, /* 6.0.0 */
     .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */
+    .domainHotpatchManage = qemuDomainHotpatchManage, /* 6.2.0 */
 };
 
 
diff --git a/src/qemu/qemu_hotpatch.c b/src/qemu/qemu_hotpatch.c
new file mode 100644
index 0000000000..45796b3f24
--- /dev/null
+++ b/src/qemu/qemu_hotpatch.c
@@ -0,0 +1,182 @@
+/*
+ * huawei_qemu_hotpatch.h: huawei qemu hotpatch functions
+ *
+ * Copyright (C) 2021-2021 HUAWEI, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include <unistd.h>
+#include "viralloc.h"
+#include "virerror.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "vircommand.h"
+#include "qemu/qemu_domain.h"
+#include "qemu_hotpatch.h"
+
+#define LIBCARE_CTL "libcare-ctl"
+#define LIBCARE_ERROR_NUMBER 255
+#define MAX_PATCHID_LEN 8
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+VIR_LOG_INIT("qemu_hotpatch");
+
+char *
+qemuDomainHotpatchQuery(virDomainObjPtr vm)
+{
+    g_autoptr(virCommand) cmd = NULL;
+    g_autofree char *binary = NULL;
+    char *output = NULL;
+    int ret = -1;
+
+    if (!(binary = virFindFileInPath(LIBCARE_CTL))) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("Failed to find libcare-ctl command."));
+        return NULL;
+    }
+
+    cmd = virCommandNewArgList(binary, "info", "-p", NULL);
+    virCommandAddArgFormat(cmd, "%d", vm->pid);
+    virCommandSetOutputBuffer(cmd, &output);
+
+    VIR_DEBUG("Querying hotpatch for domain %s. (%s info -p %d)",
+              vm->def->name, binary, vm->pid);
+
+    if (virCommandRun(cmd, &ret) < 0)
+        goto error;
+
+    if (ret == LIBCARE_ERROR_NUMBER) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("Failed to execute libcare-ctl command."));
+        goto error;
+    }
+    return output;
+
+ error:
+    VIR_FREE(output);
+    return NULL;
+}
+
+char *
+qemuDomainHotpatchApply(virDomainObjPtr vm,
+                        const char *patch)
+{
+    g_autoptr(virCommand) cmd = NULL;
+    g_autofree char *binary = NULL;
+    char *output = NULL;
+    int ret = -1;
+
+    if (!patch || !virFileExists(patch)) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       "%s", _("Invalid hotpatch file."));
+        return NULL;
+    }
+
+    if (!(binary = virFindFileInPath(LIBCARE_CTL))) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       "%s", _("Failed to find libcare-ctl command."));
+        return NULL;
+    }
+
+    cmd = virCommandNewArgList(binary, "patch", "-p", NULL);
+    virCommandAddArgFormat(cmd, "%d", vm->pid);
+    virCommandAddArgList(cmd, patch, NULL);
+    virCommandSetOutputBuffer(cmd, &output);
+
+    VIR_DEBUG("Applying hotpatch for domain %s. (%s patch -p %d %s)",
+              vm->def->name, binary, vm->pid, patch);
+
+    if (virCommandRun(cmd, &ret) < 0)
+        goto error;
+
+    if (ret == LIBCARE_ERROR_NUMBER) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("Failed to execute libcare-ctl command."));
+        goto error;
+    }
+    return output;
+
+ error:
+    VIR_FREE(output);
+    return NULL;
+}
+
+static bool
+qemuDomainHotpatchIsPatchidValid(const char *id)
+{
+    size_t len, i;
+
+    if (!id)
+        return false;
+
+    len = strlen(id);
+    if (len > MAX_PATCHID_LEN - 1)
+        return false;
+
+    for (i = 0; i < len; i++) {
+        if (!g_ascii_isalnum(*(id + i)))
+            return false;
+    }
+
+    return true;
+}
+
+char *
+qemuDomainHotpatchUnapply(virDomainObjPtr vm,
+                          const char *id)
+{
+    g_autoptr(virCommand) cmd = NULL;
+    g_autofree char *binary = NULL;
+    char *output = NULL;
+    int ret = -1;
+
+    if (!id || !qemuDomainHotpatchIsPatchidValid(id)) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       "%s", _("Invalid hotpatch id."));
+        return NULL;
+    }
+
+    if (!(binary = virFindFileInPath(LIBCARE_CTL))) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       "%s", _("Failed to find libcare-ctl command."));
+        return NULL;
+    }
+
+    cmd = virCommandNewArgList(binary, "unpatch", "-p", NULL);
+    virCommandAddArgFormat(cmd, "%d", vm->pid);
+    virCommandAddArgList(cmd, "-i", id, NULL);
+    virCommandSetOutputBuffer(cmd, &output);
+
+    VIR_DEBUG("Unapplying hotpatch for domain %s. (%s unpatch -p %d -i %s)",
+              vm->def->name, binary, vm->pid, id);
+
+    if (virCommandRun(cmd, &ret) < 0)
+        goto error;
+
+    if (ret == LIBCARE_ERROR_NUMBER) {
+        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
+                       _("Failed to execute libcare-ctl command."));
+        goto error;
+    }
+    return output;
+
+ error:
+    VIR_FREE(output);
+    return NULL;
+}
diff --git a/src/qemu/qemu_hotpatch.h b/src/qemu/qemu_hotpatch.h
new file mode 100644
index 0000000000..4c84a57950
--- /dev/null
+++ b/src/qemu/qemu_hotpatch.h
@@ -0,0 +1,36 @@
+/*
+ * huawei_qemu_hotpatch.h: huawei qemu hotpatch functions
+ *
+ * Copyright (C) 2021-2021 HUAWEI, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include "qemu/qemu_conf.h"
+
+char *
+qemuDomainHotpatchQuery(virDomainObjPtr vm);
+
+char *
+qemuDomainHotpatchApply(virDomainObjPtr vm,
+                        const char *patch);
+
+char *
+qemuDomainHotpatchUnapply(virDomainObjPtr vm,
+                          const char *id);
-- 
2.27.0

