[libvirt] [PATCH 5/8] Convert QEMU driver to use virCommand APIs

Daniel P. Berrange berrange at redhat.com
Mon Nov 22 18:09:24 UTC 2010


Switch the QEMU driver over to using the virCommand APIs
instead of passing around char **argv, **env.

* src/qemu/qemu_conf.c, src/qemu/qemu_conf.h,
  src/qemu/qemu_driver.c: Convert to virCommand
---
 src/locking/lock_manager.c |    2 +
 src/qemu/qemu_conf.c       |  632 +++++++++++++++++++-------------------------
 src/qemu/qemu_conf.h       |   21 +-
 src/qemu/qemu_driver.c     |  195 +++-----------
 4 files changed, 324 insertions(+), 526 deletions(-)

diff --git a/src/locking/lock_manager.c b/src/locking/lock_manager.c
index dc5e7d8..6bd2844 100644
--- a/src/locking/lock_manager.c
+++ b/src/locking/lock_manager.c
@@ -32,6 +32,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 
+#include "configmake.h"
+
 #define VIR_FROM_THIS VIR_FROM_LOCKING
 
 #define virLockError(code, ...)                                         \
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index dce9a63..ec255c9 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1554,12 +1554,24 @@ int qemudExtractVersionInfo(const char *qemu,
     int ret = -1, status;
     unsigned int version, is_kvm, kvm_version;
     unsigned long long flags = 0;
+    struct stat sb;
 
     if (retflags)
         *retflags = 0;
     if (retversion)
         *retversion = 0;
 
+    /* Make sure the binary we are about to try exec'ing exists.
+     * Technically we could catch the exec() failure, but that's
+     * in a sub-process so its hard to feed back a useful error
+     */
+    if (stat(qemu, &sb) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot find QEMU binary %s"),
+                             qemu);
+        return -1;
+    }
+
     if (virExec(qemuarg, qemuenv, NULL,
                 &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
         return -1;
@@ -3972,18 +3984,14 @@ qemuBuildSmpArgStr(const virDomainDefPtr def,
  * XXX 'conn' is only required to resolve network -> bridge name
  * figure out how to remove this requirement some day
  */
-int qemudBuildCommandLine(virConnectPtr conn,
-                          struct qemud_driver *driver,
-                          virDomainDefPtr def,
-                          virDomainChrDefPtr monitor_chr,
-                          int monitor_json,
-                          unsigned long long qemuCmdFlags,
-                          const char ***retargv,
-                          const char ***retenv,
-                          int **vmfds,
-                          int *nvmfds,
-                          const char *migrateFrom,
-                          virDomainSnapshotObjPtr current_snapshot)
+virCommandPtr qemudBuildCommandLine(virConnectPtr conn,
+                                    struct qemud_driver *driver,
+                                    virDomainDefPtr def,
+                                    virDomainChrDefPtr monitor_chr,
+                                    int monitor_json,
+                                    unsigned long long qemuCmdFlags,
+                                    const char *migrateFrom,
+                                    virDomainSnapshotObjPtr current_snapshot)
 {
     int i;
     char memory[50];
@@ -3993,10 +4001,6 @@ int qemudBuildCommandLine(virConnectPtr conn,
     int enableKQEMU = 0;
     int disableKVM = 0;
     int enableKVM = 0;
-    int qargc = 0, qarga = 0;
-    const char **qargv = NULL;
-    int qenvc = 0, qenva = 0;
-    const char **qenv = NULL;
     const char *emulator;
     char uuid[VIR_UUID_STRING_BUFLEN];
     char domid[50];
@@ -4004,11 +4008,12 @@ int qemudBuildCommandLine(virConnectPtr conn,
     char *smp;
     int last_good_net = -1;
     bool hasHwVirt = false;
+    virCommandPtr cmd;
 
     uname_normalize(&ut);
 
     if (qemuAssignDeviceAliases(def, qemuCmdFlags) < 0)
-        return -1;
+        return NULL;
 
     virUUIDFormat(def->uuid, uuid);
 
@@ -4020,7 +4025,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
             if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP)) {
                 qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                 "%s", _("TCP migration is not supported with this QEMU binary"));
-                return -1;
+                return NULL;
             }
         } else if (STREQ(migrateFrom, "stdio")) {
             if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
@@ -4028,13 +4033,13 @@ int qemudBuildCommandLine(virConnectPtr conn,
             } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO)) {
                 qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                 "%s", _("STDIO migration is not supported with this QEMU binary"));
-                return -1;
+                return NULL;
             }
         } else if (STRPREFIX(migrateFrom, "exec")) {
             if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC)) {
                 qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                 "%s", _("STDIO migration is not supported with this QEMU binary"));
-                return -1;
+                return NULL;
             }
         }
     }
@@ -4095,78 +4100,11 @@ int qemudBuildCommandLine(virConnectPtr conn,
         break;
     }
 
