[PATCH v2] qemu: introduce load qemu.conf for "virt-qemu-run"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Adding a new option --config (or -c) for specifying a custom
qemu.conf file.

Previously, virt-qemu-run loaded default configuration values for
QEMU via qemuStateInitialize(). The configuration was loaded from
a temporary ../etc/ directory using virQEMUDriverConfigLoadFile(),
and any qemu.conf file present in that directory was also loaded
automatically.

This patch allows users to specify a custom configuration file,
which is copied into the temporary directory (or a permanent
folder if the -r option is used) before loading the
configuration. If an existing qemu.conf is present, it is
properly backed up and restored in case of a permanent folder.
The custom qemu.conf is always removed when the program exits.

Resolves: https://gitlab.com/libvirt/libvirt/-/issues/723
Signed-off-by: Adam Julis <ajulis@xxxxxxxxxx>
---
Changes to v1:
- formatting
- g_strdup
- deleted redundant variables, cleanup
- naming
- error in loading function caused interrupting of program

 docs/manpages/virt-qemu-run.rst |   9 +++
 src/qemu/qemu_shim.c            | 120 +++++++++++++++++++++++++++++++-
 2 files changed, 128 insertions(+), 1 deletion(-)

diff --git a/docs/manpages/virt-qemu-run.rst b/docs/manpages/virt-qemu-run.rst
index 4d546ff8cc..ba1c90b52a 100644
--- a/docs/manpages/virt-qemu-run.rst
+++ b/docs/manpages/virt-qemu-run.rst
@@ -72,6 +72,15 @@ whose UUID should match a secret referenced in the guest domain XML.
 
 Display verbose information about startup.
 
+``-c`` *QEMU-CONF-FILE*,
+``--config``\ =\ *QEMU-CONF-FILE*
+
+Specify the QEMU configuration file to be used for starting the VM.
+*QEMU-CONF-FILE* is the full path to the QEMU configuration file.
+
+If this parameter is omitted, the default configuration values will
+be used.
+
 ``-h``, ``--help``
 
 Display the command line help.
diff --git a/src/qemu/qemu_shim.c b/src/qemu/qemu_shim.c
index 7fdd69b538..9672b85183 100644
--- a/src/qemu/qemu_shim.c
+++ b/src/qemu/qemu_shim.c
@@ -23,6 +23,7 @@
 #include <stdio.h>
 #include <stdbool.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "virfile.h"
 #include "virgettext.h"