-#define ADD_ARG_SPACE                                                   \
-    do { \
-        if (qargc == qarga) {                                           \
-            qarga += 10;                                                \
-            if (VIR_REALLOC_N(qargv, qarga) < 0)                        \
-                goto no_memory;                                         \
-        }                                                               \
-    } while (0)
-
-#define ADD_ARG(thisarg)                                                \
-    do {                                                                \
-        ADD_ARG_SPACE;                                                  \
-        qargv[qargc++] = thisarg;                                       \
-    } while (0)
-
-#define ADD_ARG_LIT(thisarg)                                            \
-    do {                                                                \
-        ADD_ARG_SPACE;                                                  \
-        if ((qargv[qargc++] = strdup(thisarg)) == NULL)                 \
-            goto no_memory;                                             \
-    } while (0)
-
-#define ADD_USBDISK(thisarg)                                            \
-    do {                                                                \
-        ADD_ARG_LIT("-usbdevice");                                      \
-        ADD_ARG_SPACE;                                                  \
-        if ((virAsprintf((char **)&(qargv[qargc++]),                    \
-                         "disk:%s", thisarg)) == -1) {                  \
-            goto no_memory;                                             \
-        }                                                               \
-    } while (0)
-
-#define ADD_ENV_SPACE                                                   \
-    do {                                                                \
-        if (qenvc == qenva) {                                           \
-            qenva += 10;                                                \
-            if (VIR_REALLOC_N(qenv, qenva) < 0)                         \
-                goto no_memory;                                         \
-        }                                                               \
-    } while (0)
-
-#define ADD_ENV(thisarg)                                                \
-    do {                                                                \
-        ADD_ENV_SPACE;                                                  \
-        qenv[qenvc++] = thisarg;                                        \
-    } while (0)
-
-#define ADD_ENV_LIT(thisarg)                                            \
-    do {                                                                \
-        ADD_ENV_SPACE;                                                  \
-        if ((qenv[qenvc++] = strdup(thisarg)) == NULL)                  \
-            goto no_memory;                                             \
-    } while (0)
-
-#define ADD_ENV_PAIR(envname, val)                                      \
-    do {                                                                \
-        char *envval;                                                   \
-        ADD_ENV_SPACE;                                                  \
-        if (virAsprintf(&envval, "%s=%s", envname, val) < 0)            \
-            goto no_memory;                                             \
-        qenv[qenvc++] = envval;                                         \
-    } while (0)
-
-    /* Make sure to unset or set all envvars in qemuxml2argvtest.c that
-     * are copied here using this macro, otherwise the test may fail */
-#define ADD_ENV_COPY(envname)                                           \
-    do {                                                                \
-        char *val = getenv(envname);                                    \
-        if (val != NULL) {                                              \
-            ADD_ENV_PAIR(envname, val);                                 \
-        }                                                               \
-    } while (0)
+    cmd = virCommandNew(emulator);
+    if (!cmd) {
+        virReportOOMError();
+        return NULL;
+    }
 
     /* Set '-m MB' based on maxmem, because the lower 'memory' limit
      * is set post-startup using the balloon driver. If balloon driver
@@ -4175,26 +4113,17 @@ int qemudBuildCommandLine(virConnectPtr conn,
     snprintf(memory, sizeof(memory), "%lu", def->mem.max_balloon/1024);
     snprintf(domid, sizeof(domid), "%d", def->id);
 
-    ADD_ENV_LIT("LC_ALL=C");
+    virCommandAddEnvPassCommon(cmd);
 
-    ADD_ENV_COPY("LD_PRELOAD");
-    ADD_ENV_COPY("LD_LIBRARY_PATH");
-    ADD_ENV_COPY("PATH");
-    ADD_ENV_COPY("HOME");
-    ADD_ENV_COPY("USER");
-    ADD_ENV_COPY("LOGNAME");
-    ADD_ENV_COPY("TMPDIR");
-
-    ADD_ARG_LIT(emulator);
-    ADD_ARG_LIT("-S");
+    virCommandAddArg(cmd, "-S");
 
     /* This should *never* be NULL, since we always provide
      * a machine in the capabilities data for QEMU. So this
      * check is just here as a safety in case the unexpected
      * happens */
     if (def->os.machine) {
-        ADD_ARG_LIT("-M");
-        ADD_ARG_LIT(def->os.machine);
+        virCommandAddArg(cmd, "-M");
+        virCommandAddArg(cmd, def->os.machine);
     }
 
     if (qemuBuildCpuArgStr(driver, def, emulator, qemuCmdFlags,
@@ -4202,27 +4131,27 @@ int qemudBuildCommandLine(virConnectPtr conn,
         goto error;
 
     if (cpu) {
-        ADD_ARG_LIT("-cpu");
-        ADD_ARG_LIT(cpu);
+        virCommandAddArg(cmd, "-cpu");
+        virCommandAddArg(cmd, cpu);
         VIR_FREE(cpu);
 
         if ((qemuCmdFlags & QEMUD_CMD_FLAG_NESTING) &&
             hasHwVirt)
-            ADD_ARG_LIT("-enable-nesting");
+            virCommandAddArg(cmd, "-enable-nesting");
     }
 
     if (disableKQEMU)
-        ADD_ARG_LIT("-no-kqemu");
+        virCommandAddArg(cmd, "-no-kqemu");
     else if (enableKQEMU) {
-        ADD_ARG_LIT("-enable-kqemu");
-        ADD_ARG_LIT("-kernel-kqemu");
+        virCommandAddArg(cmd, "-enable-kqemu");
+        virCommandAddArg(cmd, "-kernel-kqemu");
     }
     if (disableKVM)
-        ADD_ARG_LIT("-no-kvm");
+        virCommandAddArg(cmd, "-no-kvm");
     if (enableKVM)
-        ADD_ARG_LIT("-enable-kvm");
-    ADD_ARG_LIT("-m");
-    ADD_ARG_LIT(memory);
+        virCommandAddArg(cmd, "-enable-kvm");
+    virCommandAddArg(cmd, "-m");
+    virCommandAddArg(cmd, memory);
     if (def->mem.hugepage_backed) {
         if (!driver->hugetlbfs_mount) {
             qemuReportError(VIR_ERR_INTERNAL_ERROR,
@@ -4240,43 +4169,44 @@ int qemudBuildCommandLine(virConnectPtr conn,
                             def->emulator);
             goto error;
         }
-        ADD_ARG_LIT("-mem-prealloc");
-        ADD_ARG_LIT("-mem-path");
-        ADD_ARG_LIT(driver->hugepage_path);
+        virCommandAddArg(cmd, "-mem-prealloc");
+        virCommandAddArg(cmd, "-mem-path");
+        virCommandAddArg(cmd, driver->hugepage_path);
     }
 
-    ADD_ARG_LIT("-smp");
+    virCommandAddArg(cmd, "-smp");
     if (!(smp = qemuBuildSmpArgStr(def, qemuCmdFlags)))
         goto error;
-    ADD_ARG(smp);
+    virCommandAddArg(cmd, smp);
+    VIR_FREE(smp);
 
     if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
-        ADD_ARG_LIT("-name");
+        virCommandAddArg(cmd, "-name");
         if (driver->setProcessName &&
             (qemuCmdFlags & QEMUD_CMD_FLAG_NAME_PROCESS)) {
             char *name;
             if (virAsprintf(&name, "%s,process=qemu:%s",
                             def->name, def->name) < 0)
                 goto no_memory;
-            ADD_ARG_LIT(name);
+            virCommandAddArg(cmd, name);
         } else {
-            ADD_ARG_LIT(def->name);
+            virCommandAddArg(cmd, def->name);
         }
     }
     if (qemuCmdFlags & QEMUD_CMD_FLAG_UUID) {
-        ADD_ARG_LIT("-uuid");
-        ADD_ARG_LIT(uuid);
+        virCommandAddArg(cmd, "-uuid");
+        virCommandAddArg(cmd, uuid);
     }
     if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
         STREQ(def->os.type, "xen") ||
         STREQ(def->os.type, "linux")) {
         if (qemuCmdFlags & QEMUD_CMD_FLAG_DOMID) {
-            ADD_ARG_LIT("-domid");
-            ADD_ARG_LIT(domid);
+            virCommandAddArg(cmd, "-domid");
+            virCommandAddArg(cmd, domid);
         } else if (qemuCmdFlags & QEMUD_CMD_FLAG_XEN_DOMID) {
-            ADD_ARG_LIT("-xen-attach");
-            ADD_ARG_LIT("-xen-domid");
-            ADD_ARG_LIT(domid);
+            virCommandAddArg(cmd, "-xen-attach");
+            virCommandAddArg(cmd, "-xen-domid");
+            virCommandAddArg(cmd, domid);
         } else {
             qemuReportError(VIR_ERR_INTERNAL_ERROR,
                             _("qemu emulator '%s' does not support xen"),
@@ -4318,13 +4248,15 @@ int qemudBuildCommandLine(virConnectPtr conn,
 
             smbioscmd = qemuBuildSmbiosBiosStr(source);
             if (smbioscmd != NULL) {
-                ADD_ARG_LIT("-smbios");
-                ADD_ARG(smbioscmd);
+                virCommandAddArg(cmd, "-smbios");
+                virCommandAddArg(cmd, smbioscmd);
+                VIR_FREE(smbioscmd);
             }
             smbioscmd = qemuBuildSmbiosSystemStr(source);
             if (smbioscmd != NULL) {
-                ADD_ARG_LIT("-smbios");
-                ADD_ARG(smbioscmd);
+                virCommandAddArg(cmd, "-smbios");
+                virCommandAddArg(cmd, smbioscmd);
+                VIR_FREE(smbioscmd);
             }
         }
     }
@@ -4337,12 +4269,12 @@ int qemudBuildCommandLine(virConnectPtr conn,
      * these defaults ourselves...
      */
     if (!def->graphics)
-        ADD_ARG_LIT("-nographic");
+        virCommandAddArg(cmd, "-nographic");
 
     if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
         if (qemuCmdFlags & QEMUD_CMD_FLAG_NODEFCONFIG)
-            ADD_ARG_LIT("-nodefconfig"); /* Disabling global config files */
-        ADD_ARG_LIT("-nodefaults");  /* Disabling default guest devices */
+            virCommandAddArg(cmd, "-nodefconfig"); /* Disabling global config files */
+        virCommandAddArg(cmd, "-nodefaults");  /* Disabling default guest devices */
     }
 
     if (monitor_chr) {
@@ -4350,39 +4282,42 @@ int qemudBuildCommandLine(virConnectPtr conn,
         /* Use -chardev if it's available */
         if (qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) {
 
-            ADD_ARG_LIT("-chardev");
+            virCommandAddArg(cmd, "-chardev");
             if (!(chrdev = qemuBuildChrChardevStr(monitor_chr)))
                 goto error;
-            ADD_ARG(chrdev);
+            virCommandAddArg(cmd, chrdev);
+            VIR_FREE(chrdev);
 
-            ADD_ARG_LIT("-mon");
+            virCommandAddArg(cmd, "-mon");
             if (monitor_json)
-                ADD_ARG_LIT("chardev=monitor,mode=control");
+                virCommandAddArg(cmd, "chardev=monitor,mode=control");
             else
-                ADD_ARG_LIT("chardev=monitor,mode=readline");
+                virCommandAddArg(cmd, "chardev=monitor,mode=readline");
         } else {
             const char *prefix = NULL;
             if (monitor_json)
                 prefix = "control,";
 
-            ADD_ARG_LIT("-monitor");
+            virCommandAddArg(cmd, "-monitor");
             if (!(chrdev = qemuBuildChrArgStr(monitor_chr, prefix)))
                 goto error;
-            ADD_ARG(chrdev);
+            virCommandAddArg(cmd, chrdev);
+            VIR_FREE(chrdev);
         }
     }
 
     if (qemuCmdFlags & QEMUD_CMD_FLAG_RTC) {
         const char *rtcopt;
-        ADD_ARG_LIT("-rtc");
+        virCommandAddArg(cmd, "-rtc");
         if (!(rtcopt = qemuBuildClockArgStr(&def->clock)))
             goto error;
-        ADD_ARG(rtcopt);
+        virCommandAddArg(cmd, rtcopt);
+        VIR_FREE(rtcopt);
     } else {
         switch (def->clock.offset) {
         case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
         case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
-            ADD_ARG_LIT("-localtime");
+            virCommandAddArg(cmd, "-localtime");
             break;
 
         case VIR_DOMAIN_CLOCK_OFFSET_UTC:
@@ -4397,9 +4332,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
         }
     }
     if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE &&
-        def->clock.data.timezone) {
-        ADD_ENV_PAIR("TZ", def->clock.data.timezone);
-    }
+        def->clock.data.timezone)
+        virCommandAddEnvPair(cmd, "TZ", def->clock.data.timezone);
 
     for (i = 0; i < def->clock.ntimers; i++) {
         switch (def->clock.timers[i]->name) {
@@ -4422,7 +4356,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
                     /* the default - do nothing */
                     break;
                 case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
-                    ADD_ARG_LIT("-rtc-td-hack");
+                    virCommandAddArg(cmd, "-rtc-td-hack");
                     break;
                 case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
                 case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
@@ -4451,14 +4385,14 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 /* delay is the default if we don't have kernel
                    (-no-kvm-pit), otherwise, the default is catchup. */
                 if (qemuCmdFlags & QEMUD_CMD_FLAG_NO_KVM_PIT)
-                    ADD_ARG_LIT("-no-kvm-pit-reinjection");
+                    virCommandAddArg(cmd, "-no-kvm-pit-reinjection");
                 break;
             case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
                 if (qemuCmdFlags & QEMUD_CMD_FLAG_NO_KVM_PIT) {
                     /* do nothing - this is default for kvm-pit */
                 } else if (qemuCmdFlags & QEMUD_CMD_FLAG_TDF) {
                     /* -tdf switches to 'catchup' with userspace pit. */
-                    ADD_ARG_LIT("-tdf");
+                    virCommandAddArg(cmd, "-tdf");
                 } else {
                     /* can't catchup if we have neither pit mode */
                     qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -4487,7 +4421,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
 
             if (qemuCmdFlags & QEMUD_CMD_FLAG_NO_HPET) {
                 if (def->clock.timers[i]->present == 0)
-                    ADD_ARG_LIT("-no-hpet");
+                    virCommandAddArg(cmd, "-no-hpet");
             } else {
                 /* no hpet timer available. The only possible action
                    is to raise an error if present="yes" */
@@ -4502,10 +4436,10 @@ int qemudBuildCommandLine(virConnectPtr conn,
 
     if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
         def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
-        ADD_ARG_LIT("-no-reboot");
+        virCommandAddArg(cmd, "-no-reboot");
 
     if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
-        ADD_ARG_LIT("-no-acpi");
+        virCommandAddArg(cmd, "-no-acpi");
 
     if (!def->os.bootloader) {
         for (i = 0 ; i < def->os.nBootDevs ; i++) {
@@ -4529,7 +4463,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
         }
         if (def->os.nBootDevs) {
             virBuffer boot_buf = VIR_BUFFER_INITIALIZER;
-            ADD_ARG_LIT("-boot");
+            char *bootstr;
+            virCommandAddArg(cmd, "-boot");
 
             boot[def->os.nBootDevs] = '\0';
 
@@ -4548,24 +4483,26 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 goto error;
             }
 
-            ADD_ARG(virBufferContentAndReset(&boot_buf));
+            bootstr = virBufferContentAndReset(&boot_buf);
+            virCommandAddArg(cmd, bootstr);
+            VIR_FREE(bootstr);
         }
 
         if (def->os.kernel) {
-            ADD_ARG_LIT("-kernel");
-            ADD_ARG_LIT(def->os.kernel);
+            virCommandAddArg(cmd, "-kernel");
+            virCommandAddArg(cmd, def->os.kernel);
         }
         if (def->os.initrd) {
-            ADD_ARG_LIT("-initrd");
-            ADD_ARG_LIT(def->os.initrd);
+            virCommandAddArg(cmd, "-initrd");
+            virCommandAddArg(cmd, def->os.initrd);
         }
         if (def->os.cmdline) {
-            ADD_ARG_LIT("-append");
-            ADD_ARG_LIT(def->os.cmdline);
+            virCommandAddArg(cmd, "-append");
+            virCommandAddArg(cmd, def->os.cmdline);
         }
     } else {
-        ADD_ARG_LIT("-bootloader");
-        ADD_ARG_LIT(def->os.bootloader);
+        virCommandAddArg(cmd, "-bootloader");
+        virCommandAddArg(cmd, def->os.bootloader);
     }
 
     for (i = 0 ; i < def->ndisks ; i++) {
@@ -4598,13 +4535,14 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 goto error;
             }
 
-            ADD_ARG_LIT("-device");
+            virCommandAddArg(cmd, "-device");
 
             char *devstr;
             if (!(devstr = qemuBuildControllerDevStr(def->controllers[i])))
                 goto no_memory;
 
-            ADD_ARG(devstr);
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
         }
     }
 
@@ -4640,7 +4578,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
             if ((disk->bus == VIR_DOMAIN_DISK_BUS_USB) &&
                 !(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
                 if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
-                    ADD_USBDISK(disk->src);
+                    virCommandAddArg(cmd, "-usbdevice");
+                    virCommandAddArg(cmd, disk->src);
                 } else {
                     qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("unsupported usb disk type for '%s'"), disk->src);
@@ -4664,7 +4603,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 break;
             }
 
-            ADD_ARG_LIT("-drive");
+            virCommandAddArg(cmd, "-drive");
 
             /* Unfortunately it is nt possible to use
                -device for floppys, or Xen paravirt
@@ -4678,24 +4617,27 @@ int qemudBuildCommandLine(virConnectPtr conn,
                                              (withDeviceArg ? qemuCmdFlags :
                                               (qemuCmdFlags & ~QEMUD_CMD_FLAG_DEVICE)))))
                 goto error;
-            ADD_ARG(optstr);
+            virCommandAddArg(cmd, optstr);
+            VIR_FREE(optstr);
 
             if (withDeviceArg) {
                 if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
                     char *fdc;
-                    ADD_ARG_LIT("-global");
+                    virCommandAddArg(cmd, "-global");
 
                     if (virAsprintf(&fdc, "isa-fdc.drive%c=drive-%s",
                                     disk->info.addr.drive.unit ? 'B' : 'A',
                                     disk->info.alias) < 0)
                         goto no_memory;
-                    ADD_ARG(fdc);
+                    virCommandAddArg(cmd, fdc);
+                    VIR_FREE(fdc);
                 } else {
-                    ADD_ARG_LIT("-device");
+                    virCommandAddArg(cmd, "-device");
 
                     if (!(optstr = qemuBuildDriveDevStr(disk)))
                         goto error;
-                    ADD_ARG(optstr);
+                    virCommandAddArg(cmd, optstr);
+                    VIR_FREE(optstr);
                 }
             }
         }
@@ -4707,7 +4649,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
 
             if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
                 if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
-                    ADD_USBDISK(disk->src);
+                    virCommandAddArg(cmd, "-usbdevice");
+                    virCommandAddArg(cmd, disk->src);
                 } else {
                     qemuReportError(VIR_ERR_INTERNAL_ERROR,
                                     _("unsupported usb disk type for '%s'"), disk->src);
@@ -4756,8 +4699,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 snprintf(file, PATH_MAX, "%s", disk->src);
             }
 
-            ADD_ARG_LIT(dev);
-            ADD_ARG_LIT(file);
+            virCommandAddArg(cmd, dev);
+            virCommandAddArg(cmd, file);
         }
     }
 
@@ -4766,15 +4709,17 @@ int qemudBuildCommandLine(virConnectPtr conn,
             char *optstr;
             virDomainFSDefPtr fs = def->fss[i];
 
-            ADD_ARG_LIT("-fsdev");
+            virCommandAddArg(cmd, "-fsdev");
             if (!(optstr = qemuBuildFSStr(fs, qemuCmdFlags)))
                 goto error;
-            ADD_ARG(optstr);
+            virCommandAddArg(cmd, optstr);
+            VIR_FREE(optstr);
 
-            ADD_ARG_LIT("-device");
+            virCommandAddArg(cmd, "-device");
             if (!(optstr = qemuBuildFSDevStr(fs)))
                 goto error;
-            ADD_ARG(optstr);
+            virCommandAddArg(cmd, optstr);
+            VIR_FREE(optstr);
         }
     } else {
         if (def->nfss) {
@@ -4787,8 +4732,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
     if (!def->nnets) {
         /* If we have -device, then we set -nodefault already */
         if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-            ADD_ARG_LIT("-net");
-            ADD_ARG_LIT("none");
+            virCommandAddArg(cmd, "-net");
+            virCommandAddArg(cmd, "none");
         }
     } else {
         for (i = 0 ; i < def->nnets ; i++) {
@@ -4811,15 +4756,9 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 if (tapfd < 0)
                     goto error;
 
-                if (VIR_REALLOC_N(*vmfds, (*nvmfds)+1) < 0) {
-                    virDomainConfNWFilterTeardown(net);
-                    VIR_FORCE_CLOSE(tapfd);
-                    goto no_memory;
-                }
-
                 last_good_net = i;
 
-                (*vmfds)[(*nvmfds)++] = tapfd;
+                virCommandPreserveFD(cmd, tapfd);
 
                 if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >= sizeof(tapfd_name))
                     goto no_memory;
@@ -4830,15 +4769,9 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 if (tapfd < 0)
                     goto error;
 
-                if (VIR_REALLOC_N(*vmfds, (*nvmfds)+1) < 0) {
-                    virDomainConfNWFilterTeardown(net);
-                    VIR_FORCE_CLOSE(tapfd);
-                    goto no_memory;
-                }
-
                 last_good_net = i;
 
-                (*vmfds)[(*nvmfds)++] = tapfd;
+                virCommandPreserveFD(cmd, tapfd);
 
                 if (snprintf(tapfd_name, sizeof(tapfd_name), "%d", tapfd) >= sizeof(tapfd_name))
                     goto no_memory;
@@ -4851,12 +4784,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
                    network device */
                 int vhostfd = qemudOpenVhostNet(net, qemuCmdFlags);
                 if (vhostfd >= 0) {
-                    if (VIR_REALLOC_N(*vmfds, (*nvmfds)+1) < 0) {
-                        VIR_FORCE_CLOSE(vhostfd);
-                        goto no_memory;
-                    }
+                    virCommandPreserveFD(cmd, vhostfd);
 
-                    (*vmfds)[(*nvmfds)++] = vhostfd;
                     if (snprintf(vhostfd_name, sizeof(vhostfd_name), "%d", vhostfd)
                         >= sizeof(vhostfd_name))
                         goto no_memory;
@@ -4872,30 +4801,34 @@ int qemudBuildCommandLine(virConnectPtr conn,
              */
             if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
                 (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                ADD_ARG_LIT("-netdev");
+                virCommandAddArg(cmd, "-netdev");
                 if (!(host = qemuBuildHostNetStr(net, ',', vlan,
                                                  tapfd_name, vhostfd_name)))
                     goto error;
-                ADD_ARG(host);
+                virCommandAddArg(cmd, host);
+                VIR_FREE(host);
             }
             if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-                ADD_ARG_LIT("-device");
+                virCommandAddArg(cmd, "-device");
                 if (!(nic = qemuBuildNicDevStr(net, vlan)))
                     goto error;
-                ADD_ARG(nic);
+                virCommandAddArg(cmd, nic);
+                VIR_FREE(nic);
             } else {
-                ADD_ARG_LIT("-net");
+                virCommandAddArg(cmd, "-net");
                 if (!(nic = qemuBuildNicStr(net, "nic,", vlan)))
                     goto error;
-                ADD_ARG(nic);
+                virCommandAddArg(cmd, nic);
+                VIR_FREE(nic);
             }
             if (!((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
                   (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))) {
-                ADD_ARG_LIT("-net");
+                virCommandAddArg(cmd, "-net");
                 if (!(host = qemuBuildHostNetStr(net, ',', vlan,
                                                  tapfd_name, vhostfd_name)))
                     goto error;
-                ADD_ARG(host);
+                virCommandAddArg(cmd, host);
+                VIR_FREE(host);
             }
         }
     }
@@ -4903,8 +4836,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
     if (!def->nserials) {
         /* If we have -device, then we set -nodefault already */
         if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-            ADD_ARG_LIT("-serial");
-            ADD_ARG_LIT("none");
+            virCommandAddArg(cmd, "-serial");
+            virCommandAddArg(cmd, "none");
         }
     } else {
         for (i = 0 ; i < def->nserials ; i++) {
@@ -4914,20 +4847,23 @@ int qemudBuildCommandLine(virConnectPtr conn,
             /* Use -chardev with -device if they are available */
             if ((qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) &&
                 (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                ADD_ARG_LIT("-chardev");
+                virCommandAddArg(cmd, "-chardev");
                 if (!(devstr = qemuBuildChrChardevStr(serial)))
                     goto error;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
 
-                ADD_ARG_LIT("-device");
+                virCommandAddArg(cmd, "-device");
                 if (virAsprintf(&devstr, "isa-serial,chardev=%s", serial->info.alias) < 0)
                     goto no_memory;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
             } else {
-                ADD_ARG_LIT("-serial");
+                virCommandAddArg(cmd, "-serial");
                 if (!(devstr = qemuBuildChrArgStr(serial, NULL)))
                     goto error;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
             }
         }
     }
@@ -4935,8 +4871,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
     if (!def->nparallels) {
         /* If we have -device, then we set -nodefault already */
         if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-            ADD_ARG_LIT("-parallel");
-            ADD_ARG_LIT("none");
+            virCommandAddArg(cmd, "-parallel");
+            virCommandAddArg(cmd, "none");
         }
     } else {
         for (i = 0 ; i < def->nparallels ; i++) {
@@ -4946,20 +4882,23 @@ int qemudBuildCommandLine(virConnectPtr conn,
             /* Use -chardev with -device if they are available */
             if ((qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) &&
                 (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                ADD_ARG_LIT("-chardev");
+                virCommandAddArg(cmd, "-chardev");
                 if (!(devstr = qemuBuildChrChardevStr(parallel)))
                     goto error;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
 
-                ADD_ARG_LIT("-device");
+                virCommandAddArg(cmd, "-device");
                 if (virAsprintf(&devstr, "isa-parallel,chardev=%s", parallel->info.alias) < 0)
                     goto no_memory;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
             } else {
-                ADD_ARG_LIT("-parallel");
+                virCommandAddArg(cmd, "-parallel");
                 if (!(devstr = qemuBuildChrArgStr(parallel, NULL)))
                       goto error;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
             }
         }
     }
@@ -4977,24 +4916,26 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 goto error;
             }
 
-            ADD_ARG_LIT("-chardev");
+            virCommandAddArg(cmd, "-chardev");
             if (!(devstr = qemuBuildChrChardevStr(channel)))
                 goto error;
-            ADD_ARG(devstr);
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
 
             char *addr = virSocketFormatAddr(channel->target.addr);
             if (!addr)
                 goto error;
             int port = virSocketGetPort(channel->target.addr);
 
-            ADD_ARG_LIT("-netdev");
+            virCommandAddArg(cmd, "-netdev");
             if (virAsprintf(&devstr, "user,guestfwd=tcp:%s:%i,chardev=%s,id=user-%s",
                             addr, port, channel->info.alias, channel->info.alias) < 0) {
                 VIR_FREE(addr);
                 goto no_memory;
             }
             VIR_FREE(addr);
-            ADD_ARG(devstr);
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
             break;
 
         case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
@@ -5004,15 +4945,17 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 goto error;
             }
 
-            ADD_ARG_LIT("-chardev");
+            virCommandAddArg(cmd, "-chardev");
             if (!(devstr = qemuBuildChrChardevStr(channel)))
                 goto error;
-            ADD_ARG(devstr);
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
 
-            ADD_ARG_LIT("-device");
+            virCommandAddArg(cmd, "-device");
             if (!(devstr = qemuBuildVirtioSerialPortDevStr(channel)))
                 goto error;
-            ADD_ARG(devstr);
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
             break;
         }
     }
@@ -5030,15 +4973,17 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 goto error;
             }
 
-            ADD_ARG_LIT("-chardev");
+            virCommandAddArg(cmd, "-chardev");
             if (!(devstr = qemuBuildChrChardevStr(console)))
                 goto error;
-            ADD_ARG(devstr);
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
 
-            ADD_ARG_LIT("-device");
+            virCommandAddArg(cmd, "-device");
             if (!(devstr = qemuBuildVirtioSerialPortDevStr(console)))
                 goto error;
-            ADD_ARG(devstr);
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
             break;
 
         case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL:
@@ -5052,20 +4997,21 @@ int qemudBuildCommandLine(virConnectPtr conn,
         }
     }
 
-    ADD_ARG_LIT("-usb");
+    virCommandAddArg(cmd, "-usb");
     for (i = 0 ; i < def->ninputs ; i++) {
         virDomainInputDefPtr input = def->inputs[i];
 
         if (input->bus == VIR_DOMAIN_INPUT_BUS_USB) {
             if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
                 char *optstr;
-                ADD_ARG_LIT("-device");
+                virCommandAddArg(cmd, "-device");
                 if (!(optstr = qemuBuildUSBInputDevStr(input)))
                     goto error;
-                ADD_ARG(optstr);
+                virCommandAddArg(cmd, optstr);
+                VIR_FREE(optstr);
             } else {
-                ADD_ARG_LIT("-usbdevice");
-                ADD_ARG_LIT(input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "mouse" : "tablet");
+                virCommandAddArg(cmd, "-usbdevice");
+                virCommandAddArg(cmd, input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ? "mouse" : "tablet");
             }
         }
     }
@@ -5109,7 +5055,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 virBufferAddLit(&opt, ",sasl");
 
                 if (driver->vncSASLdir)
-                    ADD_ENV_PAIR("SASL_CONF_DIR", driver->vncSASLdir);
+                    virCommandAddEnvPair(cmd, "SASL_CONF_DIR", driver->vncSASLdir);
 
                 /* TODO: Support ACLs later */
             }
@@ -5124,11 +5070,12 @@ int qemudBuildCommandLine(virConnectPtr conn,
 
         optstr = virBufferContentAndReset(&opt);
 
-        ADD_ARG_LIT("-vnc");
-        ADD_ARG(optstr);
+        virCommandAddArg(cmd, "-vnc");
+        virCommandAddArg(cmd, optstr);
+        VIR_FREE(optstr);
         if (def->graphics[0]->data.vnc.keymap) {
-            ADD_ARG_LIT("-k");
-            ADD_ARG_LIT(def->graphics[0]->data.vnc.keymap);
+            virCommandAddArg(cmd, "-k");
+            virCommandAddArg(cmd, def->graphics[0]->data.vnc.keymap);
         }
 
         /* Unless user requested it, set the audio backend to none, to
@@ -5136,45 +5083,34 @@ int qemudBuildCommandLine(virConnectPtr conn,
          * security issues and might not work when using VNC.
          */
         if (driver->vncAllowHostAudio) {
-            ADD_ENV_COPY("QEMU_AUDIO_DRV");
+            virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV");
         } else {
-            ADD_ENV_LIT("QEMU_AUDIO_DRV=none");
+            virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none");
         }
     } else if ((def->ngraphics == 1) &&
                def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
-        char *xauth = NULL;
-        char *display = NULL;
+        if (def->graphics[0]->data.sdl.xauth)
+            virCommandAddEnvPair(cmd, "XAUTHORITY",
+                                 def->graphics[0]->data.sdl.xauth);
+        if (def->graphics[0]->data.sdl.display)
+            virCommandAddEnvPair(cmd, "DISPLAY",
+                                 def->graphics[0]->data.sdl.display);
 
-        if (def->graphics[0]->data.sdl.xauth &&
-            virAsprintf(&xauth, "XAUTHORITY=%s",
-                        def->graphics[0]->data.sdl.xauth) < 0)
-            goto no_memory;
-        if (def->graphics[0]->data.sdl.display &&
-            virAsprintf(&display, "DISPLAY=%s",
-                        def->graphics[0]->data.sdl.display) < 0) {
-            VIR_FREE(xauth);
-            goto no_memory;
-        }
-
-        if (xauth)
-            ADD_ENV(xauth);
-        if (display)
-            ADD_ENV(display);
         if (def->graphics[0]->data.sdl.fullscreen)
-            ADD_ARG_LIT("-full-screen");
+            virCommandAddArg(cmd, "-full-screen");
 
         /* If using SDL for video, then we should just let it
          * use QEMU's host audio drivers, possibly SDL too
          * User can set these two before starting libvirtd
          */
-        ADD_ENV_COPY("QEMU_AUDIO_DRV");
-        ADD_ENV_COPY("SDL_AUDIODRIVER");
+        virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV");
+        virCommandAddEnvPass(cmd, "SDL_AUDIODRIVER");
 
         /* New QEMU has this flag to let us explicitly ask for
          * SDL graphics. This is better than relying on the
          * default, since the default changes :-( */
         if (qemuCmdFlags & QEMUD_CMD_FLAG_SDL)
-            ADD_ARG_LIT("-sdl");
+            virCommandAddArg(cmd, "-sdl");
 
     } else if ((def->ngraphics == 1) &&
                def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
@@ -5227,16 +5163,17 @@ int qemudBuildCommandLine(virConnectPtr conn,
 
         optstr = virBufferContentAndReset(&opt);
 
-        ADD_ARG_LIT("-spice");
-        ADD_ARG(optstr);
+        virCommandAddArg(cmd, "-spice");
+        virCommandAddArg(cmd, optstr);
+        VIR_FREE(optstr);
         if (def->graphics[0]->data.spice.keymap) {
-            ADD_ARG_LIT("-k");
-            ADD_ARG_LIT(def->graphics[0]->data.spice.keymap);
+            virCommandAddArg(cmd, "-k");
+            virCommandAddArg(cmd, def->graphics[0]->data.spice.keymap);
         }
         /* SPICE includes native support for tunnelling audio, so we
          * set the audio backend to point at SPICE's own driver
          */
-        ADD_ENV_LIT("QEMU_AUDIO_DRV=spice");
+        virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=spice");
 
     } else if ((def->ngraphics == 1)) {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
@@ -5265,18 +5202,18 @@ int qemudBuildCommandLine(virConnectPtr conn,
                     goto error;
                 }
 
-                ADD_ARG_LIT("-vga");
-                ADD_ARG_LIT(vgastr);
+                virCommandAddArg(cmd, "-vga");
+                virCommandAddArg(cmd, vgastr);
             }
         } else {
 
             switch (def->videos[0]->type) {
             case VIR_DOMAIN_VIDEO_TYPE_VGA:
-                ADD_ARG_LIT("-std-vga");
+                virCommandAddArg(cmd, "-std-vga");
                 break;
 
             case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
-                ADD_ARG_LIT("-vmwarevga");
+                virCommandAddArg(cmd, "-vmwarevga");
                 break;
 
             case VIR_DOMAIN_VIDEO_TYPE_XEN:
@@ -5303,12 +5240,13 @@ int qemudBuildCommandLine(virConnectPtr conn,
                         goto error;
                     }
 
-                    ADD_ARG_LIT("-device");
+                    virCommandAddArg(cmd, "-device");
 
                     if (!(str = qemuBuildVideoDevStr(def->videos[i])))
                         goto error;
 
-                    ADD_ARG(str);
+                    virCommandAddArg(cmd, str);
+                    VIR_FREE(str);
                 }
             } else {
                 qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
@@ -5321,8 +5259,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
         /* If we have -device, then we set -nodefault already */
         if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
             (qemuCmdFlags & QEMUD_CMD_FLAG_VGA)) {
-            ADD_ARG_LIT("-vga");
-            ADD_ARG_LIT("none");
+            virCommandAddArg(cmd, "-vga");
+            virCommandAddArg(cmd, "none");
         }
     }
 
@@ -5337,15 +5275,16 @@ int qemudBuildCommandLine(virConnectPtr conn,
                  * we don't need to set any PCI address on it, so we don't
                  * mind too much */
                 if (sound->model == VIR_DOMAIN_SOUND_MODEL_PCSPK) {
-                    ADD_ARG_LIT("-soundhw");
-                    ADD_ARG_LIT("pcspk");
+                    virCommandAddArg(cmd, "-soundhw");
+                    virCommandAddArg(cmd, "pcspk");
                 } else {
-                    ADD_ARG_LIT("-device");
+                    virCommandAddArg(cmd, "-device");
 
                     if (!(str = qemuBuildSoundDevStr(sound)))
                         goto error;
 
-                    ADD_ARG(str);
+                    virCommandAddArg(cmd, str);
+                    VIR_FREE(str);
                 }
             }
         } else {
@@ -5368,8 +5307,9 @@ int qemudBuildCommandLine(virConnectPtr conn,
                 if (i < (def->nsounds - 1))
                     strncat(modstr, ",", size--);
             }
-            ADD_ARG_LIT("-soundhw");
-            ADD_ARG(modstr);
+            virCommandAddArg(cmd, "-soundhw");
+            virCommandAddArg(cmd, modstr);
+            VIR_FREE(modstr);
         }
     }
 
@@ -5379,13 +5319,13 @@ int qemudBuildCommandLine(virConnectPtr conn,
         char *optstr;
 
         if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-            ADD_ARG_LIT("-device");
+            virCommandAddArg(cmd, "-device");
 
             optstr = qemuBuildWatchdogDevStr(watchdog);
             if (!optstr)
                 goto error;
         } else {
-            ADD_ARG_LIT("-watchdog");
+            virCommandAddArg(cmd, "-watchdog");
 
             const char *model = virDomainWatchdogModelTypeToString(watchdog->model);
             if (!model) {
@@ -5397,7 +5337,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
             if (!(optstr = strdup(model)))
                 goto no_memory;
         }
-        ADD_ARG(optstr);
+        virCommandAddArg(cmd, optstr);
+        VIR_FREE(optstr);
 
         const char *action = virDomainWatchdogActionTypeToString(watchdog->action);
         if (!action) {
@@ -5405,8 +5346,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
                             "%s", _("invalid watchdog action"));
             goto error;
         }
-        ADD_ARG_LIT("-watchdog-action");
-        ADD_ARG_LIT(action);
+        virCommandAddArg(cmd, "-watchdog-action");
+        virCommandAddArg(cmd, action);
     }
 
     /* Add host passthrough hardware */
@@ -5419,15 +5360,17 @@ int qemudBuildCommandLine(virConnectPtr conn,
             hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
 
             if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-                ADD_ARG_LIT("-device");
+                virCommandAddArg(cmd, "-device");
                 if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
                     goto error;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
             } else {
-                ADD_ARG_LIT("-usbdevice");
+                virCommandAddArg(cmd, "-usbdevice");
                 if (!(devstr = qemuBuildUSBHostdevUsbDevStr(hostdev)))
                     goto error;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
             }
         }
 
@@ -5446,26 +5389,22 @@ int qemudBuildCommandLine(virConnectPtr conn,
                             goto no_memory;
                         }
 
-                        if (VIR_REALLOC_N(*vmfds, (*nvmfds)+1) < 0) {
-                            VIR_FREE(configfd_name);
-                            VIR_FORCE_CLOSE(configfd);
-                            goto no_memory;
-                        }
-
-                        (*vmfds)[(*nvmfds)++] = configfd;
+                        virCommandPreserveFD(cmd, configfd);
                     }
                 }
-                ADD_ARG_LIT("-device");
+                virCommandAddArg(cmd, "-device");
                 devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name);
                 VIR_FREE(configfd_name);
                 if (!devstr)
                     goto error;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
             } else if (qemuCmdFlags & QEMUD_CMD_FLAG_PCIDEVICE) {
-                ADD_ARG_LIT("-pcidevice");
+                virCommandAddArg(cmd, "-pcidevice");
                 if (!(devstr = qemuBuildPCIHostdevPCIDevStr(hostdev)))
                     goto error;
-                ADD_ARG(devstr);
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
             } else {
                 qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                                 _("PCI device assignment is not supported by this version of qemu"));
@@ -5475,8 +5414,8 @@ int qemudBuildCommandLine(virConnectPtr conn,
     }
 
     if (migrateFrom) {
-        ADD_ARG_LIT("-incoming");
-        ADD_ARG_LIT(migrateFrom);
+        virCommandAddArg(cmd, "-incoming");
+        virCommandAddArg(cmd, migrateFrom);
     }
 
     /* QEMU changed its default behavior to not include the virtio balloon
@@ -5495,76 +5434,47 @@ int qemudBuildCommandLine(virConnectPtr conn,
         }
         if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
             char *optstr;
-            ADD_ARG_LIT("-device");
+            virCommandAddArg(cmd, "-device");
 
             optstr = qemuBuildMemballoonDevStr(def->memballoon);
             if (!optstr)
                 goto error;
-            ADD_ARG(optstr);
+            virCommandAddArg(cmd, optstr);
+            VIR_FREE(optstr);
         } else if (qemuCmdFlags & QEMUD_CMD_FLAG_BALLOON) {
-            ADD_ARG_LIT("-balloon");
-            ADD_ARG_LIT("virtio");
+            virCommandAddArg(cmd, "-balloon");
+            virCommandAddArg(cmd, "virtio");
         }
     }
 
     if (current_snapshot && current_snapshot->def->active) {
-        ADD_ARG_LIT("-loadvm");
-        ADD_ARG_LIT(current_snapshot->def->name);
+        virCommandAddArg(cmd, "-loadvm");
+        virCommandAddArg(cmd, current_snapshot->def->name);
     }
 
     if (def->namespaceData) {
-        qemuDomainCmdlineDefPtr cmd;
-
-        cmd = def->namespaceData;
-        for (i = 0; i < cmd->num_args; i++)
-            ADD_ARG_LIT(cmd->args[i]);
-        for (i = 0; i < cmd->num_env; i++) {
-            if (cmd->env_value[i])
-                ADD_ENV_PAIR(cmd->env_name[i], cmd->env_value[i]);
+        qemuDomainCmdlineDefPtr qemucmd;
+
+        qemucmd = def->namespaceData;
+        for (i = 0; i < qemucmd->num_args; i++)
+            virCommandAddArg(cmd, qemucmd->args[i]);
+        for (i = 0; i < qemucmd->num_env; i++) {
+            if (qemucmd->env_value[i])
+                virCommandAddEnvPair(cmd, qemucmd->env_name[i], qemucmd->env_value[i]);
             else
-                ADD_ENV_PAIR(cmd->env_name[i], "");
+                virCommandAddEnvPair(cmd, qemucmd->env_name[i], "");
         }
     }
 
-    ADD_ARG(NULL);
-    ADD_ENV(NULL);
-
-    *retargv = qargv;
-    *retenv = qenv;
-    return 0;
+    return cmd;
 
  no_memory:
     virReportOOMError();
  error:
     for (i = 0; i <= last_good_net; i++)
         virDomainConfNWFilterTeardown(def->nets[i]);
-    if (vmfds &&
-        *vmfds) {
-        for (i = 0; i < *nvmfds; i++)
-            VIR_FORCE_CLOSE((*vmfds)[i]);
-        VIR_FREE(*vmfds);
-        *nvmfds = 0;
-    }
-    if (qargv) {
-        for (i = 0 ; i < qargc ; i++)
-            VIR_FREE((qargv)[i]);
-        VIR_FREE(qargv);
-    }
-    if (qenv) {
-        for (i = 0 ; i < qenvc ; i++)
-            VIR_FREE((qenv)[i]);
-        VIR_FREE(qenv);
-    }
-    return -1;
-
-#undef ADD_ARG
-#undef ADD_ARG_LIT
-#undef ADD_ARG_SPACE
-#undef ADD_USBDISK
-#undef ADD_ENV
-#undef ADD_ENV_COPY
-#undef ADD_ENV_LIT
-#undef ADD_ENV_SPACE
+    virCommandFree(cmd);
+    return NULL;
 }
 
 
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 3789ed2..b006e75 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -41,6 +41,7 @@
 # include "driver.h"
 # include "bitmap.h"
 # include "locking/lock_manager.h"
+# include "command.h"
 
 # define qemudDebug(fmt, ...) do {} while(0)
 
@@ -230,18 +231,14 @@ int         qemudParseHelpStr           (const char *qemu,
                                          unsigned int *is_kvm,
                                          unsigned int *kvm_version);
 
-int         qemudBuildCommandLine       (virConnectPtr conn,
-                                         struct qemud_driver *driver,
-                                         virDomainDefPtr def,
-                                         virDomainChrDefPtr monitor_chr,
-                                         int monitor_json,
-                                         unsigned long long qemuCmdFlags,
-                                         const char ***retargv,
-                                         const char ***retenv,
-                                         int **vmfds,
-                                         int *nvmfds,
-                                         const char *migrateFrom,
-                                         virDomainSnapshotObjPtr current_snapshot)
+virCommandPtr qemudBuildCommandLine(virConnectPtr conn,
+                                    struct qemud_driver *driver,
+                                    virDomainDefPtr def,
+                                    virDomainChrDefPtr monitor_chr,
+                                    int monitor_json,
+                                    unsigned long long qemuCmdFlags,
+                                    const char *migrateFrom,
+                                    virDomainSnapshotObjPtr current_snapshot)
     ATTRIBUTE_NONNULL(1);
 
 /* With vlan == -1, use netdev syntax, else old hostnet */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9dcf02d..0b0b6fe 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3017,14 +3017,6 @@ qemuAssignPCIAddresses(virDomainDefPtr def)
     int ret = -1;
     unsigned long long qemuCmdFlags = 0;
     qemuDomainPCIAddressSetPtr addrs = NULL;
-    struct stat sb;
-
-    if (stat(def->emulator, &sb) < 0) {
-        virReportSystemError(errno,
-                             _("Cannot find QEMU binary %s"),
-                             def->emulator);
-        goto cleanup;
-    }
 
     if (qemudExtractVersionInfo(def->emulator,
                                 NULL,
@@ -3881,16 +3873,8 @@ static int qemudStartVMDaemon(virConnectPtr conn,
                               bool start_paused,
                               int stdin_fd,
                               const char *stdin_path) {
-    const char **argv = NULL, **tmp;
-    const char **progenv = NULL;
-    int i, ret, runflags;
-    struct stat sb;
-    int *vmfds = NULL;
-    int nvmfds = 0;
+    int ret;
     unsigned long long qemuCmdFlags;
-    fd_set keepfd;
-    const char *emulator;
-    pid_t child;
     int pos = -1;
     char ebuf[1024];
     char *pidfile = NULL;
@@ -3898,6 +3882,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
     char *timestamp;
     qemuDomainObjPrivatePtr priv = vm->privateData;
     virDomainLockPtr lock = NULL;
+    virCommandPtr cmd = NULL;
 
     struct qemudHookData hookData;
     hookData.conn = conn;
@@ -3905,8 +3890,6 @@ static int qemudStartVMDaemon(virConnectPtr conn,
     hookData.driver = driver;
     hookData.lockState = NULL; /* XXX add lock state from migration source ! */
 
-    FD_ZERO(&keepfd);
-
     DEBUG0("Beginning VM startup process");
 
     if (virDomainObjIsActive(vm)) {
@@ -3987,21 +3970,8 @@ static int qemudStartVMDaemon(virConnectPtr conn,
     if ((logfile = qemudLogFD(driver, vm->def->name)) < 0)
         goto cleanup;
 
-    emulator = vm->def->emulator;
-
-    /* Make sure the binary we are about to try exec'ing exists.
-     * Technically we could catch the exec() failure, but that's
-     * in a sub-process so its hard to feed back a useful error
-     */
-    if (stat(emulator, &sb) < 0) {
-        virReportSystemError(errno,
-                             _("Cannot find QEMU binary %s"),
-                             emulator);
-        goto cleanup;
-    }
-
     DEBUG0("Determing emulator version");
-    if (qemudExtractVersionInfo(emulator,
+    if (qemudExtractVersionInfo(vm->def->emulator,
                                 NULL,
                                 &qemuCmdFlags) < 0)
         goto cleanup;
@@ -4070,10 +4040,10 @@ static int qemudStartVMDaemon(virConnectPtr conn,
 
     DEBUG0("Building emulator command line");
     vm->def->id = driver->nextvmid++;
-    if (qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
-                              priv->monJSON, qemuCmdFlags, &argv, &progenv,
-                              &vmfds, &nvmfds, migrateFrom,
-                              vm->current_snapshot) < 0)
+    if (!(cmd = qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
+                                      priv->monJSON, qemuCmdFlags,
+                                      migrateFrom,
+                                      vm->current_snapshot)))
         goto cleanup;
 
     if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
@@ -4108,70 +4078,46 @@ static int qemudStartVMDaemon(virConnectPtr conn,
         VIR_FREE(timestamp);
     }
 
-    tmp = progenv;
-
-    while (*tmp) {
-        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
-            VIR_WARN("Unable to write envv to logfile: %s",
-                     virStrerror(errno, ebuf, sizeof ebuf));
-        if (safewrite(logfile, " ", 1) < 0)
-            VIR_WARN("Unable to write envv to logfile: %s",
-                     virStrerror(errno, ebuf, sizeof ebuf));
-        tmp++;
-    }
-    tmp = argv;
-    while (*tmp) {
-        if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
-            VIR_WARN("Unable to write argv to logfile: %s",
-                     virStrerror(errno, ebuf, sizeof ebuf));
-        if (safewrite(logfile, " ", 1) < 0)
-            VIR_WARN("Unable to write argv to logfile: %s",
-                     virStrerror(errno, ebuf, sizeof ebuf));
-        tmp++;
-    }
-    if (safewrite(logfile, "\n", 1) < 0)
-        VIR_WARN("Unable to write argv to logfile: %s",
-                 virStrerror(errno, ebuf, sizeof ebuf));
+    virCommandWriteArgLog(cmd, logfile);
 
     if ((pos = lseek(logfile, 0, SEEK_END)) < 0)
         VIR_WARN("Unable to seek to end of logfile: %s",
                  virStrerror(errno, ebuf, sizeof ebuf));
 
-    for (i = 0 ; i < nvmfds ; i++)
-        FD_SET(vmfds[i], &keepfd);
-
     VIR_DEBUG("Clear emulator capabilities: %d",
               driver->clearEmulatorCapabilities);
-    runflags = VIR_EXEC_NONBLOCK;
-    if (driver->clearEmulatorCapabilities) {
-        runflags |= VIR_EXEC_CLEAR_CAPS;
-    }
-
-    VIR_WARN("Executing %s", argv[0]);
-    ret = virExecDaemonize(argv, progenv, &keepfd, &child,
-                           stdin_fd, &logfile, &logfile,
-                           runflags,
-                           qemudSecurityHook, &hookData,
-                           pidfile);
-    VIR_WARN("Executing done %s", argv[0]);
+    /** XXXX runflags = VIR_EXEC_NONBLOCK; */
+    if (driver->clearEmulatorCapabilities)
+        virCommandClearCaps(cmd);
+
+    VIR_WARN("Executing %s", vm->def->emulator);
+    virCommandSetPreExecHook(cmd, qemudSecurityHook, &hookData);
+    virCommandSetInputFD(cmd, stdin_fd);
+    virCommandSetOutputFD(cmd, &logfile);
+    virCommandSetErrorFD(cmd, &logfile);
+    virCommandSetPidFile(cmd, pidfile);
+    virCommandDaemonize(cmd);
+
+    ret = virCommandRun(cmd, NULL);
+    VIR_WARN("Executing done %s", vm->def->emulator);
     VIR_FREE(pidfile);
 
     /* XXX this is bollocks. Need a sync point */
     sleep(5);
 
-    VIR_WARN("Locking %s", argv[0]);
+    VIR_WARN("Locking %s", vm->def->emulator);
     if (!(lock = virDomainLockForStartup(driver->contentLockManager,
                                          driver->metadataLockManager,
                                          NULL, /* XXX lock state */
                                          vm)))
         goto cleanup;
 
-    VIR_WARN("Labelling %s", argv[0]);
+    VIR_WARN("Labelling %s", vm->def->emulator);
     DEBUG0("Setting domain security labels");
     if (virSecurityManagerSetAllLabel(driver->securityManager,
                                       vm, stdin_path) < 0)
         goto cleanup;
-    VIR_WARN("All done %s", argv[0]);
+    VIR_WARN("All done %s", vm->def->emulator);
 
 
     /* wait for qemu process to to show up */
@@ -4181,6 +4127,11 @@ static int qemudStartVMDaemon(virConnectPtr conn,
                             _("Domain %s didn't show up\n"), vm->def->name);
             ret = -1;
         }
+#if 0
+    /*
+     * XXX this is bogus. It isn't safe to set vm->pid = chidl
+     * because child no longer exists.
+     */
     } else if (ret == -2) {
         /* The virExec process that launches the daemon failed. Pending on
          * when it failed (we can't determine for sure), there may be
@@ -4191,30 +4142,16 @@ static int qemudStartVMDaemon(virConnectPtr conn,
          */
         vm->pid = child;
         ret = 0;
+#endif
     }
 
     if (migrateFrom)
         start_paused = true;
     vm->state = start_paused ? VIR_DOMAIN_PAUSED : VIR_DOMAIN_RUNNING;
 
-    for (i = 0 ; argv[i] ; i++)
-        VIR_FREE(argv[i]);
-    VIR_FREE(argv);
-
-    for (i = 0 ; progenv[i] ; i++)
-        VIR_FREE(progenv[i]);
-    VIR_FREE(progenv);
-
     if (ret == -1) /* The VM failed to start; tear filters before taps */
         virDomainConfVMNWFilterTeardown(vm);
 
-    if (vmfds) {
-        for (i = 0 ; i < nvmfds ; i++) {
-            VIR_FORCE_CLOSE(vmfds[i]);
-        }
-        VIR_FREE(vmfds);
-    }
-
     if (ret == -1) /* The VM failed to start */
         goto cleanup;
 
@@ -4264,6 +4201,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
         goto cleanup;
 
     virDomainLockReleaseAndFree(lock);
+    virCommandFree(cmd);
 
     VIR_FORCE_CLOSE(logfile);
 
@@ -4274,14 +4212,15 @@ cleanup:
      * that will re-aquire the lock in order to perform relabelling
      */
     virDomainLockReleaseAndFree(lock);
+    virCommandFree(cmd);
+
+    VIR_FORCE_CLOSE(logfile);
 
     /* We jump here if we failed to start the VM for any reason, or
      * if we failed to initialize the now running VM. kill it off and
      * pretend we never started it */
     qemudShutdownVMDaemon(driver, vm, 0);
 
-    VIR_FORCE_CLOSE(logfile);
-
     return -1;
 }
 
@@ -7312,13 +7251,8 @@ static char *qemuDomainXMLToNative(virConnectPtr conn,
     struct qemud_driver *driver = conn->privateData;
     virDomainDefPtr def = NULL;
     virDomainChrDef monConfig;
-    const char *emulator;
     unsigned long long qemuCmdFlags;
-    struct stat sb;
-    const char **retargv = NULL;
-    const char **retenv = NULL;
-    const char **tmp;
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    virCommandPtr cmd = NULL;
     char *ret = NULL;
     int i;
 
@@ -7368,69 +7302,24 @@ static char *qemuDomainXMLToNative(virConnectPtr conn,
             def->graphics[i]->data.vnc.autoport)
             def->graphics[i]->data.vnc.port = 5900;
     }
-    emulator = def->emulator;
-
-    /* Make sure the binary we are about to try exec'ing exists.
-     * Technically we could catch the exec() failure, but that's
-     * in a sub-process so its hard to feed back a useful error
-     */
-    if (stat(emulator, &sb) < 0) {
-        virReportSystemError(errno,
-                             _("Cannot find QEMU binary %s"),
-                             emulator);
-        goto cleanup;
-    }
 
-    if (qemudExtractVersionInfo(emulator,
+    if (qemudExtractVersionInfo(def->emulator,
                                 NULL,
-                                &qemuCmdFlags) < 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("Cannot determine QEMU argv syntax %s"),
-                        emulator);
+                                &qemuCmdFlags) < 0)
         goto cleanup;
-    }
 
     if (qemuPrepareMonitorChr(driver, &monConfig, def->name) < 0)
         goto cleanup;
 
-    if (qemudBuildCommandLine(conn, driver, def,
-                              &monConfig, 0, qemuCmdFlags,
-                              &retargv, &retenv,
-                              NULL, NULL, /* Don't want it to create TAP devices */
-                              NULL, NULL) < 0) {
-        goto cleanup;
-    }
-
-    tmp = retenv;
-    while (*tmp) {
-        virBufferAdd(&buf, *tmp, strlen(*tmp));
-        virBufferAddLit(&buf, " ");
-        tmp++;
-    }
-    tmp = retargv;
-    while (*tmp) {
-        virBufferAdd(&buf, *tmp, strlen(*tmp));
-        virBufferAddLit(&buf, " ");
-        tmp++;
-    }
-
-    if (virBufferError(&buf)) {
-        virBufferFreeAndReset(&buf);
-        virReportOOMError();
+    if (!(cmd = qemudBuildCommandLine(conn, driver, def,
+                                      &monConfig, 0, qemuCmdFlags,
+                                      NULL, NULL)))
         goto cleanup;
-    }
 
-    ret = virBufferContentAndReset(&buf);
+    ret = virCommandToString(cmd);
 
 cleanup:
     qemuDriverUnlock(driver);
-    for (tmp = retargv ; tmp && *tmp ; tmp++)
-        VIR_FREE(*tmp);
-    VIR_FREE(retargv);
-
-    for (tmp = retenv ; tmp && *tmp ; tmp++)
-        VIR_FREE(*tmp);
-    VIR_FREE(retenv);
 
     virDomainDefFree(def);
     return ret;
-- 
1.7.2.3




More information about the libvir-list mailing list