@@ -132,6 +133,101 @@ qemuShimQuench(void *userData G_GNUC_UNUSED,
 {
 }
 
+/* Load specific QEMU config file for the -c option */
+static int
+qemuAddConfigFile(const char *source_file,
+                  const char *root,
+                  char **old_config_file,
+                  char **saved_config_file,
+                  long long deltams)
+{
+    struct stat st;
+    VIR_AUTOCLOSE srcFD = -1;
+    VIR_AUTOCLOSE dstFD = -1;
+    g_autofree char *config_dir = NULL;
+    g_autofree char *config_dir_file = NULL;
+    g_autofree char *config_dir_file_real = NULL;
+    g_autofree char *source_file_real = NULL;
+
+    if (source_file == NULL)
+        return 0;
+
+    if ((srcFD = open(source_file, O_RDONLY)) < 0) {
+        g_printerr("Couldn't open specific config file\n");
+        return -1;
+    }
+
+    if (fstat(srcFD, &st) != 0) {
+        g_printerr("Specific config file does not exist\n");
+        return -1;
+    }
+    if (!S_ISREG(st.st_mode)) {
+        g_printerr("Specific config is not a regular file\n");
+        return -1;
+    }
+
+    /* Since source file exists, make the destination path or
+     * validate that it already exists */
+    config_dir = g_strdup_printf("%s/etc/", root);
+
+    if (g_mkdir_with_parents(config_dir, 0777) < 0) {
+        g_printerr("Couldn't make the directory for specific config file\n");
+        return -1;
+    }
+
+    config_dir_file = g_strdup_printf("%sqemu.conf", config_dir);
+
+    /* If the source file is same as the destination file, no action needed */
+    if ((source_file_real = realpath(source_file, NULL)) &&
+        (config_dir_file_real = realpath(config_dir_file, NULL))) {
+        if (STREQ(source_file_real, config_dir_file_real)) {
+            return 0;
+        }
+    }
+
+    /* Check already existing qemu.conf in the subfolder, if so, renamed
+     * (appended via deltams constant - should be unique). Final cleanup
+     * at main() will revert this change */
+    if (access(config_dir_file, R_OK) == 0) {
+        *old_config_file = g_strdup_printf("%sqemu_old_%lld.conf",
+                                            config_dir, deltams);
+
+        if (rename(config_dir_file, *old_config_file) != 0) {
+            g_printerr("Couldn't rename old config file, try delete it\n");
+            return -1;
+        }
+    }
+
+    if ((dstFD = open(config_dir_file, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) {
+        g_printerr("Couldn't open file for define specific config\n");
+        return -1;
+    }
+
+    *saved_config_file = g_steal_pointer(&config_dir_file);
+
+    do {
+        char buffer[1024];
+        ssize_t nread = 0;
+
+        nread = saferead(srcFD, buffer, 1024);
+
+        if (nread < 0) {
+            g_printerr("Couldn't read from specific config\n");
+            return -1;
+        } else if (nread == 0) {
+            break;
+        } else {
+            ssize_t nwrite = safewrite(dstFD, buffer, nread);
+            if (nwrite != nread) {
+                g_printerr("Couldn't write to file for define specific config\n");
+                return -1;
+            }
+        }
+    } while (1);
+
+    return 0;
+}
+
 int main(int argc, char **argv)
 {
     g_autoptr(virIdentity) sysident = NULL;
@@ -141,7 +237,10 @@ int main(int argc, char **argv)
     g_autofree char *xml = NULL;
     g_autofree char *uri = NULL;
     g_autofree char *suri = NULL;
+    g_autofree char *old_config_file = NULL;
+    g_autofree char *saved_config_file = NULL;
     const char *root = NULL;
+    const char *config = NULL;
     g_autofree char *escaped = NULL;
     bool tmproot = false;
     int ret = 1;
@@ -156,6 +255,7 @@ int main(int argc, char **argv)
         { "root", 'r', 0, G_OPTION_ARG_STRING, &root, "Root directory", "DIR" },
         { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug, "Debug output", NULL },
         { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Verbose output", NULL },
+        { "config", 'c', 0, G_OPTION_ARG_STRING, &config, "Load specific QEMU configuration file", "QEMU-CONF-FILE"},
         { 0 }
     };
     int quitfd[2] = {-1, -1};
@@ -172,7 +272,7 @@ int main(int argc, char **argv)
         return 1;
     }
 
-    if (argc != 2) {
+    if (argc != 2 && argc != 3) {
         g_autofree char *help = g_option_context_get_help(ctx, TRUE, NULL);
         g_printerr("%s", help);
         return 1;
@@ -234,6 +334,12 @@ int main(int argc, char **argv)
         goto cleanup;
     }
 
+    if (config && qemuAddConfigFile(config, root, &old_config_file,
+                                    &saved_config_file, deltams()) < 0) {
+        g_printerr("Specific config file was not loaded, process interupted\n");
+        goto cleanup;
+    }
+
     escaped = g_uri_escape_string(root, NULL, true);
 
     virFileActivateDirOverrideForProg(argv[0]);
@@ -402,6 +508,18 @@ int main(int argc, char **argv)
     VIR_FORCE_CLOSE(quitfd[0]);
     VIR_FORCE_CLOSE(quitfd[1]);
 
+    if (saved_config_file) {
+        if (remove(saved_config_file) != 0)
+            g_printerr("Deleting specific config failed, located in: %s\n",
+                        saved_config_file);
+
+        if (old_config_file && access(old_config_file, R_OK) == 0) {
+            if (rename(old_config_file, saved_config_file) != 0)
+                g_printerr("Renaming your old qemu.conf failed, ups, located in %s\n",
+                           old_config_file);
+        }
+    }
+
     if (dom != NULL)
         virDomainFree(dom);
     if (sconn != NULL)
-- 
2.47.1




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux