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

[libvirt] [PATCH 02/10] Move QEMU command line management into a separate file



The qemu_conf.c code is doing three jobs, driver config file
loading, QEMU capabilities management and QEMU command line
management. Move the command line code into its own file

* src/qemu/qemu_command.c, src/qemu/qemu_command.h: New
  command line management code
* src/qemu/qemu_conf.c, src/qemu/qemu_conf.h: Delete command
  line code
* src/qemu/qemu_conf.h, src/qemu_conf.c: Adapt for API renames
* src/Makefile.am: add src/qemu/qemu_command.c
* src/qemu/qemu_monitor_json.c, src/qemu/qemu_monitor_text.c: Add
  import of qemu_command.h
---
 src/Makefile.am              |    1 +
 src/qemu/qemu_command.c      | 5793 ++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_command.h      |  165 ++
 src/qemu/qemu_conf.c         | 5748 -----------------------------------------
 src/qemu/qemu_conf.h         |  134 -
 src/qemu/qemu_driver.c       |   27 +-
 src/qemu/qemu_monitor_json.c |    2 +-
 src/qemu/qemu_monitor_text.c |    2 +-
 8 files changed, 5975 insertions(+), 5897 deletions(-)
 create mode 100644 src/qemu/qemu_command.c
 create mode 100644 src/qemu/qemu_command.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 4ce0b35..d4626d9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -268,6 +268,7 @@ VBOX_DRIVER_EXTRA_DIST = vbox/vbox_tmpl.c vbox/README
 
 QEMU_DRIVER_SOURCES =						\
 		qemu/qemu_capabilities.c qemu/qemu_capabilities.h\
+		qemu/qemu_command.c qemu/qemu_command.h		\
 		qemu/qemu_conf.c qemu/qemu_conf.h		\
 		qemu/qemu_monitor.c qemu/qemu_monitor.h		\
 		qemu/qemu_monitor_text.c			\
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
new file mode 100644
index 0000000..bde3904
--- /dev/null
+++ b/src/qemu/qemu_command.c
@@ -0,0 +1,5793 @@
+/*
+ * qemu_command.c: QEMU command generation
+ *
+ * Copyright (C) 2006-2007, 2009-2010 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange redhat com>
+ */
+
+#include <config.h>
+
+#include "qemu_command.h"
+#include "qemu_capabilities.h"
+#include "qemu_bridge_filter.h"
+#include "cpu/cpu.h"
+#include "memory.h"
+#include "logging.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "files.h"
+#include "uuid.h"
+#include "c-ctype.h"
+#include "domain_nwfilter.h"
+
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+
+VIR_ENUM_DECL(virDomainDiskQEMUBus)
+VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
+              "ide",
+              "floppy",
+              "scsi",
+              "virtio",
+              "xen",
+              "usb",
+              "uml",
+              "sata")
+
+
+VIR_ENUM_DECL(qemuDiskCacheV1)
+VIR_ENUM_DECL(qemuDiskCacheV2)
+
+VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST,
+              "default",
+              "off",
+              "off", /* writethrough not supported, so for safety, disable */
+              "on"); /* Old 'on' was equivalent to 'writeback' */
+
+VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST,
+              "default",
+              "none",
+              "writethrough",
+              "writeback");
+
+VIR_ENUM_DECL(qemuVideo)
+
+VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
+              "std",
+              "cirrus",
+              "vmware",
+              "", /* no arg needed for xen */
+              "", /* don't support vbox */
+              "qxl");
+
+static void
+uname_normalize (struct utsname *ut)
+{
+    uname(ut);
+
+    /* Map i386, i486, i586 to i686.  */
+    if (ut->machine[0] == 'i' &&
+        ut->machine[1] != '\0' &&
+        ut->machine[2] == '8' &&
+        ut->machine[3] == '6' &&
+        ut->machine[4] == '\0')
+        ut->machine[1] = '6';
+}
+
+
+/**
+ * qemuPhysIfaceConnect:
+ * @conn: pointer to virConnect object
+ * @driver: pointer to the qemud_driver
+ * @net: pointer to he VM's interface description with direct device type
+ * @qemuCmdFlags: flags for qemu
+ * @vmuuid: The UUID of the VM (needed by 802.1Qbh)
+ *
+ * Returns a filedescriptor on success or -1 in case of error.
+ */
+int
+qemuPhysIfaceConnect(virConnectPtr conn,
+                     struct qemud_driver *driver,
+                     virDomainNetDefPtr net,
+                     unsigned long long qemuCmdFlags,
+                     const unsigned char *vmuuid,
+                     enum virVMOperationType vmop)
+{
+    int rc;
+#if WITH_MACVTAP
+    char *res_ifname = NULL;
+    int vnet_hdr = 0;
+    int err;
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR &&
+        net->model && STREQ(net->model, "virtio"))
+        vnet_hdr = 1;
+
+    rc = openMacvtapTap(net->ifname, net->mac, net->data.direct.linkdev,
+                        net->data.direct.mode, vnet_hdr, vmuuid,
+                        &net->data.direct.virtPortProfile, &res_ifname,
+                        vmop);
+    if (rc >= 0) {
+        VIR_FREE(net->ifname);
+        net->ifname = res_ifname;
+    }
+
+    if (rc >=0 && driver->macFilter) {
+        if ((err = networkAllowMacOnPort(driver, net->ifname, net->mac))) {
+            virReportSystemError(err,
+                 _("failed to add ebtables rule to allow MAC address on  '%s'"),
+                                 net->ifname);
+        }
+    }
+
+    if (rc >= 0) {
+        if ((net->filter) && (net->ifname)) {
+            err = virDomainConfNWFilterInstantiate(conn, net);
+            if (err) {
+                VIR_FORCE_CLOSE(rc);
+                delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
+                           &net->data.direct.virtPortProfile);
+                VIR_FREE(net->ifname);
+            }
+        }
+    }
+#else
+    (void)conn;
+    (void)net;
+    (void)qemuCmdFlags;
+    (void)driver;
+    (void)vmuuid;
+    (void)vmop;
+    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                    "%s", _("No support for macvtap device"));
+    rc = -1;
+#endif
+    return rc;
+}
+
+
+int
+qemuNetworkIfaceConnect(virConnectPtr conn,
+                        struct qemud_driver *driver,
+                        virDomainNetDefPtr net,
+                        unsigned long long qemuCmdFlags)
+{
+    char *brname = NULL;
+    int err;
+    int tapfd = -1;
+    int vnet_hdr = 0;
+    int template_ifname = 0;
+    unsigned char tapmac[VIR_MAC_BUFLEN];
+
+    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
+        int active, fail = 0;
+        virErrorPtr errobj;
+        virNetworkPtr network = virNetworkLookupByName(conn,
+                                                       net->data.network.name);
+        if (!network)
+            return -1;
+
+        active = virNetworkIsActive(network);
+        if (active != 1) {
+            fail = 1;
+
+            if (active == 0)
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("Network '%s' is not active."),
+                                net->data.network.name);
+        }
+
+        if (!fail) {
+            brname = virNetworkGetBridgeName(network);
+            if (brname == NULL)
+                fail = 1;
+        }
+
+        /* Make sure any above failure is preserved */
+        errobj = virSaveLastError();
+        virNetworkFree(network);
+        virSetError(errobj);
+        virFreeError(errobj);
+
+        if (fail)
+            return -1;
+
+    } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+        if (!(brname = strdup(net->data.bridge.brname))) {
+            virReportOOMError();
+            return -1;
+        }
+    } else {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("Network type %d is not supported"), net->type);
+        return -1;
+    }
+
+    if (!driver->brctl && (err = brInit(&driver->brctl))) {
+        virReportSystemError(err, "%s",
+                             _("cannot initialize bridge support"));
+        goto cleanup;
+    }
+
+    if (!net->ifname ||
+        STRPREFIX(net->ifname, "vnet") ||
+        strchr(net->ifname, '%')) {
+        VIR_FREE(net->ifname);
+        if (!(net->ifname = strdup("vnet%d"))) {
+            virReportOOMError();
+            goto cleanup;
+        }
+        /* avoid exposing vnet%d in dumpxml or error outputs */
+        template_ifname = 1;
+    }
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR &&
+        net->model && STREQ(net->model, "virtio"))
+        vnet_hdr = 1;
+
+    memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
+    tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
+    if ((err = brAddTap(driver->brctl,
+                        brname,
+                        &net->ifname,
+                        tapmac,
+                        vnet_hdr,
+                        &tapfd))) {
+        if (err == ENOTSUP) {
+            /* In this particular case, give a better diagnostic. */
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Failed to add tap interface to bridge. "
+                              "%s is not a bridge device"), brname);
+        } else if (err == ENOENT) {
+            /* When the tun drive is missing, give a better message. */
+            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                            _("Failed to add tap interface to bridge. "
+                              "Your kernel is missing the 'tun' module or "
+                              "CONFIG_TUN, or you need to add the "
+                              "/dev/net/tun device node."));
+        } else if (template_ifname) {
+            virReportSystemError(err,
+                                 _("Failed to add tap interface to bridge '%s'"),
+                                 brname);
+        } else {
+            virReportSystemError(err,
+                                 _("Failed to add tap interface '%s' to bridge '%s'"),
+                                 net->ifname, brname);
+        }
+        if (template_ifname)
+            VIR_FREE(net->ifname);
+        tapfd = -1;
+    }
+
+    if (driver->macFilter) {
+        if ((err = networkAllowMacOnPort(driver, net->ifname, net->mac))) {
+            virReportSystemError(err,
+                 _("failed to add ebtables rule to allow MAC address on  '%s'"),
+                                 net->ifname);
+        }
+    }
+
+    if (tapfd >= 0) {
+        if ((net->filter) && (net->ifname)) {
+            err = virDomainConfNWFilterInstantiate(conn, net);
+            if (err)
+                VIR_FORCE_CLOSE(tapfd);
+        }
+    }
+
+cleanup:
+    VIR_FREE(brname);
+
+    return tapfd;
+}
+
+
+int
+qemuOpenVhostNet(virDomainNetDefPtr net,
+                 unsigned long long qemuCmdFlags)
+{
+
+    /* If qemu supports vhost-net mode (including the -netdev command
+     * option), the nic model is virtio, and we can open
+     * /dev/vhost_net, assume that vhost-net mode is available and
+     * return the fd to /dev/vhost_net. Otherwise, return -1.
+     */
+
+    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HOST &&
+          qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV &&
+          qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE &&
+          net->model && STREQ(net->model, "virtio")))
+        return -1;
+
+    return open("/dev/vhost-net", O_RDWR, 0);
+}
+
+
+static int qemuDomainDeviceAliasIndex(virDomainDeviceInfoPtr info,
+                                      const char *prefix)
+{
+    int idx;
+
+    if (!info->alias)
+        return -1;
+    if (!STRPREFIX(info->alias, prefix))
+        return -1;
+
+    if (virStrToLong_i(info->alias + strlen(prefix), NULL, 10, &idx) < 0)
+        return -1;
+
+    return idx;
+}
+
+
+int qemuDomainNetVLAN(virDomainNetDefPtr def)
+{
+    return qemuDomainDeviceAliasIndex(&def->info, "net");
+}
+
+
+/* Names used before -drive existed */
+static int qemuAssignDeviceDiskAliasLegacy(virDomainDiskDefPtr disk)
+{
+    char *devname;
+
+    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
+        STREQ(disk->dst, "hdc"))
+        devname = strdup("cdrom");
+    else
+        devname = strdup(disk->dst);
+
+    if (!devname) {
+        virReportOOMError();
+        return -1;
+    }
+
+    disk->info.alias = devname;
+    return 0;
+}
+
+
+char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
+                               unsigned long long qemudCmdFlags)
+{
+    char *ret;
+
+    if (qemudCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+        if (virAsprintf(&ret, "%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0) {
+            virReportOOMError();
+            return NULL;
+        }
+    } else {
+        if (!(ret = strdup(disk->info.alias))) {
+            virReportOOMError();
+            return NULL;
+        }
+    }
+    return ret;
+}
+
+
+/* Names used before -drive supported the id= option */
+static int qemuAssignDeviceDiskAliasFixed(virDomainDiskDefPtr disk)
+{
+    int busid, devid;
+    int ret;
+    char *devname;
+
+    if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot convert disk '%s' to bus/device index"),
+                        disk->dst);
+        return -1;
+    }
+
+    switch (disk->bus) {
+    case VIR_DOMAIN_DISK_BUS_IDE:
+        if (disk->device== VIR_DOMAIN_DISK_DEVICE_DISK)
+            ret = virAsprintf(&devname, "ide%d-hd%d", busid, devid);
+        else
+            ret = virAsprintf(&devname, "ide%d-cd%d", busid, devid);
+        break;
+    case VIR_DOMAIN_DISK_BUS_SCSI:
+        if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
+            ret = virAsprintf(&devname, "scsi%d-hd%d", busid, devid);
+        else
+            ret = virAsprintf(&devname, "scsi%d-cd%d", busid, devid);
+        break;
+    case VIR_DOMAIN_DISK_BUS_FDC:
+        ret = virAsprintf(&devname, "floppy%d", devid);
+        break;
+    case VIR_DOMAIN_DISK_BUS_VIRTIO:
+        ret = virAsprintf(&devname, "virtio%d", devid);
+        break;
+    case VIR_DOMAIN_DISK_BUS_XEN:
+        ret = virAsprintf(&devname, "xenblk%d", devid);
+        break;
+    default:
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                        _("Unsupported disk name mapping for bus '%s'"),
+                        virDomainDiskBusTypeToString(disk->bus));
+        return -1;
+    }
+
+    if (ret == -1) {
+        virReportOOMError();
+        return -1;
+    }
+
+    disk->info.alias = devname;
+
+    return 0;
+}
+
+
+/* Our custom -drive naming scheme used with id= */
+static int qemuAssignDeviceDiskAliasCustom(virDomainDiskDefPtr disk)
+{
+    const char *prefix = virDomainDiskBusTypeToString(disk->bus);
+    if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+        if (virAsprintf(&disk->info.alias, "%s%d-%d-%d", prefix,
+                        disk->info.addr.drive.controller,
+                        disk->info.addr.drive.bus,
+                        disk->info.addr.drive.unit) < 0)
+            goto no_memory;
+    } else {
+        int idx = virDiskNameToIndex(disk->dst);
+        if (virAsprintf(&disk->info.alias, "%s-disk%d", prefix, idx) < 0)
+            goto no_memory;
+    }
+
+    return 0;
+
+no_memory:
+    virReportOOMError();
+    return -1;
+}
+
+
+int
+qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, unsigned long long qemuCmdFlags)
+{
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
+            return qemuAssignDeviceDiskAliasCustom(def);
+        else
+            return qemuAssignDeviceDiskAliasFixed(def);
+    } else {
+        return qemuAssignDeviceDiskAliasLegacy(def);
+    }
+}
+
+
+int
+qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx)
+{
+    if (idx == -1) {
+        int i;
+        idx = 0;
+        for (i = 0 ; i < def->nnets ; i++) {
+            int thisidx;
+            if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "net")) < 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                _("Unable to determine device index for network device"));
+                return -1;
+            }
+            if (thisidx >= idx)
+                idx = thisidx + 1;
+        }
+    }
+
+    if (virAsprintf(&net->info.alias, "net%d", idx) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int
+qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx)
+{
+    if (idx == -1) {
+        int i;
+        idx = 0;
+        for (i = 0 ; i < def->nhostdevs ; i++) {
+            int thisidx;
+            if ((thisidx = qemuDomainDeviceAliasIndex(&def->hostdevs[i]->info, "hostdev")) < 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                _("Unable to determine device index for hostdevwork device"));
+                return -1;
+            }
+            if (thisidx >= idx)
+                idx = thisidx + 1;
+        }
+    }
+
+    if (virAsprintf(&hostdev->info.alias, "hostdev%d", idx) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int
+qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
+{
+    const char *prefix = virDomainControllerTypeToString(controller->type);
+
+    if (virAsprintf(&controller->info.alias,  "%s%d", prefix,
+                    controller->idx) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int
+qemuAssignDeviceAliases(virDomainDefPtr def, unsigned long long qemuCmdFlags)
+{
+    int i;
+
+    for (i = 0; i < def->ndisks ; i++) {
+        if (qemuAssignDeviceDiskAlias(def->disks[i], qemuCmdFlags) < 0)
+            return -1;
+    }
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
+        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+        for (i = 0; i < def->nnets ; i++) {
+            if (qemuAssignDeviceNetAlias(def, def->nets[i], i) < 0)
+                return -1;
+        }
+    }
+
+    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
+        return 0;
+
+    for (i = 0; i < def->nfss ; i++) {
+        if (virAsprintf(&def->fss[i]->info.alias, "fs%d", i) < 0)
+            goto no_memory;
+    }
+    for (i = 0; i < def->nsounds ; i++) {
+        if (virAsprintf(&def->sounds[i]->info.alias, "sound%d", i) < 0)
+            goto no_memory;
+    }
+    for (i = 0; i < def->nhostdevs ; i++) {
+        if (qemuAssignDeviceHostdevAlias(def, def->hostdevs[i], i) < 0)
+            return -1;
+    }
+    for (i = 0; i < def->nvideos ; i++) {
+        if (virAsprintf(&def->videos[i]->info.alias, "video%d", i) < 0)
+            goto no_memory;
+    }
+    for (i = 0; i < def->ncontrollers ; i++) {
+        if (qemuAssignDeviceControllerAlias(def->controllers[i]) < 0)
+            return -1;
+    }
+    for (i = 0; i < def->ninputs ; i++) {
+        if (virAsprintf(&def->inputs[i]->info.alias, "input%d", i) < 0)
+            goto no_memory;
+    }
+    for (i = 0; i < def->nparallels ; i++) {
+        if (virAsprintf(&def->parallels[i]->info.alias, "parallel%d", i) < 0)
+            goto no_memory;
+    }
+    for (i = 0; i < def->nserials ; i++) {
+        if (virAsprintf(&def->serials[i]->info.alias, "serial%d", i) < 0)
+            goto no_memory;
+    }
+    for (i = 0; i < def->nchannels ; i++) {
+        if (virAsprintf(&def->channels[i]->info.alias, "channel%d", i) < 0)
+            goto no_memory;
+    }
+    if (def->console) {
+        if (virAsprintf(&def->console->info.alias, "console%d", i) < 0)
+            goto no_memory;
+    }
+    if (def->watchdog) {
+        if (virAsprintf(&def->watchdog->info.alias, "watchdog%d", 0) < 0)
+            goto no_memory;
+    }
+    if (def->memballoon) {
+        if (virAsprintf(&def->memballoon->info.alias, "balloon%d", 0) < 0)
+            goto no_memory;
+    }
+
+    return 0;
+
+    no_memory:
+    virReportOOMError();
+    return -1;
+}
+
+
+#define QEMU_PCI_ADDRESS_LAST_SLOT 31
+struct _qemuDomainPCIAddressSet {
+    virHashTablePtr used;
+    int nextslot;
+};
+
+
+static char *qemuPCIAddressAsString(virDomainDeviceInfoPtr dev)
+{
+    char *addr;
+
+    if (dev->addr.pci.domain != 0 ||
+        dev->addr.pci.bus != 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Only PCI domain 0 and bus 0 are available"));
+        return NULL;
+    }
+
+    if (virAsprintf(&addr, "%d:%d:%d",
+                    dev->addr.pci.domain,
+                    dev->addr.pci.bus,
+                    dev->addr.pci.slot) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+    return addr;
+}
+
+
+static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
+                                 virDomainDeviceInfoPtr dev,
+                                 void *opaque)
+{
+    qemuDomainPCIAddressSetPtr addrs = opaque;
+
+    if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+        char *addr = qemuPCIAddressAsString(dev);
+        if (!addr)
+            return -1;
+
+        VIR_DEBUG("Remembering PCI addr %s", addr);
+
+        if (virHashAddEntry(addrs->used, addr, addr) < 0) {
+            VIR_FREE(addr);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+
+qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def)
+{
+    qemuDomainPCIAddressSetPtr addrs;
+
+    if (VIR_ALLOC(addrs) < 0)
+        goto no_memory;
+
+    if (!(addrs->used = virHashCreate(10)))
+        goto no_memory;
+
+    if (virDomainDeviceInfoIterate(def, qemuCollectPCIAddress, addrs) < 0)
+        goto error;
+
+    return addrs;
+
+no_memory:
+    virReportOOMError();
+error:
+    qemuDomainPCIAddressSetFree(addrs);
+    return NULL;
+}
+
+int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev)
+{
+    char *addr;
+
+    addr = qemuPCIAddressAsString(dev);
+    if (!addr)
+        return -1;
+
+    VIR_DEBUG("Reserving PCI addr %s", addr);
+
+    if (virHashLookup(addrs->used, addr)) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unable to reserve PCI address %s"), addr);
+        VIR_FREE(addr);
+        return -1;
+    }
+
+    if (virHashAddEntry(addrs->used, addr, addr)) {
+        VIR_FREE(addr);
+        return -1;
+    }
+
+    if (dev->addr.pci.slot > addrs->nextslot) {
+        addrs->nextslot = dev->addr.pci.slot + 1;
+        if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
+            addrs->nextslot = 0;
+    }
+
+    return 0;
+}
+
+int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
+                                    int slot)
+{
+    virDomainDeviceInfo dev;
+
+    dev.addr.pci.domain = 0;
+    dev.addr.pci.bus = 0;
+    dev.addr.pci.slot = slot;
+
+    return qemuDomainPCIAddressReserveAddr(addrs, &dev);
+}
+
+
+int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev)
+{
+    int ret = 0;
+    if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
+        ret = qemuDomainPCIAddressReserveAddr(addrs, dev);
+    else
+        ret = qemuDomainPCIAddressSetNextAddr(addrs, dev);
+    return ret;
+}
+
+static void qemuDomainPCIAddressSetFreeEntry(void *payload, const char *name ATTRIBUTE_UNUSED)
+{
+    VIR_FREE(payload);
+}
+
+
+int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev)
+{
+    char *addr;
+    int ret;
+
+    addr = qemuPCIAddressAsString(dev);
+    if (!addr)
+        return -1;
+
+    ret = virHashRemoveEntry(addrs->used, addr, qemuDomainPCIAddressSetFreeEntry);
+
+    VIR_FREE(addr);
+
+    return ret;
+}
+
+
+void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
+{
+    if (!addrs)
+        return;
+
+    virHashFree(addrs->used, qemuDomainPCIAddressSetFreeEntry);
+    VIR_FREE(addrs);
+}
+
+
+int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev)
+{
+    int i;
+    int iteration;
+
+    for (i = addrs->nextslot, iteration = 0;
+         iteration <= QEMU_PCI_ADDRESS_LAST_SLOT; i++, iteration++) {
+        virDomainDeviceInfo maybe;
+        char *addr;
+
+        if (QEMU_PCI_ADDRESS_LAST_SLOT < i)
+            i = 0;
+        memset(&maybe, 0, sizeof(maybe));
+        maybe.addr.pci.domain = 0;
+        maybe.addr.pci.bus = 0;
+        maybe.addr.pci.slot = i;
+
+        if (!(addr = qemuPCIAddressAsString(&maybe)))
+            return -1;
+
+        if (virHashLookup(addrs->used, addr)) {
+            VIR_DEBUG("PCI addr %s already in use", addr);
+            VIR_FREE(addr);
+            continue;
+        }
+
+        VIR_DEBUG("Allocating PCI addr %s", addr);
+
+        if (virHashAddEntry(addrs->used, addr, addr) < 0) {
+            VIR_FREE(addr);
+            return -1;
+        }
+
+        dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+        dev->addr.pci = maybe.addr.pci;
+
+        addrs->nextslot = i + 1;
+        if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
+            addrs->nextslot = 0;
+
+        return 0;
+    }
+
+    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                    "%s", _("No more available PCI addresses"));
+    return -1;
+}
+
+/*
+ * This assigns static PCI slots to all configured devices.
+ * The ordering here is chosen to match the ordering used
+ * with old QEMU < 0.12, so that if a user updates a QEMU
+ * host from old QEMU to QEMU >= 0.12, their guests should
+ * get PCI addresses in the same order as before.
+ *
+ * NB, if they previously hotplugged devices then all bets
+ * are off. Hotplug for old QEMU was unfixably broken wrt
+ * to stable PCI addressing.
+ *
+ * Order is:
+ *
+ *  - Host bridge (slot 0)
+ *  - PIIX3 ISA bridge, IDE controller, something else unknown, USB controller (slot 1)
+ *  - Video (slot 2)
+ *
+ * Incrementally assign slots from 3 onwards:
+ *
+ *  - Net
+ *  - Sound
+ *  - SCSI controllers
+ *  - VirtIO block
+ *  - VirtIO balloon
+ *  - Host device passthrough
+ *  - Watchdog
+ *
+ * Prior to this function being invoked, qemuCollectPCIAddress() will have
+ * added all existing PCI addresses from the 'def' to 'addrs'. Thus this
+ * function must only try to reserve addresses if info.type == NONE and
+ * skip over info.type == PCI
+ */
+int
+qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
+{
+    int i;
+    bool reservedIDE = false;
+
+    /* Host bridge */
+    if (qemuDomainPCIAddressReserveSlot(addrs, 0) < 0)
+        goto error;
+
+    /* Verify that first IDE controller (if any) is on the PIIX3, fn 1 */
+    for (i = 0; i < def->ncontrollers ; i++) {
+        /* First IDE controller lives on the PIIX3 at slot=1, function=1 */
+        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
+            def->controllers[i]->idx == 0) {
+            if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+                if (def->controllers[i]->info.addr.pci.domain != 0 ||
+                    def->controllers[i]->info.addr.pci.bus != 0 ||
+                    def->controllers[i]->info.addr.pci.slot != 1 ||
+                    def->controllers[i]->info.addr.pci.function != 1) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("Primary IDE controller must have PCI address 0:0:1.1"));
+                    goto error;
+                }
+                /* If TYPE==PCI, then then qemuCollectPCIAddress() function
+                 * has already reserved the address, so we must skip */
+                reservedIDE = true;
+            } else {
+                def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+                def->controllers[i]->info.addr.pci.domain = 0;
+                def->controllers[i]->info.addr.pci.bus = 0;
+                def->controllers[i]->info.addr.pci.slot = 1;
+                def->controllers[i]->info.addr.pci.function = 1;
+            }
+        }
+    }
+
+    /* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller)
+     * hardcoded slot=1, multifunction device
+     */
+    if (!reservedIDE &&
+        qemuDomainPCIAddressReserveSlot(addrs, 1) < 0)
+        goto error;
+
+    /* First VGA is hardcoded slot=2 */
+    if (def->nvideos > 0) {
+        if (def->videos[0]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+            if (def->videos[0]->info.addr.pci.domain != 0 ||
+                def->videos[0]->info.addr.pci.bus != 0 ||
+                def->videos[0]->info.addr.pci.slot != 2 ||
+                def->videos[0]->info.addr.pci.function != 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                _("Primary video card must have PCI address 0:0:2.0"));
+                goto error;
+            }
+        } else {
+            def->videos[0]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
+            def->videos[0]->info.addr.pci.domain = 0;
+            def->videos[0]->info.addr.pci.bus = 0;
+            def->videos[0]->info.addr.pci.slot = 2;
+            def->videos[0]->info.addr.pci.function = 0;
+            if (qemuDomainPCIAddressReserveSlot(addrs, 2) < 0)
+                goto error;
+        }
+    }
+    for (i = 0; i < def->nfss ; i++) {
+        if (def->fss[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+
+        /* Only support VirtIO-9p-pci so far. If that changes,
+         * we might need to skip devices here */
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->fss[i]->info) < 0)
+            goto error;
+    }
+
+    /* Network interfaces */
+    for (i = 0; i < def->nnets ; i++) {
+        if (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->nets[i]->info) < 0)
+            goto error;
+    }
+
+    /* Sound cards */
+    for (i = 0; i < def->nsounds ; i++) {
+        if (def->sounds[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+        /* Skip ISA sound card, and PCSPK */
+        if (def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_SB16 ||
+            def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK)
+            continue;
+
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->sounds[i]->info) < 0)
+            goto error;
+    }
+
+    /* Disk controllers (SCSI only for now) */
+    for (i = 0; i < def->ncontrollers ; i++) {
+        /* FDC lives behind the ISA bridge */
+        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC)
+            continue;
+
+        /* First IDE controller lives on the PIIX3 at slot=1, function=1,
+           dealt with earlier on*/
+        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
+            def->controllers[i]->idx == 0)
+            continue;
+
+        if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
+            goto error;
+    }
+
+    /* Disks (VirtIO only for now */
+    for (i = 0; i < def->ndisks ; i++) {
+        if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+
+        /* Only VirtIO disks use PCI addrs */
+        if (def->disks[i]->bus != VIR_DOMAIN_DISK_BUS_VIRTIO)
+            continue;
+
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->disks[i]->info) < 0)
+            goto error;
+    }
+
+    /* Host PCI devices */
+    for (i = 0; i < def->nhostdevs ; i++) {
+        if (def->hostdevs[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
+            def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
+            continue;
+
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->hostdevs[i]->info) < 0)
+            goto error;
+    }
+
+    /* VirtIO balloon */
+    if (def->memballoon &&
+        def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
+        def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->memballoon->info) < 0)
+            goto error;
+    }
+
+    /* A watchdog */
+    if (def->watchdog &&
+        def->watchdog->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->watchdog->info) < 0)
+            goto error;
+    }
+
+    /* Further non-primary video cards */
+    for (i = 1; i < def->nvideos ; i++) {
+        if (def->videos[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+            continue;
+        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->videos[i]->info) < 0)
+            goto error;
+    }
+    for (i = 0; i < def->ninputs ; i++) {
+        /* Nada - none are PCI based (yet) */
+    }
+    for (i = 0; i < def->nparallels ; i++) {
+        /* Nada - none are PCI based (yet) */
+    }
+    for (i = 0; i < def->nserials ; i++) {
+        /* Nada - none are PCI based (yet) */
+    }
+    for (i = 0; i < def->nchannels ; i++) {
+        /* Nada - none are PCI based (yet) */
+    }
+
+    return 0;
+
+error:
+    return -1;
+}
+
+
+static int
+qemuBuildDeviceAddressStr(virBufferPtr buf,
+                          virDomainDeviceInfoPtr info)
+{
+    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+        if (info->addr.pci.domain != 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                            _("Only PCI device addresses with domain=0 are supported"));
+            return -1;
+        }
+        if (info->addr.pci.bus != 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                            _("Only PCI device addresses with bus=0 are supported"));
+            return -1;
+        }
+        if (info->addr.pci.function != 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                            _("Only PCI device addresses with function=0 are supported"));
+            return -1;
+        }
+
+        /* XXX
+         * When QEMU grows support for > 1 PCI bus, then pci.0 changes
+         * to pci.1, pci.2, etc
+         * When QEMU grows support for > 1 PCI domain, then pci.0 change
+         * to pciNN.0  where NN is the domain number
+         */
+        virBufferVSprintf(buf, ",bus=pci.0,addr=0x%x", info->addr.pci.slot);
+    }
+    return 0;
+}
+
+
+#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
+  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
+
+static int
+qemuSafeSerialParamValue(const char *value)
+{
+    if (strspn(value, QEMU_SERIAL_PARAM_ACCEPTED_CHARS) != strlen (value)) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("driver serial '%s' contains unsafe characters"),
+                        value);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+char *
+qemuBuildDriveStr(virDomainDiskDefPtr disk,
+                  int bootable,
+                  unsigned long long qemuCmdFlags)
+{
+    virBuffer opt = VIR_BUFFER_INITIALIZER;
+    const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
+    int idx = virDiskNameToIndex(disk->dst);
+    int busid = -1, unitid = -1;
+
+    if (idx < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unsupported disk type '%s'"), disk->dst);
+        goto error;
+    }
+
+    switch (disk->bus) {
+    case VIR_DOMAIN_DISK_BUS_SCSI:
+        if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                            _("unexpected address type for scsi disk"));
+            goto error;
+        }
+
+        /* Setting bus= attr for SCSI drives, causes a controller
+         * to be created. Yes this is slightly odd. It is not possible
+         * to have > 1 bus on a SCSI controller (yet). */
+        if (disk->info.addr.drive.bus != 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("SCSI controller only supports 1 bus"));
+            goto error;
+        }
+        busid = disk->info.addr.drive.controller;
+        unitid = disk->info.addr.drive.unit;
+        break;
+
+    case VIR_DOMAIN_DISK_BUS_IDE:
+        if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                            _("unexpected address type for ide disk"));
+            goto error;
+        }
+        /* We can only have 1 IDE controller (currently) */
+        if (disk->info.addr.drive.controller != 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Only 1 %s controller is supported"), bus);
+            goto error;
+        }
+        busid = disk->info.addr.drive.bus;
+        unitid = disk->info.addr.drive.unit;
+        break;
+
+    case VIR_DOMAIN_DISK_BUS_FDC:
+        if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                            _("unexpected address type for fdc disk"));
+            goto error;
+        }
+        /* We can only have 1 FDC controller (currently) */
+        if (disk->info.addr.drive.controller != 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Only 1 %s controller is supported"), bus);
+            goto error;
+        }
+        /* We can only have 1 FDC bus (currently) */
+        if (disk->info.addr.drive.bus != 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("Only 1 %s bus is supported"), bus);
+            goto error;
+        }
+        unitid = disk->info.addr.drive.unit;
+
+        break;
+
+    case VIR_DOMAIN_DISK_BUS_VIRTIO:
+        /* Each virtio drive is a separate PCI device, no unit/busid or index */
+        idx = -1;
+        break;
+
+    case VIR_DOMAIN_DISK_BUS_XEN:
+        /* Xen has no address type currently, so assign based on index */
+        break;
+    }
+
+    /* disk->src is NULL when we use nbd disks */
+    if (disk->src || (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+                      disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_NBD)) {
+        if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
+            /* QEMU only supports magic FAT format for now */
+            if (disk->driverType &&
+                STRNEQ(disk->driverType, "fat")) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("unsupported disk driver type for '%s'"),
+                                disk->driverType);
+                goto error;
+            }
+            if (!disk->readonly) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                _("cannot create virtual FAT disks in read-write mode"));
+                goto error;
+            }
+            if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
+                virBufferVSprintf(&opt, "file=fat:floppy:%s,", disk->src);
+            else
+                virBufferVSprintf(&opt, "file=fat:%s,", disk->src);
+        } else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
+            switch (disk->protocol) {
+            case VIR_DOMAIN_DISK_PROTOCOL_NBD:
+                if (disk->nhosts != 1) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("NBD accepts only one host"));
+                    goto error;
+                }
+                virBufferVSprintf(&opt, "file=nbd:%s:%s,",
+                                  disk->hosts->name, disk->hosts->port);
+                break;
+            case VIR_DOMAIN_DISK_PROTOCOL_RBD:
+                /* TODO: set monitor hostnames */
+                virBufferVSprintf(&opt, "file=rbd:%s,", disk->src);
+                break;
+            case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
+                if (disk->nhosts == 0)
+                    virBufferVSprintf(&opt, "file=sheepdog:%s,", disk->src);
+                else
+                    /* only one host is supported now */
+                    virBufferVSprintf(&opt, "file=sheepdog:%s:%s:%s,",
+                                      disk->hosts->name, disk->hosts->port,
+                                      disk->src);
+                break;
+            }
+        } else {
+            virBufferVSprintf(&opt, "file=%s,", disk->src);
+        }
+    }
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
+        virBufferAddLit(&opt, "if=none");
+    else
+        virBufferVSprintf(&opt, "if=%s", bus);
+
+    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
+        virBufferAddLit(&opt, ",media=cdrom");
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+        virBufferVSprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
+    } else {
+        if (busid == -1 && unitid == -1) {
+            if (idx != -1)
+                virBufferVSprintf(&opt, ",index=%d", idx);
+        } else {
+            if (busid != -1)
+                virBufferVSprintf(&opt, ",bus=%d", busid);
+            if (unitid != -1)
+                virBufferVSprintf(&opt, ",unit=%d", unitid);
+        }
+    }
+    if (bootable &&
+        disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+        disk->bus != VIR_DOMAIN_DISK_BUS_IDE)
+        virBufferAddLit(&opt, ",boot=on");
+    if (disk->readonly &&
+        qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_READONLY)
+        virBufferAddLit(&opt, ",readonly=on");
+    if (disk->driverType && *disk->driverType != '\0' &&
+        disk->type != VIR_DOMAIN_DISK_TYPE_DIR &&
+        qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_FORMAT)
+        virBufferVSprintf(&opt, ",format=%s", disk->driverType);
+    if (disk->serial &&
+        (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_SERIAL)) {
+        if (qemuSafeSerialParamValue(disk->serial) < 0)
+            goto error;
+        virBufferVSprintf(&opt, ",serial=%s", disk->serial);
+    }
+
+    if (disk->cachemode) {
+        const char *mode =
+            (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_CACHE_V2) ?
+            qemuDiskCacheV2TypeToString(disk->cachemode) :
+            qemuDiskCacheV1TypeToString(disk->cachemode);
+
+        virBufferVSprintf(&opt, ",cache=%s", mode);
+    } else if (disk->shared && !disk->readonly) {
+        virBufferAddLit(&opt, ",cache=off");
+    }
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON) {
+        if (disk->error_policy) {
+            virBufferVSprintf(&opt, ",werror=%s,rerror=%s",
+                              virDomainDiskErrorPolicyTypeToString(disk->error_policy),
+                              virDomainDiskErrorPolicyTypeToString(disk->error_policy));
+        }
+    }
+
+    if (virBufferError(&opt)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&opt);
+
+error:
+    virBufferFreeAndReset(&opt);
+    return NULL;
+}
+
+
+char *
+qemuBuildDriveDevStr(virDomainDiskDefPtr disk)
+{
+    virBuffer opt = VIR_BUFFER_INITIALIZER;
+    const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
+    int idx = virDiskNameToIndex(disk->dst);
+
+    if (idx < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unsupported disk type '%s'"), disk->dst);
+        goto error;
+    }
+
+    switch (disk->bus) {
+    case VIR_DOMAIN_DISK_BUS_IDE:
+        virBufferAddLit(&opt, "ide-drive");
+        virBufferVSprintf(&opt, ",bus=ide.%d,unit=%d",
+                          disk->info.addr.drive.bus,
+                          disk->info.addr.drive.unit);
+        break;
+    case VIR_DOMAIN_DISK_BUS_SCSI:
+        virBufferAddLit(&opt, "scsi-disk");
+        virBufferVSprintf(&opt, ",bus=scsi%d.%d,scsi-id=%d",
+                          disk->info.addr.drive.controller,
+                          disk->info.addr.drive.bus,
+                          disk->info.addr.drive.unit);
+        break;
+    case VIR_DOMAIN_DISK_BUS_VIRTIO:
+        virBufferAddLit(&opt, "virtio-blk-pci");
+        qemuBuildDeviceAddressStr(&opt, &disk->info);
+        break;
+    case VIR_DOMAIN_DISK_BUS_USB:
+        virBufferAddLit(&opt, "usb-storage");
+        break;
+    default:
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unsupported disk bus '%s' with device setup"), bus);
+        goto error;
+    }
+    virBufferVSprintf(&opt, ",drive=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
+    virBufferVSprintf(&opt, ",id=%s", disk->info.alias);
+
+    if (virBufferError(&opt)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&opt);
+
+error:
+    virBufferFreeAndReset(&opt);
+    return NULL;
+}
+
+
+char *qemuBuildFSStr(virDomainFSDefPtr fs,
+                     unsigned long long qemuCmdFlags ATTRIBUTE_UNUSED)
+{
+    virBuffer opt = VIR_BUFFER_INITIALIZER;
+
+    if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                        _("only supports mount filesystem type"));
+        goto error;
+    }
+
+    virBufferAddLit(&opt, "local");
+    if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_MAPPED) {
+        virBufferAddLit(&opt, ",security_model=mapped");
+    } else if(fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
+        virBufferAddLit(&opt, ",security_model=passthrough");
+    } else if(fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_SQUASH) {
+        virBufferAddLit(&opt, ",security_model=none");
+    }
+    virBufferVSprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
+    virBufferVSprintf(&opt, ",path=%s", fs->src);
+
+    if (virBufferError(&opt)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&opt);
+
+error:
+    virBufferFreeAndReset(&opt);
+    return NULL;
+}
+
+
+char *
+qemuBuildFSDevStr(virDomainFSDefPtr fs)
+{
+    virBuffer opt = VIR_BUFFER_INITIALIZER;
+
+    if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                        _("can only passthrough directories"));
+        goto error;
+    }
+
+    virBufferAddLit(&opt, "virtio-9p-pci");
+    virBufferVSprintf(&opt, ",id=%s", fs->info.alias);
+    virBufferVSprintf(&opt, ",fsdev=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
+    virBufferVSprintf(&opt, ",mount_tag=%s", fs->dst);
+    qemuBuildDeviceAddressStr(&opt, &fs->info);
+
+    if (virBufferError(&opt)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&opt);
+
+error:
+    virBufferFreeAndReset(&opt);
+    return NULL;
+}
+
+
+char *
+qemuBuildControllerDevStr(virDomainControllerDefPtr def)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    switch (def->type) {
+    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
+        virBufferAddLit(&buf, "lsi");
+        virBufferVSprintf(&buf, ",id=scsi%d", def->idx);
+        break;
+
+    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
+        if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+            virBufferAddLit(&buf, "virtio-serial-pci");
+        } else {
+            virBufferAddLit(&buf, "virtio-serial");
+        }
+        virBufferVSprintf(&buf, ",id=" QEMU_VIRTIO_SERIAL_PREFIX "%d",
+                          def->idx);
+        if (def->opts.vioserial.ports != -1) {
+            virBufferVSprintf(&buf, ",max_ports=%d",
+                              def->opts.vioserial.ports);
+        }
+        if (def->opts.vioserial.vectors != -1) {
+            virBufferVSprintf(&buf, ",vectors=%d",
+                              def->opts.vioserial.vectors);
+        }
+        break;
+
+    /* We always get an IDE controller, whether we want it or not. */
+    case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
+    default:
+        goto error;
+    }
+
+    if (qemuBuildDeviceAddressStr(&buf, &def->info) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *
+qemuBuildNicStr(virDomainNetDefPtr net,
+                const char *prefix,
+                int vlan)
+{
+    char *str;
+    if (virAsprintf(&str,
+                    "%smacaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s%s%s",
+                    prefix ? prefix : "",
+                    net->mac[0], net->mac[1],
+                    net->mac[2], net->mac[3],
+                    net->mac[4], net->mac[5],
+                    vlan,
+                    (net->model ? ",model=" : ""),
+                    (net->model ? net->model : ""),
+                    (net->info.alias ? ",name=" : ""),
+                    (net->info.alias ? net->info.alias : "")) < 0) {
+        virReportOOMError();
+        return NULL;
+    }
+
+    return str;
+}
+
+
+char *
+qemuBuildNicDevStr(virDomainNetDefPtr net, int vlan)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    const char *nic;
+
+    if (!net->model) {
+        nic = "rtl8139";
+    } else if (STREQ(net->model, "virtio")) {
+        nic = "virtio-net-pci";
+    } else {
+        nic = net->model;
+    }
+
+    virBufferAdd(&buf, nic, strlen(nic));
+    if (vlan == -1)
+        virBufferVSprintf(&buf, ",netdev=host%s", net->info.alias);
+    else
+        virBufferVSprintf(&buf, ",vlan=%d", vlan);
+    virBufferVSprintf(&buf, ",id=%s", net->info.alias);
+    virBufferVSprintf(&buf, ",mac=%02x:%02x:%02x:%02x:%02x:%02x",
+                      net->mac[0], net->mac[1],
+                      net->mac[2], net->mac[3],
+                      net->mac[4], net->mac[5]);
+    if (qemuBuildDeviceAddressStr(&buf, &net->info) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *
+qemuBuildHostNetStr(virDomainNetDefPtr net,
+                    char type_sep,
+                    int vlan,
+                    const char *tapfd,
+                    const char *vhostfd)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    switch (net->type) {
+    case VIR_DOMAIN_NET_TYPE_NETWORK:
+    case VIR_DOMAIN_NET_TYPE_BRIDGE:
+    case VIR_DOMAIN_NET_TYPE_DIRECT:
+        virBufferAddLit(&buf, "tap");
+        virBufferVSprintf(&buf, "%cfd=%s", type_sep, tapfd);
+        type_sep = ',';
+        break;
+
+    case VIR_DOMAIN_NET_TYPE_ETHERNET:
+        virBufferAddLit(&buf, "tap");
+        if (net->ifname) {
+            virBufferVSprintf(&buf, "%cifname=%s", type_sep, net->ifname);
+            type_sep = ',';
+        }
+        if (net->data.ethernet.script) {
+            virBufferVSprintf(&buf, "%cscript=%s", type_sep,
+                              net->data.ethernet.script);
+            type_sep = ',';
+        }
+        break;
+
+    case VIR_DOMAIN_NET_TYPE_CLIENT:
+    case VIR_DOMAIN_NET_TYPE_SERVER:
+    case VIR_DOMAIN_NET_TYPE_MCAST:
+        virBufferAddLit(&buf, "socket");
+        switch (net->type) {
+        case VIR_DOMAIN_NET_TYPE_CLIENT:
+            virBufferVSprintf(&buf, "%cconnect=%s:%d",
+                              type_sep,
+                              net->data.socket.address,
+                              net->data.socket.port);
+            break;
+        case VIR_DOMAIN_NET_TYPE_SERVER:
+            virBufferVSprintf(&buf, "%clisten=%s:%d",
+                              type_sep,
+                              net->data.socket.address,
+                              net->data.socket.port);
+            break;
+        case VIR_DOMAIN_NET_TYPE_MCAST:
+            virBufferVSprintf(&buf, "%cmcast=%s:%d",
+                              type_sep,
+                              net->data.socket.address,
+                              net->data.socket.port);
+            break;
+        case VIR_DOMAIN_NET_TYPE_USER:
+        case VIR_DOMAIN_NET_TYPE_ETHERNET:
+        case VIR_DOMAIN_NET_TYPE_NETWORK:
+        case VIR_DOMAIN_NET_TYPE_BRIDGE:
+        case VIR_DOMAIN_NET_TYPE_INTERNAL:
+        case VIR_DOMAIN_NET_TYPE_DIRECT:
+        case VIR_DOMAIN_NET_TYPE_LAST:
+            break;
+        }
+        type_sep = ',';
+        break;
+
+    case VIR_DOMAIN_NET_TYPE_USER:
+    default:
+        virBufferAddLit(&buf, "user");
+        break;
+    }
+
+    if (vlan >= 0) {
+        virBufferVSprintf(&buf, "%cvlan=%d", type_sep, vlan);
+        if (net->info.alias)
+            virBufferVSprintf(&buf, ",name=host%s",
+                              net->info.alias);
+    } else {
+        virBufferVSprintf(&buf, "%cid=host%s",
+                          type_sep, net->info.alias);
+    }
+
+    if (vhostfd && *vhostfd) {
+        virBufferVSprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd);
+    }
+
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+
+char *
+qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    const char *model = virDomainWatchdogModelTypeToString(dev->model);
+    if (!model) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("missing watchdog model"));
+        goto error;
+    }
+
+    virBufferVSprintf(&buf, "%s", model);
+    virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
+    if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *
+qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAddLit(&buf, "virtio-balloon-pci");
+    virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
+    if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *
+qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferVSprintf(&buf, "%s",
+                      dev->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
+                      "usb-mouse" : "usb-tablet");
+    virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *
+qemuBuildSoundDevStr(virDomainSoundDefPtr sound)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    const char *model = virDomainSoundModelTypeToString(sound->model);
+
+    if (!model) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("invalid sound model"));
+        goto error;
+    }
+
+    /* Hack for 2 wierdly unusal devices name in QEMU */
+    if (STREQ(model, "es1370"))
+        model = "ES1370";
+    else if (STREQ(model, "ac97"))
+        model = "AC97";
+
+    virBufferVSprintf(&buf, "%s", model);
+    virBufferVSprintf(&buf, ",id=%s", sound->info.alias);
+    if (qemuBuildDeviceAddressStr(&buf, &sound->info) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+static char *
+qemuBuildVideoDevStr(virDomainVideoDefPtr video)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    const char *model = qemuVideoTypeToString(video->type);
+
+    if (!model) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("invalid video model"));
+        goto error;
+    }
+
+    virBufferVSprintf(&buf, "%s", model);
+    virBufferVSprintf(&buf, ",id=%s", video->info.alias);
+    if (qemuBuildDeviceAddressStr(&buf, &video->info) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+int
+qemuOpenPCIConfig(virDomainHostdevDefPtr dev)
+{
+    char *path = NULL;
+    int configfd = -1;
+
+    if (virAsprintf(&path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config",
+                    dev->source.subsys.u.pci.domain,
+                    dev->source.subsys.u.pci.bus,
+                    dev->source.subsys.u.pci.slot,
+                    dev->source.subsys.u.pci.function) < 0) {
+        virReportOOMError();
+        return -1;
+    }
+
+    configfd = open(path, O_RDWR, 0);
+
+    if (configfd < 0)
+        virReportSystemError(errno, _("Failed opening %s"), path);
+
+    VIR_FREE(path);
+
+    return configfd;
+}
+
+char *
+qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev, const char *configfd)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferAddLit(&buf, "pci-assign");
+    virBufferVSprintf(&buf, ",host=%.2x:%.2x.%.1x",
+                      dev->source.subsys.u.pci.bus,
+                      dev->source.subsys.u.pci.slot,
+                      dev->source.subsys.u.pci.function);
+    virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
+    if (configfd && *configfd)
+        virBufferVSprintf(&buf, ",configfd=%s", configfd);
+    if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
+        goto error;
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *
+qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev)
+{
+    char *ret = NULL;
+
+    if (virAsprintf(&ret, "host=%.2x:%.2x.%.1x",
+                    dev->source.subsys.u.pci.bus,
+                    dev->source.subsys.u.pci.slot,
+                    dev->source.subsys.u.pci.function) < 0)
+        virReportOOMError();
+
+    return ret;
+}
+
+
+char *
+qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev)
+{
+    char *ret = NULL;
+
+    if (!dev->source.subsys.u.usb.bus &&
+        !dev->source.subsys.u.usb.device) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("USB host device is missing bus/device information"));
+        return NULL;
+    }
+
+    if (virAsprintf(&ret, "usb-host,hostbus=%d,hostaddr=%d,id=%s",
+                    dev->source.subsys.u.usb.bus,
+                    dev->source.subsys.u.usb.device,
+                    dev->info.alias) < 0)
+        virReportOOMError();
+
+    return ret;
+}
+
+
+char *
+qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev)
+{
+    char *ret = NULL;
+
+    if (!dev->source.subsys.u.usb.bus &&
+        !dev->source.subsys.u.usb.device) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("USB host device is missing bus/device information"));
+        return NULL;
+    }
+
+    if (virAsprintf(&ret, "host:%d.%d",
+                    dev->source.subsys.u.usb.bus,
+                    dev->source.subsys.u.usb.device) < 0)
+        virReportOOMError();
+
+    return ret;
+}
+
+
+
+/* This function outputs a -chardev command line option which describes only the
+ * host side of the character device */
+char *
+qemuBuildChrChardevStr(virDomainChrDefPtr dev)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    bool telnet;
+
+    switch(dev->type) {
+    case VIR_DOMAIN_CHR_TYPE_NULL:
+        virBufferVSprintf(&buf, "null,id=%s", dev->info.alias);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_VC:
+        virBufferVSprintf(&buf, "vc,id=%s", dev->info.alias);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_PTY:
+        virBufferVSprintf(&buf, "pty,id=%s", dev->info.alias);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+        virBufferVSprintf(&buf, "tty,id=%s,path=%s", dev->info.alias, dev->data.file.path);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+        virBufferVSprintf(&buf, "file,id=%s,path=%s", dev->info.alias, dev->data.file.path);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+        virBufferVSprintf(&buf, "pipe,id=%s,path=%s", dev->info.alias, dev->data.file.path);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_STDIO:
+        virBufferVSprintf(&buf, "stdio,id=%s", dev->info.alias);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_UDP:
+        virBufferVSprintf(&buf,
+                          "udp,id=%s,host=%s,port=%s,localaddr=%s,localport=%s",
+                          dev->info.alias,
+                          dev->data.udp.connectHost,
+                          dev->data.udp.connectService,
+                          dev->data.udp.bindHost,
+                          dev->data.udp.bindService);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_TCP:
+        telnet = dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
+        virBufferVSprintf(&buf,
+                          "socket,id=%s,host=%s,port=%s%s%s",
+                          dev->info.alias,
+                          dev->data.tcp.host,
+                          dev->data.tcp.service,
+                          telnet ? ",telnet" : "",
+                          dev->data.tcp.listen ? ",server,nowait" : "");
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_UNIX:
+        virBufferVSprintf(&buf,
+                          "socket,id=%s,path=%s%s",
+                          dev->info.alias,
+                          dev->data.nix.path,
+                          dev->data.nix.listen ? ",server,nowait" : "");
+        break;
+    }
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *
+qemuBuildChrArgStr(virDomainChrDefPtr dev, const char *prefix)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if (prefix)
+        virBufferAdd(&buf, prefix, strlen(prefix));
+
+    switch (dev->type) {
+    case VIR_DOMAIN_CHR_TYPE_NULL:
+        virBufferAddLit(&buf, "null");
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_VC:
+        virBufferAddLit(&buf, "vc");
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_PTY:
+        virBufferAddLit(&buf, "pty");
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_DEV:
+        virBufferStrcat(&buf, dev->data.file.path, NULL);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_FILE:
+        virBufferVSprintf(&buf, "file:%s", dev->data.file.path);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_PIPE:
+        virBufferVSprintf(&buf, "pipe:%s", dev->data.file.path);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_STDIO:
+        virBufferAddLit(&buf, "stdio");
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_UDP:
+        virBufferVSprintf(&buf, "udp:%s:%s %s:%s",
+                          dev->data.udp.connectHost,
+                          dev->data.udp.connectService,
+                          dev->data.udp.bindHost,
+                          dev->data.udp.bindService);
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_TCP:
+        if (dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) {
+            virBufferVSprintf(&buf, "telnet:%s:%s%s",
+                              dev->data.tcp.host,
+                              dev->data.tcp.service,
+                              dev->data.tcp.listen ? ",server,nowait" : "");
+        } else {
+            virBufferVSprintf(&buf, "tcp:%s:%s%s",
+                              dev->data.tcp.host,
+                              dev->data.tcp.service,
+                              dev->data.tcp.listen ? ",server,nowait" : "");
+        }
+        break;
+
+    case VIR_DOMAIN_CHR_TYPE_UNIX:
+        virBufferVSprintf(&buf, "unix:%s%s",
+                          dev->data.nix.path,
+                          dev->data.nix.listen ? ",server,nowait" : "");
+        break;
+    }
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+char *
+qemuBuildVirtioSerialPortDevStr(virDomainChrDefPtr dev)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)
+        virBufferAddLit(&buf, "virtconsole");
+    else
+        virBufferAddLit(&buf, "virtserialport");
+
+    if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
+        /* Check it's a virtio-serial address */
+        if (dev->info.type !=
+            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
+        {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("virtio serial device has invalid address type"));
+            goto error;
+        }
+
+        virBufferVSprintf(&buf,
+                          ",bus=" QEMU_VIRTIO_SERIAL_PREFIX "%d.%d",
+                          dev->info.addr.vioserial.controller,
+                          dev->info.addr.vioserial.bus);
+        virBufferVSprintf(&buf,
+                          ",nr=%d",
+                          dev->info.addr.vioserial.port);
+    }
+
+    virBufferVSprintf(&buf, ",chardev=%s", dev->info.alias);
+    if (dev->target.name) {
+        virBufferVSprintf(&buf, ",name=%s", dev->target.name);
+    }
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+static char *qemuBuildSmbiosBiosStr(virSysinfoDefPtr def)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if ((def->bios_vendor == NULL) && (def->bios_version == NULL) &&
+        (def->bios_date == NULL) && (def->bios_release == NULL))
+        return(NULL);
+
+    virBufferAddLit(&buf, "type=0");
+
+    /* 0:Vendor */
+    if (def->bios_vendor)
+        virBufferVSprintf(&buf, ",vendor=%s", def->bios_vendor);
+    /* 0:BIOS Version */
+    if (def->bios_version)
+        virBufferVSprintf(&buf, ",version=%s", def->bios_version);
+    /* 0:BIOS Release Date */
+    if (def->bios_date)
+        virBufferVSprintf(&buf, ",date=%s", def->bios_date);
+    /* 0:System BIOS Major Release and 0:System BIOS Minor Release */
+    if (def->bios_release)
+        virBufferVSprintf(&buf, ",release=%s", def->bios_release);
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return(NULL);
+}
+
+static char *qemuBuildSmbiosSystemStr(virSysinfoDefPtr def, bool skip_uuid)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    if ((def->system_manufacturer == NULL) && (def->system_sku == NULL) &&
+        (def->system_product == NULL) && (def->system_version == NULL) &&
+        (def->system_serial == NULL) && (def->system_family == NULL) &&
+        (def->system_uuid == NULL || skip_uuid))
+        return NULL;
+
+    virBufferAddLit(&buf, "type=1");
+
+    /* 1:Manufacturer */
+    if (def->system_manufacturer)
+        virBufferVSprintf(&buf, ",manufacturer=%s",
+                          def->system_manufacturer);
+     /* 1:Product Name */
+    if (def->system_product)
+        virBufferVSprintf(&buf, ",product=%s", def->system_product);
+    /* 1:Version */
+    if (def->system_version)
+        virBufferVSprintf(&buf, ",version=%s", def->system_version);
+    /* 1:Serial Number */
+    if (def->system_serial)
+        virBufferVSprintf(&buf, ",serial=%s", def->system_serial);
+    /* 1:UUID */
+    if (def->system_uuid && !skip_uuid)
+        virBufferVSprintf(&buf, ",uuid=%s", def->system_uuid);
+    /* 1:SKU Number */
+    if (def->system_sku)
+        virBufferVSprintf(&buf, ",sku=%s", def->system_sku);
+    /* 1:Family */
+    if (def->system_family)
+        virBufferVSprintf(&buf, ",family=%s", def->system_family);
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return(NULL);
+}
+
+static char *
+qemuBuildClockArgStr(virDomainClockDefPtr def)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    switch (def->offset) {
+    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+        virBufferAddLit(&buf, "base=utc");
+        break;
+
+    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
+        virBufferAddLit(&buf, "base=localtime");
+        break;
+
+    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: {
+        time_t now = time(NULL);
+        struct tm nowbits;
+
+        now += def->data.adjustment;
+        gmtime_r(&now, &nowbits);
+
+        virBufferVSprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d",
+                          nowbits.tm_year + 1900,
+                          nowbits.tm_mon + 1,
+                          nowbits.tm_mday,
+                          nowbits.tm_hour,
+                          nowbits.tm_min,
+                          nowbits.tm_sec);
+    }   break;
+
+    default:
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                        _("unsupported clock offset '%s'"),
+                        virDomainClockOffsetTypeToString(def->offset));
+        goto error;
+    }
+
+    /* Look for an 'rtc' timer element, and add in appropriate clock= and driftfix= */
+    int i;
+    for (i = 0; i < def->ntimers; i++) {
+        if (def->timers[i]->name == VIR_DOMAIN_TIMER_NAME_RTC) {
+            switch (def->timers[i]->track) {
+            case -1: /* unspecified - use hypervisor default */
+                break;
+            case VIR_DOMAIN_TIMER_TRACK_BOOT:
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                _("unsupported rtc timer track '%s'"),
+                                virDomainTimerTrackTypeToString(def->timers[i]->track));
+                goto error;
+            case VIR_DOMAIN_TIMER_TRACK_GUEST:
+                virBufferAddLit(&buf, ",clock=vm");
+                break;
+            case VIR_DOMAIN_TIMER_TRACK_WALL:
+                virBufferAddLit(&buf, ",clock=host");
+                break;
+            }
+
+            switch (def->timers[i]->tickpolicy) {
+            case -1:
+            case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
+                /* This is the default - missed ticks delivered when
+                   next scheduled, at normal rate */
+                break;
+            case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
+                /* deliver ticks at a faster rate until caught up */
+                virBufferAddLit(&buf, ",driftfix=slew");
+                break;
+            case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
+            case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                _("unsupported rtc timer tickpolicy '%s'"),
+                                virDomainTimerTickpolicyTypeToString(def->timers[i]->tickpolicy));
+                goto error;
+            }
+            break; /* no need to check other timers - there is only one rtc */
+        }
+    }
+
+    if (virBufferError(&buf)) {
+        virReportOOMError();
+        goto error;
+    }
+
+    return virBufferContentAndReset(&buf);
+
+error:
+    virBufferFreeAndReset(&buf);
+    return NULL;
+}
+
+
+static int
+qemuBuildCpuArgStr(const struct qemud_driver *driver,
+                   const virDomainDefPtr def,
+                   const char *emulator,
+                   unsigned long long qemuCmdFlags,
+                   const struct utsname *ut,
+                   char **opt,
+                   bool *hasHwVirt)
+{
+    const virCPUDefPtr host = driver->caps->host.cpu;
+    virCPUDefPtr guest = NULL;
+    unsigned int ncpus = 0;
+    const char **cpus = NULL;
+    union cpuData *data = NULL;
+    int ret = -1;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    int i;
+
+    *hasHwVirt = false;
+
+    if (def->cpu && def->cpu->model) {
+        if (qemuCapsProbeCPUModels(emulator, qemuCmdFlags, ut->machine,
+                                   &ncpus, &cpus) < 0)
+            goto cleanup;
+
+        if (!ncpus || !host) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                            _("CPU specification not supported by hypervisor"));
+            goto cleanup;
+        }
+    }
+
+    if (ncpus > 0 && host) {
+        virCPUCompareResult cmp;
+        const char *preferred;
+        int hasSVM;
+
+        cmp = cpuGuestData(host, def->cpu, &data);
+        switch (cmp) {
+        case VIR_CPU_COMPARE_INCOMPATIBLE:
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("guest CPU is not compatible with host CPU"));
+            /* fall through */
+        case VIR_CPU_COMPARE_ERROR:
+            goto cleanup;
+
+        default:
+            break;
+        }
+
+        if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(ut->machine)))
+            goto no_memory;
+
+        if (def->cpu->match == VIR_CPU_MATCH_MINIMUM)
+            preferred = host->model;
+        else
+            preferred = def->cpu->model;
+
+        guest->type = VIR_CPU_TYPE_GUEST;
+        if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
+            goto cleanup;
+
+        /* Only 'svm' requires --enable-nesting. The nested
+         * 'vmx' patches now simply hook off the CPU features
+         */
+        hasSVM = cpuHasFeature(guest->arch, data, "svm");
+        if (hasSVM < 0)
+            goto cleanup;
+        *hasHwVirt = hasSVM > 0 ? true : false;
+
+        virBufferVSprintf(&buf, "%s", guest->model);
+        for (i = 0; i < guest->nfeatures; i++) {
+            char sign;
+            if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE)
+                sign = '-';
+            else
+                sign = '+';
+
+            virBufferVSprintf(&buf, ",%c%s", sign, guest->features[i].name);
+        }
+    }
+    else {
+        /*
+         * Need to force a 32-bit guest CPU type if
+         *
+         *  1. guest OS is i686
+         *  2. host OS is x86_64
+         *  3. emulator is qemu-kvm or kvm
+         *
+         * Or
+         *
+         *  1. guest OS is i686
+         *  2. emulator is qemu-system-x86_64
+         */
+        if (STREQ(def->os.arch, "i686") &&
+            ((STREQ(ut->machine, "x86_64") &&
+              strstr(emulator, "kvm")) ||
+             strstr(emulator, "x86_64")))
+            virBufferAddLit(&buf, "qemu32");
+    }
+
+    if (virBufferError(&buf))
+        goto no_memory;
+
+    *opt = virBufferContentAndReset(&buf);
+
+    ret = 0;
+
+cleanup:
+    virCPUDefFree(guest);
+    cpuDataFree(ut->machine, data);
+
+    if (cpus) {
+        for (i = 0; i < ncpus; i++)
+            VIR_FREE(cpus[i]);
+        VIR_FREE(cpus);
+    }
+
+    return ret;
+
+no_memory:
+    virReportOOMError();
+    goto cleanup;
+}
+
+static char *
+qemuBuildSmpArgStr(const virDomainDefPtr def,
+                   unsigned long long qemuCmdFlags)
+{
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+    virBufferVSprintf(&buf, "%u", def->vcpus);
+
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) {
+        if (def->vcpus != def->maxvcpus)
+            virBufferVSprintf(&buf, ",maxcpus=%u", def->maxvcpus);
+        /* sockets, cores, and threads are either all zero
+         * or all non-zero, thus checking one of them is enough */
+        if (def->cpu && def->cpu->sockets) {
+            virBufferVSprintf(&buf, ",sockets=%u", def->cpu->sockets);
+            virBufferVSprintf(&buf, ",cores=%u", def->cpu->cores);
+            virBufferVSprintf(&buf, ",threads=%u", def->cpu->threads);
+        }
+        else {
+            virBufferVSprintf(&buf, ",sockets=%u", def->maxvcpus);
+            virBufferVSprintf(&buf, ",cores=%u", 1);
+            virBufferVSprintf(&buf, ",threads=%u", 1);
+        }
+    } else if (def->vcpus != def->maxvcpus) {
+        virBufferFreeAndReset(&buf);
+        /* FIXME - consider hot-unplugging cpus after boot for older qemu */
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                        _("setting current vcpu count less than maximum is "
+                          "not supported with this QEMU binary"));
+        return NULL;
+    }
+
+    if (virBufferError(&buf)) {
+        virBufferFreeAndReset(&buf);
+        virReportOOMError();
+        return NULL;
+    }
+
+    return virBufferContentAndReset(&buf);
+}
+
+
+/*
+ * Constructs a argv suitable for launching qemu with config defined
+ * for a given virtual machine.
+ *
+ * XXX 'conn' is only required to resolve network -> bridge name
+ * figure out how to remove this requirement some day
+ */
+virCommandPtr
+qemuBuildCommandLine(virConnectPtr conn,
+                     struct qemud_driver *driver,
+                     virDomainDefPtr def,
+                     virDomainChrDefPtr monitor_chr,
+                     bool monitor_json,
+                     unsigned long long qemuCmdFlags,
+                     const char *migrateFrom,
+                     virDomainSnapshotObjPtr current_snapshot,
+                     enum virVMOperationType vmop)
+{
+    int i;
+    char boot[VIR_DOMAIN_BOOT_LAST+1];
+    struct utsname ut;
+    int disableKQEMU = 0;
+    int enableKQEMU = 0;
+    int disableKVM = 0;
+    int enableKVM = 0;
+    const char *emulator;
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    char *cpu;
+    char *smp;
+    int last_good_net = -1;
+    bool hasHwVirt = false;
+    virCommandPtr cmd;
+    bool has_rbd_hosts = false;
+    virBuffer rbd_hosts = VIR_BUFFER_INITIALIZER;
+
+    uname_normalize(&ut);
+
+    if (qemuAssignDeviceAliases(def, qemuCmdFlags) < 0)
+        return NULL;
+
+    virUUIDFormat(def->uuid, uuid);
+
+    /* Migration is very annoying due to wildly varying syntax & capabilities
+     * over time of KVM / QEMU codebases
+     */
+    if (migrateFrom) {
+        if (STRPREFIX(migrateFrom, "tcp")) {
+            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP)) {
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                "%s", _("TCP migration is not supported with this QEMU binary"));
+                return NULL;
+            }
+        } else if (STREQ(migrateFrom, "stdio")) {
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
+                migrateFrom = "exec:cat";
+            } 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 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 NULL;
+            }
+        }
+    }
+
+    emulator = def->emulator;
+
+    /*
+     * do not use boot=on for drives when not using KVM since this
+     * is not supported at all in upstream QEmu.
+     */
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_KVM) &&
+        (def->virtType == VIR_DOMAIN_VIRT_QEMU) &&
+        (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT))
+        qemuCmdFlags -= QEMUD_CMD_FLAG_DRIVE_BOOT;
+
+    switch (def->virtType) {
+    case VIR_DOMAIN_VIRT_QEMU:
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU)
+            disableKQEMU = 1;
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_KVM)
+            disableKVM = 1;
+        break;
+
+    case VIR_DOMAIN_VIRT_KQEMU:
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_KVM)
+            disableKVM = 1;
+
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_ENABLE_KQEMU) {
+            enableKQEMU = 1;
+        } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU)) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("the QEMU binary %s does not support kqemu"),
+                            emulator);
+        }
+        break;
+
+    case VIR_DOMAIN_VIRT_KVM:
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU)
+            disableKQEMU = 1;
+
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_ENABLE_KVM) {
+            enableKVM = 1;
+        } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_KVM)) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("the QEMU binary %s does not support kvm"),
+                            emulator);
+        }
+        break;
+
+    case VIR_DOMAIN_VIRT_XEN:
+        /* XXX better check for xenner */
+        break;
+
+    default:
+        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                        _("the QEMU binary %s does not support %s"),
+                        emulator, virDomainVirtTypeToString(def->virtType));
+        break;
+    }
+
+    cmd = virCommandNewArgList(emulator, "-S", NULL);
+
+    virCommandAddEnvPassCommon(cmd);
+
+    /* 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)
+        virCommandAddArgList(cmd, "-M", def->os.machine, NULL);
+
+    if (qemuBuildCpuArgStr(driver, def, emulator, qemuCmdFlags,
+                           &ut, &cpu, &hasHwVirt) < 0)
+        goto error;
+
+    if (cpu) {
+        virCommandAddArgList(cmd, "-cpu", cpu, NULL);
+        VIR_FREE(cpu);
+
+        if ((qemuCmdFlags & QEMUD_CMD_FLAG_NESTING) &&
+            hasHwVirt)
+            virCommandAddArg(cmd, "-enable-nesting");
+    }
+
+    if (disableKQEMU)
+        virCommandAddArg(cmd, "-no-kqemu");
+    else if (enableKQEMU)
+        virCommandAddArgList(cmd, "-enable-kqemu", "-kernel-kqemu", NULL);
+    if (disableKVM)
+        virCommandAddArg(cmd, "-no-kvm");
+    if (enableKVM)
+        virCommandAddArg(cmd, "-enable-kvm");
+
+    /* Set '-m MB' based on maxmem, because the lower 'memory' limit
+     * is set post-startup using the balloon driver. If balloon driver
+     * is not supported, then they're out of luck anyway
+     */
+    virCommandAddArg(cmd, "-m");
+    virCommandAddArgFormat(cmd, "%lu", def->mem.max_balloon / 1024);
+    if (def->mem.hugepage_backed) {
+        if (!driver->hugetlbfs_mount) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("hugetlbfs filesystem is not mounted"));
+            goto error;
+        }
+        if (!driver->hugepage_path) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("hugepages are disabled by administrator config"));
+            goto error;
+        }
+        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MEM_PATH)) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("hugepage backing not supported by '%s'"),
+                            def->emulator);
+            goto error;
+        }
+        virCommandAddArgList(cmd, "-mem-prealloc", "-mem-path",
+                             driver->hugepage_path, NULL);
+    }
+
+    virCommandAddArg(cmd, "-smp");
+    if (!(smp = qemuBuildSmpArgStr(def, qemuCmdFlags)))
+        goto error;
+    virCommandAddArg(cmd, smp);
+    VIR_FREE(smp);
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
+        virCommandAddArg(cmd, "-name");
+        if (driver->setProcessName &&
+            (qemuCmdFlags & QEMUD_CMD_FLAG_NAME_PROCESS)) {
+            virCommandAddArgFormat(cmd, "%s,process=qemu:%s",
+                                   def->name, def->name);
+        } else {
+            virCommandAddArg(cmd, def->name);
+        }
+    }
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_UUID)
+        virCommandAddArgList(cmd, "-uuid", uuid, NULL);
+    if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
+        STREQ(def->os.type, "xen") ||
+        STREQ(def->os.type, "linux")) {
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_DOMID) {
+            virCommandAddArg(cmd, "-domid");
+            virCommandAddArgFormat(cmd, "%d", def->id);
+        } else if (qemuCmdFlags & QEMUD_CMD_FLAG_XEN_DOMID) {
+            virCommandAddArg(cmd, "-xen-attach");
+            virCommandAddArg(cmd, "-xen-domid");
+            virCommandAddArgFormat(cmd, "%d", def->id);
+        } else {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("qemu emulator '%s' does not support xen"),
+                            def->emulator);
+            goto error;
+        }
+    }
+
+    if ((def->os.smbios_mode != VIR_DOMAIN_SMBIOS_NONE) &&
+        (def->os.smbios_mode != VIR_DOMAIN_SMBIOS_EMULATE)) {
+        virSysinfoDefPtr source = NULL;
+        bool skip_uuid = false;
+
+        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_SMBIOS_TYPE)) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                    _("the QEMU binary %s does not support smbios settings"),
+                            emulator);
+            goto error;
+        }
+
+        /* should we really error out or just warn in those cases ? */
+        if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) {
+            if (driver->hostsysinfo == NULL) {
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                            _("Host SMBIOS information is not available"));
+                goto error;
+            }
+            source = driver->hostsysinfo;
+            /* Host and guest uuid must differ, by definition of UUID. */
+            skip_uuid = true;
+        } else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_SYSINFO) {
+            if (def->sysinfo == NULL) {
+                qemuReportError(VIR_ERR_XML_ERROR,
+                            _("Domain '%s' sysinfo are not available"),
+                               def->name);
+                goto error;
+            }
+            source = def->sysinfo;
+            /* domain_conf guaranteed that system_uuid matches guest uuid. */
+        }
+        if (source != NULL) {
+            char *smbioscmd;
+
+            smbioscmd = qemuBuildSmbiosBiosStr(source);
+            if (smbioscmd != NULL) {
+                virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
+                VIR_FREE(smbioscmd);
+            }
+            smbioscmd = qemuBuildSmbiosSystemStr(source, skip_uuid);
+            if (smbioscmd != NULL) {
+                virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
+                VIR_FREE(smbioscmd);
+            }
+        }
+    }
+
+    /*
+     * NB, -nographic *MUST* come before any serial, or monitor
+     * or parallel port flags due to QEMU craziness, where it
+     * decides to change the serial port & monitor to be on stdout
+     * if you ask for nographic. So we have to make sure we override
+     * these defaults ourselves...
+     */
+    if (!def->graphics)
+        virCommandAddArg(cmd, "-nographic");
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_NODEFCONFIG)
+            virCommandAddArg(cmd,
+                             "-nodefconfig"); /* Disable global config files */
+        virCommandAddArg(cmd,
+                         "-nodefaults");  /* Disable default guest devices */
+    }
+
+    if (monitor_chr) {
+        char *chrdev;
+        /* Use -chardev if it's available */
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) {
+
+            virCommandAddArg(cmd, "-chardev");
+            if (!(chrdev = qemuBuildChrChardevStr(monitor_chr)))
+                goto error;
+            virCommandAddArg(cmd, chrdev);
+            VIR_FREE(chrdev);
+
+            virCommandAddArg(cmd, "-mon");
+            virCommandAddArgFormat(cmd, "chardev=monitor,mode=%s",
+                                   monitor_json ? "control" : "readline");
+        } else {
+            const char *prefix = NULL;
+            if (monitor_json)
+                prefix = "control,";
+
+            virCommandAddArg(cmd, "-monitor");
+            if (!(chrdev = qemuBuildChrArgStr(monitor_chr, prefix)))
+                goto error;
+            virCommandAddArg(cmd, chrdev);
+            VIR_FREE(chrdev);
+        }
+    }
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_RTC) {
+        const char *rtcopt;
+        virCommandAddArg(cmd, "-rtc");
+        if (!(rtcopt = qemuBuildClockArgStr(&def->clock)))
+            goto error;
+        virCommandAddArg(cmd, rtcopt);
+        VIR_FREE(rtcopt);
+    } else {
+        switch (def->clock.offset) {
+        case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
+        case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
+            virCommandAddArg(cmd, "-localtime");
+            break;
+
+        case VIR_DOMAIN_CLOCK_OFFSET_UTC:
+            /* Nothing, its the default */
+            break;
+
+        default:
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("unsupported clock offset '%s'"),
+                            virDomainClockOffsetTypeToString(def->clock.offset));
+            goto error;
+        }
+    }
+    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_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) {
+        default:
+        case VIR_DOMAIN_TIMER_NAME_PLATFORM:
+        case VIR_DOMAIN_TIMER_NAME_TSC:
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("unsupported timer type (name) '%s'"),
+                            virDomainTimerNameTypeToString(def->clock.timers[i]->name));
+            goto error;
+
+        case VIR_DOMAIN_TIMER_NAME_RTC:
+            /* This has already been taken care of (in qemuBuildClockArgStr)
+               if QEMUD_CMD_FLAG_RTC is set (mutually exclusive with
+               QEMUD_FLAG_RTC_TD_HACK) */
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_RTC_TD_HACK) {
+                switch (def->clock.timers[i]->tickpolicy) {
+                case -1:
+                case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
+                    /* the default - do nothing */
+                    break;
+                case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
+                    virCommandAddArg(cmd, "-rtc-td-hack");
+                    break;
+                case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
+                case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
+                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                    _("unsupported rtc tickpolicy '%s'"),
+                                    virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
+                goto error;
+                }
+            } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_RTC)
+                       && (def->clock.timers[i]->tickpolicy
+                           != VIR_DOMAIN_TIMER_TICKPOLICY_DELAY)
+                       && (def->clock.timers[i]->tickpolicy != -1)) {
+                /* a non-default rtc policy was given, but there is no
+                   way to implement it in this version of qemu */
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                _("unsupported rtc tickpolicy '%s'"),
+                                virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
+                goto error;
+            }
+            break;
+
+        case VIR_DOMAIN_TIMER_NAME_PIT:
+            switch (def->clock.timers[i]->tickpolicy) {
+            case -1:
+            case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
+                /* 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)
+                    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. */
+                    virCommandAddArg(cmd, "-tdf");
+                } else {
+                    /* can't catchup if we have neither pit mode */
+                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                    _("unsupported pit tickpolicy '%s'"),
+                                    virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
+                    goto error;
+                }
+                break;
+            case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
+            case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
+                /* no way to support these modes for pit in qemu */
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                _("unsupported pit tickpolicy '%s'"),
+                                virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
+                goto error;
+            }
+            break;
+
+        case VIR_DOMAIN_TIMER_NAME_HPET:
+            /* the only meaningful attribute for hpet is "present". If
+             * present is -1, that means it wasn't specified, and
+             * should be left at the default for the
+             * hypervisor. "default" when -no-hpet exists is "yes",
+             * and when -no-hpet doesn't exist is "no". "confusing"?
+             * "yes"! */
+
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_NO_HPET) {
+                if (def->clock.timers[i]->present == 0)
+                    virCommandAddArg(cmd, "-no-hpet");
+            } else {
+                /* no hpet timer available. The only possible action
+                   is to raise an error if present="yes" */
+                if (def->clock.timers[i]->present == 1) {
+                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                    "%s", _("pit timer is not supported"));
+                }
+            }
+            break;
+        }
+    }
+
+    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
+        def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
+        virCommandAddArg(cmd, "-no-reboot");
+
+    if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
+        virCommandAddArg(cmd, "-no-acpi");
+
+    if (!def->os.bootloader) {
+        for (i = 0 ; i < def->os.nBootDevs ; i++) {
+            switch (def->os.bootDevs[i]) {
+            case VIR_DOMAIN_BOOT_CDROM:
+                boot[i] = 'd';
+                break;
+            case VIR_DOMAIN_BOOT_FLOPPY:
+                boot[i] = 'a';
+                break;
+            case VIR_DOMAIN_BOOT_DISK:
+                boot[i] = 'c';
+                break;
+            case VIR_DOMAIN_BOOT_NET:
+                boot[i] = 'n';
+                break;
+            default:
+                boot[i] = 'c';
+                break;
+            }
+        }
+        if (def->os.nBootDevs) {
+            virBuffer boot_buf = VIR_BUFFER_INITIALIZER;
+            virCommandAddArg(cmd, "-boot");
+
+            boot[def->os.nBootDevs] = '\0';
+
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_BOOT_MENU &&
+                def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_DEFAULT) {
+                if (def->os.bootmenu == VIR_DOMAIN_BOOT_MENU_ENABLED)
+                    virBufferVSprintf(&boot_buf, "order=%s,menu=on", boot);
+                else if (def->os.bootmenu == VIR_DOMAIN_BOOT_MENU_DISABLED)
+                    virBufferVSprintf(&boot_buf, "order=%s,menu=off", boot);
+            } else {
+                virBufferVSprintf(&boot_buf, "%s", boot);
+            }
+
+            virCommandAddArgBuffer(cmd, &boot_buf);
+        }
+
+        if (def->os.kernel)
+            virCommandAddArgList(cmd, "-kernel", def->os.kernel, NULL);
+        if (def->os.initrd)
+            virCommandAddArgList(cmd, "-initrd", def->os.initrd, NULL);
+        if (def->os.cmdline)
+            virCommandAddArgList(cmd, "-append", def->os.cmdline, NULL);
+    } else {
+        virCommandAddArgList(cmd, "-bootloader", def->os.bootloader, NULL);
+    }
+
+    for (i = 0 ; i < def->ndisks ; i++) {
+        virDomainDiskDefPtr disk = def->disks[i];
+
+        if (disk->driverName != NULL &&
+            !STREQ(disk->driverName, "qemu")) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("unsupported driver name '%s' for disk '%s'"),
+                            disk->driverName, disk->src);
+            goto error;
+        }
+    }
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+        for (i = 0 ; i < def->ncontrollers ; i++) {
+            virDomainControllerDefPtr cont = def->controllers[i];
+
+            /* We don't add an explicit IDE or FD controller because the
+             * provided PIIX4 device already includes one. It isn't possible to
+             * remove the PIIX4. */
+            if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE ||
+                cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC)
+                continue;
+
+            /* QEMU doesn't implement a SATA driver */
+            if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA) {
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                "%s", _("SATA is not supported with this QEMU binary"));
+                goto error;
+            }
+
+            virCommandAddArg(cmd, "-device");
+
+            char *devstr;
+            if (!(devstr = qemuBuildControllerDevStr(def->controllers[i])))
+                goto no_memory;
+
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
+        }
+    }
+
+    /* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
+        int bootCD = 0, bootFloppy = 0, bootDisk = 0;
+
+        /* If QEMU supports boot=on for -drive param... */
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) {
+            for (i = 0 ; i < def->os.nBootDevs ; i++) {
+                switch (def->os.bootDevs[i]) {
+                case VIR_DOMAIN_BOOT_CDROM:
+                    bootCD = 1;
+                    break;
+                case VIR_DOMAIN_BOOT_FLOPPY:
+                    bootFloppy = 1;
+                    break;
+                case VIR_DOMAIN_BOOT_DISK:
+                    bootDisk = 1;
+                    break;
+                }
+            }
+        }
+
+        for (i = 0 ; i < def->ndisks ; i++) {
+            char *optstr;
+            int bootable = 0;
+            virDomainDiskDefPtr disk = def->disks[i];
+            int withDeviceArg = 0;
+            int j;
+
+            /* Unless we have -device, then USB disks need special
+               handling */
+            if ((disk->bus == VIR_DOMAIN_DISK_BUS_USB) &&
+                !(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+                if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
+                    virCommandAddArg(cmd, "-usbdevice");
+                    virCommandAddArgFormat(cmd, "disk:%s", disk->src);
+                } else {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                    _("unsupported usb disk type for '%s'"),
+                                    disk->src);
+                    goto error;
+                }
+                continue;
+            }
+
+            switch (disk->device) {
+            case VIR_DOMAIN_DISK_DEVICE_CDROM:
+                bootable = bootCD;
+                bootCD = 0;
+                break;
+            case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
+                bootable = bootFloppy;
+                bootFloppy = 0;
+                break;
+            case VIR_DOMAIN_DISK_DEVICE_DISK:
+                bootable = bootDisk;
+                bootDisk = 0;
+                break;
+            }
+
+            virCommandAddArg(cmd, "-drive");
+
+            /* Unfortunately it is not possible to use
+               -device for floppies, or Xen paravirt
+               devices. Fortunately, those don't need
+               static PCI addresses, so we don't really
+               care that we can't use -device */
+            if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
+                (disk->bus != VIR_DOMAIN_DISK_BUS_XEN))
+                withDeviceArg = 1;
+            if (!(optstr = qemuBuildDriveStr(disk, bootable,
+                                             (withDeviceArg ? qemuCmdFlags :
+                                              (qemuCmdFlags & ~QEMUD_CMD_FLAG_DEVICE)))))
+                goto error;
+            virCommandAddArg(cmd, optstr);
+            VIR_FREE(optstr);
+
+            if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+                disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
+                for (j = 0 ; j < disk->nhosts ; j++) {
+                    if (!has_rbd_hosts) {
+                        virBufferAddLit(&rbd_hosts, "CEPH_ARGS=-m ");
+                        has_rbd_hosts = true;
+                    } else {
+                        virBufferAddLit(&rbd_hosts, ",");
+                    }
+                    virDomainDiskHostDefPtr host = &disk->hosts[j];
+                    if (host->port) {
+                        virBufferVSprintf(&rbd_hosts, "%s:%s",
+                                          host->name,
+                                          host->port);
+                    } else {
+                        virBufferVSprintf(&rbd_hosts, "%s",
+                                          host->name);
+                    }
+                }
+            }
+
+            if (withDeviceArg) {
+                if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
+                    virCommandAddArg(cmd, "-global");
+                    virCommandAddArgFormat(cmd, "isa-fdc.drive%c=drive-%s",
+                                           disk->info.addr.drive.unit
+                                           ? 'B' : 'A',
+                                           disk->info.alias);
+                } else {
+                    virCommandAddArg(cmd, "-device");
+
+                    if (!(optstr = qemuBuildDriveDevStr(disk)))
+                        goto error;
+                    virCommandAddArg(cmd, optstr);
+                    VIR_FREE(optstr);
+                }
+            }
+        }
+    } else {
+        for (i = 0 ; i < def->ndisks ; i++) {
+            char dev[NAME_MAX];
+            char file[PATH_MAX];
+            virDomainDiskDefPtr disk = def->disks[i];
+            int j;
+
+            if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
+                if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
+                    virCommandAddArg(cmd, "-usbdevice");
+                    virCommandAddArgFormat(cmd, "disk:%s", disk->src);
+                } else {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                    _("unsupported usb disk type for '%s'"),
+                                    disk->src);
+                    goto error;
+                }
+                continue;
+            }
+
+            if (STREQ(disk->dst, "hdc") &&
+                disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
+                if (disk->src) {
+                    snprintf(dev, NAME_MAX, "-%s", "cdrom");
+                } else {
+                    continue;
+                }
+            } else {
+                if (STRPREFIX(disk->dst, "hd") ||
+                    STRPREFIX(disk->dst, "fd")) {
+                    snprintf(dev, NAME_MAX, "-%s", disk->dst);
+                } else {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                    _("unsupported disk type '%s'"), disk->dst);
+                    goto error;
+                }
+            }
+
+            if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
+                /* QEMU only supports magic FAT format for now */
+                if (disk->driverType &&
+                    STRNEQ(disk->driverType, "fat")) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                    _("unsupported disk driver type for '%s'"),
+                                    disk->driverType);
+                    goto error;
+                }
+                if (!disk->readonly) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                    _("cannot create virtual FAT disks in read-write mode"));
+                    goto error;
+                }
+                if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
+                    snprintf(file, PATH_MAX, "fat:floppy:%s", disk->src);
+                else
+                    snprintf(file, PATH_MAX, "fat:%s", disk->src);
+            } else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
+                switch (disk->protocol) {
+                case VIR_DOMAIN_DISK_PROTOCOL_NBD:
+                    if (disk->nhosts != 1) {
+                        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                                        _("NBD accepts only one host"));
+                        goto error;
+                    }
+                    snprintf(file, PATH_MAX, "nbd:%s:%s,",
+                             disk->hosts->name, disk->hosts->port);
+                    break;
+                case VIR_DOMAIN_DISK_PROTOCOL_RBD:
+                    snprintf(file, PATH_MAX, "rbd:%s,", disk->src);
+                    for (j = 0 ; j < disk->nhosts ; j++) {
+                        if (!has_rbd_hosts) {
+                            virBufferAddLit(&rbd_hosts, "CEPH_ARGS=-m ");
+                            has_rbd_hosts = true;
+                        } else {
+                            virBufferAddLit(&rbd_hosts, ",");
+                        }
+                        virDomainDiskHostDefPtr host = &disk->hosts[j];
+                        if (host->port) {
+                            virBufferVSprintf(&rbd_hosts, "%s:%s",
+                                              host->name,
+                                              host->port);
+                        } else {
+                            virBufferVSprintf(&rbd_hosts, "%s",
+                                              host->name);
+                        }
+                    }
+                    break;
+                case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
+                    if (disk->nhosts == 0)
+                        snprintf(file, PATH_MAX, "sheepdog:%s,", disk->src);
+                    else
+                        /* only one host is supported now */
+                        snprintf(file, PATH_MAX, "sheepdog:%s:%s:%s,",
+                                 disk->hosts->name, disk->hosts->port,
+                                 disk->src);
+                    break;
+                }
+            } else {
+                snprintf(file, PATH_MAX, "%s", disk->src);
+            }
+
+            virCommandAddArgList(cmd, dev, file, NULL);
+        }
+    }
+
+    if (has_rbd_hosts)
+        virCommandAddEnvBuffer(cmd, &rbd_hosts);
+
+    if (qemuCmdFlags & QEMUD_CMD_FLAG_FSDEV) {
+        for (i = 0 ; i < def->nfss ; i++) {
+            char *optstr;
+            virDomainFSDefPtr fs = def->fss[i];
+
+            virCommandAddArg(cmd, "-fsdev");
+            if (!(optstr = qemuBuildFSStr(fs, qemuCmdFlags)))
+                goto error;
+            virCommandAddArg(cmd, optstr);
+            VIR_FREE(optstr);
+
+            virCommandAddArg(cmd, "-device");
+            if (!(optstr = qemuBuildFSDevStr(fs)))
+                goto error;
+            virCommandAddArg(cmd, optstr);
+            VIR_FREE(optstr);
+        }
+    } else {
+        if (def->nfss) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                            _("filesystem passthrough not supported by this QEMU"));
+            goto error;
+        }
+    }
+
+    if (!def->nnets) {
+        /* If we have -device, then we set -nodefault already */
+        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
+            virCommandAddArgList(cmd, "-net", "none", NULL);
+    } else {
+        for (i = 0 ; i < def->nnets ; i++) {
+            virDomainNetDefPtr net = def->nets[i];
+            char *nic, *host;
+            char tapfd_name[50];
+            char vhostfd_name[50] = "";
+            int vlan;
+
+            /* VLANs are not used with -netdev, so don't record them */
+            if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
+                (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
+                vlan = -1;
+            else
+                vlan = i;
+
+            if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
+                net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+                int tapfd = qemuNetworkIfaceConnect(conn, driver, net,
+                                                    qemuCmdFlags);
+                if (tapfd < 0)
+                    goto error;
+
+                last_good_net = i;
+                virCommandTransferFD(cmd, tapfd);
+
+                if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
+                             tapfd) >= sizeof(tapfd_name))
+                    goto no_memory;
+            } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
+                int tapfd = qemuPhysIfaceConnect(conn, driver, net,
+                                                 qemuCmdFlags,
+                                                 def->uuid,
+                                                 vmop);
+                if (tapfd < 0)
+                    goto error;
+
+                last_good_net = i;
+                virCommandTransferFD(cmd, tapfd);
+
+                if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
+                             tapfd) >= sizeof(tapfd_name))
+                    goto no_memory;
+            }
+
+            if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
+                net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
+                net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
+                /* Attempt to use vhost-net mode for these types of
+                   network device */
+                int vhostfd = qemuOpenVhostNet(net, qemuCmdFlags);
+                if (vhostfd >= 0) {
+                    virCommandTransferFD(cmd, vhostfd);
+
+                    if (snprintf(vhostfd_name, sizeof(vhostfd_name), "%d",
+                                 vhostfd) >= sizeof(vhostfd_name))
+                        goto no_memory;
+                }
+            }
+            /* Possible combinations:
+             *
+             *  1. Old way:   -net nic,model=e1000,vlan=1 -net tap,vlan=1
+             *  2. Semi-new:  -device e1000,vlan=1        -net tap,vlan=1
+             *  3. Best way:  -netdev type=tap,id=netdev1 -device e1000,id=netdev1
+             *
+             * NB, no support for -netdev without use of -device
+             */
+            if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
+                (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+                virCommandAddArg(cmd, "-netdev");
+                if (!(host = qemuBuildHostNetStr(net, ',', vlan,
+                                                 tapfd_name, vhostfd_name)))
+                    goto error;
+                virCommandAddArg(cmd, host);
+                VIR_FREE(host);
+            }
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+                virCommandAddArg(cmd, "-device");
+                if (!(nic = qemuBuildNicDevStr(net, vlan)))
+                    goto error;
+                virCommandAddArg(cmd, nic);
+                VIR_FREE(nic);
+            } else {
+                virCommandAddArg(cmd, "-net");
+                if (!(nic = qemuBuildNicStr(net, "nic,", vlan)))
+                    goto error;
+                virCommandAddArg(cmd, nic);
+                VIR_FREE(nic);
+            }
+            if (!((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
+                  (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))) {
+                virCommandAddArg(cmd, "-net");
+                if (!(host = qemuBuildHostNetStr(net, ',', vlan,
+                                                 tapfd_name, vhostfd_name)))
+                    goto error;
+                virCommandAddArg(cmd, host);
+                VIR_FREE(host);
+            }
+        }
+    }
+
+    if (!def->nserials) {
+        /* If we have -device, then we set -nodefault already */
+        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
+            virCommandAddArgList(cmd, "-serial", "none", NULL);
+    } else {
+        for (i = 0 ; i < def->nserials ; i++) {
+            virDomainChrDefPtr serial = def->serials[i];
+            char *devstr;
+
+            /* Use -chardev with -device if they are available */
+            if ((qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) &&
+                (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+                virCommandAddArg(cmd, "-chardev");
+                if (!(devstr = qemuBuildChrChardevStr(serial)))
+                    goto error;
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
+
+                virCommandAddArg(cmd, "-device");
+                virCommandAddArgFormat(cmd, "isa-serial,chardev=%s",
+                                       serial->info.alias);
+            } else {
+                virCommandAddArg(cmd, "-serial");
+                if (!(devstr = qemuBuildChrArgStr(serial, NULL)))
+                    goto error;
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
+            }
+        }
+    }
+
+    if (!def->nparallels) {
+        /* If we have -device, then we set -nodefault already */
+        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
+            virCommandAddArgList(cmd, "-parallel", "none", NULL);
+    } else {
+        for (i = 0 ; i < def->nparallels ; i++) {
+            virDomainChrDefPtr parallel = def->parallels[i];
+            char *devstr;
+
+            /* Use -chardev with -device if they are available */
+            if ((qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) &&
+                (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+                virCommandAddArg(cmd, "-chardev");
+                if (!(devstr = qemuBuildChrChardevStr(parallel)))
+                    goto error;
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
+
+                virCommandAddArg(cmd, "-device");
+                virCommandAddArgFormat(cmd, "isa-parallel,chardev=%s",
+                                       parallel->info.alias);
+            } else {
+                virCommandAddArg(cmd, "-parallel");
+                if (!(devstr = qemuBuildChrArgStr(parallel, NULL)))
+                      goto error;
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
+            }
+        }
+    }
+
+    for (i = 0 ; i < def->nchannels ; i++) {
+        virDomainChrDefPtr channel = def->channels[i];
+        char *devstr;
+
+        switch(channel->targetType) {
+        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
+            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) ||
+                !(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                "%s", _("guestfwd requires QEMU to support -chardev & -device"));
+                goto error;
+            }
+
+            virCommandAddArg(cmd, "-chardev");
+            if (!(devstr = qemuBuildChrChardevStr(channel)))
+                goto error;
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
+
+            char *addr = virSocketFormatAddr(channel->target.addr);
+            if (!addr)
+                goto error;
+            int port = virSocketGetPort(channel->target.addr);
+
+            virCommandAddArg(cmd, "-netdev");
+            virCommandAddArgFormat(cmd,
+                                   "user,guestfwd=tcp:%s:%i,chardev=%s,id=user-%s",
+                                   addr, port, channel->info.alias,
+                                   channel->info.alias);
+            VIR_FREE(addr);
+            break;
+
+        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
+            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                    _("virtio channel requires QEMU to support -device"));
+                goto error;
+            }
+
+            virCommandAddArg(cmd, "-chardev");
+            if (!(devstr = qemuBuildChrChardevStr(channel)))
+                goto error;
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
+
+            virCommandAddArg(cmd, "-device");
+            if (!(devstr = qemuBuildVirtioSerialPortDevStr(channel)))
+                goto error;
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
+            break;
+        }
+    }
+
+    /* Explicit console devices */
+    if (def->console) {
+        virDomainChrDefPtr console = def->console;
+        char *devstr;
+
+        switch(console->targetType) {
+        case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO:
+            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
+                qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
+                    _("virtio channel requires QEMU to support -device"));
+                goto error;
+            }
+
+            virCommandAddArg(cmd, "-chardev");
+            if (!(devstr = qemuBuildChrChardevStr(console)))
+                goto error;
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
+
+            virCommandAddArg(cmd, "-device");
+            if (!(devstr = qemuBuildVirtioSerialPortDevStr(console)))
+                goto error;
+            virCommandAddArg(cmd, devstr);
+            VIR_FREE(devstr);
+            break;
+
+        case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL:
+            break;
+
+        default:
+            qemuReportError(VIR_ERR_NO_SUPPORT,
+                            _("unsupported console target type %s"),
+                            NULLSTR(virDomainChrConsoleTargetTypeToString(console->targetType)));
+            goto error;
+        }
+    }
+
+    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;
+                virCommandAddArg(cmd, "-device");
+                if (!(optstr = qemuBuildUSBInputDevStr(input)))
+                    goto error;
+                virCommandAddArg(cmd, optstr);
+                VIR_FREE(optstr);
+            } else {
+                virCommandAddArgList(cmd, "-usbdevice",
+                                     input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE
+                                     ? "mouse" : "tablet", NULL);
+            }
+        }
+    }
+
+    if (def->ngraphics > 1) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("only 1 graphics device is supported"));
+        goto error;
+    }
+
+    if ((def->ngraphics == 1) &&
+        def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+        virBuffer opt = VIR_BUFFER_INITIALIZER;
+
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
+            if (def->graphics[0]->data.vnc.listenAddr)
+                virBufferAdd(&opt, def->graphics[0]->data.vnc.listenAddr, -1);
+            else if (driver->vncListen)
+                virBufferAdd(&opt, driver->vncListen, -1);
+
+            virBufferVSprintf(&opt, ":%d",
+                              def->graphics[0]->data.vnc.port - 5900);
+
+            if (def->graphics[0]->data.vnc.auth.passwd ||
+                driver->vncPassword)
+                virBufferAddLit(&opt, ",password");
+
+            if (driver->vncTLS) {
+                virBufferAddLit(&opt, ",tls");
+                if (driver->vncTLSx509verify) {
+                    virBufferVSprintf(&opt, ",x509verify=%s",
+                                      driver->vncTLSx509certdir);
+                } else {
+                    virBufferVSprintf(&opt, ",x509=%s",
+                                      driver->vncTLSx509certdir);
+                }
+            }
+
+            if (driver->vncSASL) {
+                virBufferAddLit(&opt, ",sasl");
+
+                if (driver->vncSASLdir)
+                    virCommandAddEnvPair(cmd, "SASL_CONF_DIR",
+                                         driver->vncSASLdir);
+
+                /* TODO: Support ACLs later */
+            }
+        } else {
+            virBufferVSprintf(&opt, "%d",
+                              def->graphics[0]->data.vnc.port - 5900);
+        }
+
+        virCommandAddArg(cmd, "-vnc");
+        virCommandAddArgBuffer(cmd, &opt);
+        if (def->graphics[0]->data.vnc.keymap) {
+            virCommandAddArgList(cmd, "-k", def->graphics[0]->data.vnc.keymap,
+                                 NULL);
+        }
+
+        /* Unless user requested it, set the audio backend to none, to
+         * prevent it opening the host OS audio devices, since that causes
+         * security issues and might not work when using VNC.
+         */
+        if (driver->vncAllowHostAudio) {
+            virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV");
+        } else {
+            virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none");
+        }
+    } else if ((def->ngraphics == 1) &&
+               def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+        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.fullscreen)
+            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
+         */
+        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)
+            virCommandAddArg(cmd, "-sdl");
+
+    } else if ((def->ngraphics == 1) &&
+               def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
+        virBuffer opt = VIR_BUFFER_INITIALIZER;
+
+        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_SPICE)) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                            _("spice graphics are not supported with this QEMU"));
+            goto error;
+        }
+
+        virBufferVSprintf(&opt, "port=%u", def->graphics[0]->data.spice.port);
+
+        if (driver->spiceTLS && def->graphics[0]->data.spice.tlsPort != -1)
+            virBufferVSprintf(&opt, ",tls-port=%u", def->graphics[0]->data.spice.tlsPort);
+
+        if (def->graphics[0]->data.spice.listenAddr)
+            virBufferVSprintf(&opt, ",addr=%s", def->graphics[0]->data.spice.listenAddr);
+        else if (driver->spiceListen)
+            virBufferVSprintf(&opt, ",addr=%s", driver->spiceListen);
+
+        /* In the password case we set it via monitor command, to avoid
+         * making it visible on CLI, so there's no use of password=XXX
+         * in this bit of the code */
+        if (!def->graphics[0]->data.spice.auth.passwd &&
+            !driver->spicePassword)
+            virBufferAddLit(&opt, ",disable-ticketing");
+
+        if (driver->spiceTLS)
+            virBufferVSprintf(&opt, ",x509-dir=%s",
+                              driver->spiceTLSx509certdir);
+
+        for (i = 0 ; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST ; i++) {
+            int mode = def->graphics[0]->data.spice.channels[i];
+            switch (mode) {
+            case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
+                virBufferVSprintf(&opt, ",tls-channel=%s",
+                                  virDomainGraphicsSpiceChannelNameTypeToString(i));
+                break;
+            case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
+                virBufferVSprintf(&opt, ",plaintext-channel=%s",
+                                  virDomainGraphicsSpiceChannelNameTypeToString(i));
+                break;
+            }
+        }
+
+        virCommandAddArg(cmd, "-spice");
+        virCommandAddArgBuffer(cmd, &opt);
+        if (def->graphics[0]->data.spice.keymap)
+            virCommandAddArgList(cmd, "-k",
+                                 def->graphics[0]->data.spice.keymap, NULL);
+        /* SPICE includes native support for tunnelling audio, so we
+         * set the audio backend to point at SPICE's own driver
+         */
+        virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=spice");
+
+    } else if ((def->ngraphics == 1)) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                    _("unsupported graphics type '%s'"),
+                    virDomainGraphicsTypeToString(def->graphics[0]->type));
+        goto error;
+    }
+
+    if (def->nvideos > 0) {
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_VGA) {
+            if (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_XEN) {
+                /* nothing - vga has no effect on Xen pvfb */
+            } else {
+                if ((def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_QXL) &&
+                    !(qemuCmdFlags & QEMUD_CMD_FLAG_VGA_QXL)) {
+                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                    _("This QEMU does not support QXL graphics adapters"));
+                    goto error;
+                }
+
+                const char *vgastr = qemuVideoTypeToString(def->videos[0]->type);
+                if (!vgastr || STREQ(vgastr, "")) {
+                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                    _("video type %s is not supported with QEMU"),
+                                    virDomainVideoTypeToString(def->videos[0]->type));
+                    goto error;
+                }
+
+                virCommandAddArgList(cmd, "-vga", vgastr, NULL);
+            }
+        } else {
+
+            switch (def->videos[0]->type) {
+            case VIR_DOMAIN_VIDEO_TYPE_VGA:
+                virCommandAddArg(cmd, "-std-vga");
+                break;
+
+            case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
+                virCommandAddArg(cmd, "-vmwarevga");
+                break;
+
+            case VIR_DOMAIN_VIDEO_TYPE_XEN:
+            case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
+                /* No special args - this is the default */
+                break;
+
+            default:
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                _("video type %s is not supported with this QEMU"),
+                                virDomainVideoTypeToString(def->videos[0]->type));
+                goto error;
+            }
+        }
+
+        if (def->nvideos > 1) {
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+                for (i = 1 ; i < def->nvideos ; i++) {
+                    char *str;
+                    if (def->videos[i]->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
+                        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                        _("video type %s is only valid as primary video card"),
+                                        virDomainVideoTypeToString(def->videos[0]->type));
+                        goto error;
+                    }
+
+                    virCommandAddArg(cmd, "-device");
+
+                    if (!(str = qemuBuildVideoDevStr(def->videos[i])))
+                        goto error;
+
+                    virCommandAddArg(cmd, str);
+                    VIR_FREE(str);
+                }
+            } else {
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                                "%s", _("only one video card is currently supported"));
+                goto error;
+            }
+        }
+
+    } else {
+        /* If we have -device, then we set -nodefault already */
+        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
+            (qemuCmdFlags & QEMUD_CMD_FLAG_VGA) &&
+            (qemuCmdFlags & QEMUD_CMD_FLAG_VGA_NONE))
+            virCommandAddArgList(cmd, "-vga", "none", NULL);
+    }
+
+    /* Add sound hardware */
+    if (def->nsounds) {
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+            for (i = 0 ; i < def->nsounds ; i++) {
+                virDomainSoundDefPtr sound = def->sounds[i];
+                char *str = NULL;
+
+                /* Sadly pcspk device doesn't use -device syntax. Fortunately
+                 * 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) {
+                    virCommandAddArgList(cmd, "-soundhw", "pcspk", NULL);
+                } else {
+                    virCommandAddArg(cmd, "-device");
+
+                    if (!(str = qemuBuildSoundDevStr(sound)))
+                        goto error;
+
+                    virCommandAddArg(cmd, str);
+                    VIR_FREE(str);
+                }
+            }
+        } else {
+            int size = 100;
+            char *modstr;
+            if (VIR_ALLOC_N(modstr, size+1) < 0)
+                goto no_memory;
+
+            for (i = 0 ; i < def->nsounds && size > 0 ; i++) {
+                virDomainSoundDefPtr sound = def->sounds[i];
+                const char *model = virDomainSoundModelTypeToString(sound->model);
+                if (!model) {
+                    VIR_FREE(modstr);
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                    "%s", _("invalid sound model"));
+                    goto error;
+                }
+                strncat(modstr, model, size);
+                size -= strlen(model);
+                if (i < (def->nsounds - 1))
+                    strncat(modstr, ",", size--);
+            }
+            virCommandAddArgList(cmd, "-soundhw", modstr, NULL);
+            VIR_FREE(modstr);
+        }
+    }
+
+    /* Add watchdog hardware */
+    if (def->watchdog) {
+        virDomainWatchdogDefPtr watchdog = def->watchdog;
+        char *optstr;
+
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+            virCommandAddArg(cmd, "-device");
+
+            optstr = qemuBuildWatchdogDevStr(watchdog);
+            if (!optstr)
+                goto error;
+        } else {
+            virCommandAddArg(cmd, "-watchdog");
+
+            const char *model = virDomainWatchdogModelTypeToString(watchdog->model);
+            if (!model) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                "%s", _("missing watchdog model"));
+                goto error;
+            }
+
+            if (!(optstr = strdup(model)))
+                goto no_memory;
+        }
+        virCommandAddArg(cmd, optstr);
+        VIR_FREE(optstr);
+
+        int act = watchdog->action;
+        if (act == VIR_DOMAIN_WATCHDOG_ACTION_DUMP)
+            act = VIR_DOMAIN_WATCHDOG_ACTION_PAUSE;
+        const char *action = virDomainWatchdogActionTypeToString(act);
+        if (!action) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("invalid watchdog action"));
+            goto error;
+        }
+        virCommandAddArgList(cmd, "-watchdog-action", action, NULL);
+    }
+
+    /* Add host passthrough hardware */
+    for (i = 0 ; i < def->nhostdevs ; i++) {
+        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
+        char *devstr;
+
+        /* USB */
+        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
+
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+                virCommandAddArg(cmd, "-device");
+                if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
+                    goto error;
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
+            } else {
+                virCommandAddArg(cmd, "-usbdevice");
+                if (!(devstr = qemuBuildUSBHostdevUsbDevStr(hostdev)))
+                    goto error;
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
+            }
+        }
+
+        /* PCI */
+        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
+            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
+            if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+                char *configfd_name = NULL;
+                if (qemuCmdFlags & QEMUD_CMD_FLAG_PCI_CONFIGFD) {
+                    int configfd = qemuOpenPCIConfig(hostdev);
+
+                    if (configfd >= 0) {
+                        if (virAsprintf(&configfd_name, "%d", configfd) < 0) {
+                            VIR_FORCE_CLOSE(configfd);
+                            virReportOOMError();
+                            goto no_memory;
+                        }
+
+                        virCommandTransferFD(cmd, configfd);
+                    }
+                }
+                virCommandAddArg(cmd, "-device");
+                devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name);
+                VIR_FREE(configfd_name);
+                if (!devstr)
+                    goto error;
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
+            } else if (qemuCmdFlags & QEMUD_CMD_FLAG_PCIDEVICE) {
+                virCommandAddArg(cmd, "-pcidevice");
+                if (!(devstr = qemuBuildPCIHostdevPCIDevStr(hostdev)))
+                    goto error;
+                virCommandAddArg(cmd, devstr);
+                VIR_FREE(devstr);
+            } else {
+                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+                                _("PCI device assignment is not supported by this version of qemu"));
+                goto error;
+            }
+        }
+    }
+
+    if (migrateFrom)
+        virCommandAddArgList(cmd, "-incoming", migrateFrom, NULL);
+
+    /* QEMU changed its default behavior to not include the virtio balloon
+     * device.  Explicitly request it to ensure it will be present.
+     *
+     * NB: Earlier we declared that VirtIO balloon will always be in
+     * slot 0x3 on bus 0x0
+     */
+    if ((def->memballoon) &&
+        (def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
+        if (def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) {
+            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                            _("Memory balloon device type '%s' is not supported by this version of qemu"),
+                            virDomainMemballoonModelTypeToString(def->memballoon->model));
+            goto error;
+        }
+        if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
+            char *optstr;
+            virCommandAddArg(cmd, "-device");
+
+            optstr = qemuBuildMemballoonDevStr(def->memballoon);
+            if (!optstr)
+                goto error;
+            virCommandAddArg(cmd, optstr);
+            VIR_FREE(optstr);
+        } else if (qemuCmdFlags & QEMUD_CMD_FLAG_BALLOON) {
+            virCommandAddArgList(cmd, "-balloon", "virtio", NULL);
+        }
+    }
+
+    if (current_snapshot && current_snapshot->def->active)
+        virCommandAddArgList(cmd, "-loadvm", current_snapshot->def->name,
+                             NULL);
+
+    if (def->namespaceData) {
+        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++)
+            virCommandAddEnvPair(cmd, qemucmd->env_name[i],
+                                 qemucmd->env_value[i]
+                                 ? qemucmd->env_value[i] : "");
+    }
+
+    return cmd;
+
+ no_memory:
+    virReportOOMError();
+ error:
+    for (i = 0; i <= last_good_net; i++)
+        virDomainConfNWFilterTeardown(def->nets[i]);
+    virBufferFreeAndReset(&rbd_hosts);
+    virCommandFree(cmd);
+    return NULL;
+}
+
+
+/*
+ * This method takes a string representing a QEMU command line ARGV set
+ * optionally prefixed by a list of environment variables. It then tries
+ * to split it up into a NULL terminated list of env & argv, splitting
+ * on space
+ */
+static int qemuStringToArgvEnv(const char *args,
+                               const char ***retenv,
+                               const char ***retargv)
+{
+    char **arglist = NULL;
+    int argcount = 0;
+    int argalloc = 0;
+    int envend;
+    int i;
+    const char *curr = args;
+    const char *start;
+    const char **progenv = NULL;
+    const char **progargv = NULL;
+
+    /* Iterate over string, splitting on sequences of ' ' */
+    while (curr && *curr != '\0') {
+        char *arg;
+        const char *next;
+
+        start = curr;
+        /* accept a space in CEPH_ARGS */
+        if (STRPREFIX(curr, "CEPH_ARGS=-m ")) {
+            start += strlen("CEPH_ARGS=-m ");
+        }
+        if (*start == '\'') {
+            if (start == curr)
+                curr++;
+            next = strchr(start + 1, '\'');
+        } else if (*start == '"') {
+            if (start == curr)
+                curr++;
+            next = strchr(start + 1, '"');
+        } else {
+            next = strchr(start, ' ');
+        }
+        if (!next)
+            next = strchr(curr, '\n');
+
+        if (next) {
+            arg = strndup(curr, next-curr);
+            if (*next == '\'' ||
+                *next == '"')
+                next++;
+        } else {
+            arg = strdup(curr);
+        }
+
+        if (!arg)
+            goto no_memory;
+
+        if (argalloc == argcount) {
+            if (VIR_REALLOC_N(arglist, argalloc+10) < 0) {
+                VIR_FREE(arg);
+                goto no_memory;
+            }
+            argalloc+=10;
+        }
+
+        arglist[argcount++] = arg;
+
+        while (next && c_isspace(*next))
+            next++;
+
+        curr = next;
+    }
+
+    /* Iterate over list of args, finding first arg not containing
+     * the '=' character (eg, skip over env vars FOO=bar) */
+    for (envend = 0 ; ((envend < argcount) &&
+                       (strchr(arglist[envend], '=') != NULL));
+         envend++)
+        ; /* nada */
+
+    /* Copy the list of env vars */
+    if (envend > 0) {
+        if (VIR_REALLOC_N(progenv, envend+1) < 0)
+            goto no_memory;
+        for (i = 0 ; i < envend ; i++) {
+            progenv[i] = arglist[i];
+            arglist[i] = NULL;
+        }
+        progenv[i] = NULL;
+    }
+
+    /* Copy the list of argv */
+    if (VIR_REALLOC_N(progargv, argcount-envend + 1) < 0)
+        goto no_memory;
+    for (i = envend ; i < argcount ; i++)
+        progargv[i-envend] = arglist[i];
+    progargv[i-envend] = NULL;
+
+    VIR_FREE(arglist);
+
+    *retenv = progenv;
+    *retargv = progargv;
+
+    return 0;
+
+no_memory:
+    for (i = 0 ; progenv && progenv[i] ; i++)
+        VIR_FREE(progenv[i]);
+    VIR_FREE(progenv);
+    for (i = 0 ; i < argcount ; i++)
+        VIR_FREE(arglist[i]);
+    VIR_FREE(arglist);
+    virReportOOMError();
+    return -1;
+}
+
+
+/*
+ * Search for a named env variable, and return the value part
+ */
+static const char *qemuFindEnv(const char **progenv,
+                               const char *name)
+{
+    int i;
+    int len = strlen(name);
+
+    for (i = 0 ; progenv && progenv[i] ; i++) {
+        if (STREQLEN(progenv[i], name, len) &&
+            progenv[i][len] == '=')
+            return progenv[i] + len + 1;
+    }
+    return NULL;
+}
+
+/*
+ * Takes a string containing a set of key=value,key=value,key...
+ * parameters and splits them up, returning two arrays with
+ * the individual keys and values. If allowEmptyValue is nonzero,
+ * the "=value" part is optional and if a key with no value is found,
+ * NULL is be placed into corresponding place in retvalues.
+ */
+int
+qemuParseKeywords(const char *str,
+                  char ***retkeywords,
+                  char ***retvalues,
+                  int allowEmptyValue)
+{
+    int keywordCount = 0;
+    int keywordAlloc = 0;
+    char **keywords = NULL;
+    char **values = NULL;
+    const char *start = str;
+    const char *end;
+    int i;
+
+    *retkeywords = NULL;
+    *retvalues = NULL;
+    end = start + strlen(str);
+
+    while (start) {
+        const char *separator;
+        const char *endmark;
+        char *keyword;
+        char *value = NULL;
+
+        if (!(endmark = strchr(start, ',')))
+            endmark = end;
+        if (!(separator = strchr(start, '=')))
+            separator = end;
+
+        if (separator >= endmark) {
+            if (!allowEmptyValue) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("malformed keyword arguments in '%s'"), str);
+                goto error;
+            }
+            separator = endmark;
+        }
+
+        if (!(keyword = strndup(start, separator - start)))
+            goto no_memory;
+
+        if (separator < endmark) {
+            separator++;
+            if (!(value = strndup(separator, endmark - separator))) {
+                VIR_FREE(keyword);
+                goto no_memory;
+            }
+        }
+
+        if (keywordAlloc == keywordCount) {
+            if (VIR_REALLOC_N(keywords, keywordAlloc + 10) < 0 ||
+                VIR_REALLOC_N(values, keywordAlloc + 10) < 0) {
+                VIR_FREE(keyword);
+                VIR_FREE(value);
+                goto no_memory;
+            }
+            keywordAlloc += 10;
+        }
+
+        keywords[keywordCount] = keyword;
+        values[keywordCount] = value;
+        keywordCount++;
+
+        start = endmark < end ? endmark + 1 : NULL;
+    }
+
+    *retkeywords = keywords;
+    *retvalues = values;
+
+    return keywordCount;
+
+no_memory:
+    virReportOOMError();
+error:
+    for (i = 0 ; i < keywordCount ; i++) {
+        VIR_FREE(keywords[i]);
+        VIR_FREE(values[i]);
+    }
+    VIR_FREE(keywords);
+    VIR_FREE(values);
+    return -1;
+}
+
+/*
+ * Tries to parse new style QEMU -drive  args.
+ *
+ * eg -drive file=/dev/HostVG/VirtData1,if=ide,index=1
+ *
+ * Will fail if not using the 'index' keyword
+ */
+static virDomainDiskDefPtr
+qemuParseCommandLineDisk(virCapsPtr caps,
+                         const char *val,
+                         int nvirtiodisk)
+{
+    virDomainDiskDefPtr def = NULL;
+    char **keywords;
+    char **values;
+    int nkeywords;
+    int i;
+    int idx = -1;
+    int busid = -1;
+    int unitid = -1;
+
+    if ((nkeywords = qemuParseKeywords(val,
+                                       &keywords,
+                                       &values, 0)) < 0)
+        return NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->bus = VIR_DOMAIN_DISK_BUS_IDE;
+    def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+    def->type = VIR_DOMAIN_DISK_TYPE_FILE;
+
+    for (i = 0 ; i < nkeywords ; i++) {
+        if (STREQ(keywords[i], "file")) {
+            if (values[i] && STRNEQ(values[i], "")) {
+                def->src = values[i];
+                values[i] = NULL;
+                if (STRPREFIX(def->src, "/dev/"))
+                    def->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
+                else if (STRPREFIX(def->src, "nbd:")) {
+                    char *host, *port;
+
+                    def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
+                    host = def->src + strlen("nbd:");
+                    port = strchr(host, ':');
+                    if (!port) {
+                        def = NULL;
+                        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                        _("cannot parse nbd filename '%s'"), def->src);
+                        goto cleanup;
+                    }
+                    *port++ = '\0';
+                    if (VIR_ALLOC(def->hosts) < 0) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+                    def->nhosts = 1;
+                    def->hosts->name = strdup(host);
+                    if (!def->hosts->name) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+                    def->hosts->port = strdup(port);
+                    if (!def->hosts->port) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+
+                    VIR_FREE(def->src);
+                    def->src = NULL;
+                } else if (STRPREFIX(def->src, "rbd:")) {
+                    char *p = def->src;
+
+                    def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
+                    def->src = strdup(p + strlen("rbd:"));
+                    if (!def->src) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+
+                    VIR_FREE(p);
+                } else if (STRPREFIX(def->src, "sheepdog:")) {
+                    char *p = def->src;
+                    char *port, *vdi;
+
+                    def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
+                    def->src = strdup(p + strlen("sheepdog:"));
+                    if (!def->src) {
+                        virReportOOMError();
+                        goto cleanup;
+                    }
+
+                    /* def->src must be [vdiname] or [host]:[port]:[vdiname] */
+                    port = strchr(def->src, ':');
+                    if (port) {
+                        *port++ = '\0';
+                        vdi = strchr(port, ':');
+                        if (!vdi) {
+                            def = NULL;
+                            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                            _("cannot parse sheepdog filename '%s'"), p);
+                            goto cleanup;
+                        }
+                        *vdi++ = '\0';
+                        if (VIR_ALLOC(def->hosts) < 0) {
+                            virReportOOMError();
+                            goto cleanup;
+                        }
+                        def->nhosts = 1;
+                        def->hosts->name = def->src;
+                        def->hosts->port = strdup(port);
+                        if (!def->hosts->port) {
+                            virReportOOMError();
+                            goto cleanup;
+                        }
+                        def->src = strdup(vdi);
+                        if (!def->src) {
+                            virReportOOMError();
+                            goto cleanup;
+                        }
+                    }
+
+                    VIR_FREE(p);
+                } else
+                    def->type = VIR_DOMAIN_DISK_TYPE_FILE;
+            } else {
+                def->type = VIR_DOMAIN_DISK_TYPE_FILE;
+            }
+        } else if (STREQ(keywords[i], "if")) {
+            if (STREQ(values[i], "ide"))
+                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
+            else if (STREQ(values[i], "scsi"))
+                def->bus = VIR_DOMAIN_DISK_BUS_SCSI;
+            else if (STREQ(values[i], "virtio"))
+                def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
+            else if (STREQ(values[i], "xen"))
+                def->bus = VIR_DOMAIN_DISK_BUS_XEN;
+        } else if (STREQ(keywords[i], "media")) {
+            if (STREQ(values[i], "cdrom")) {
+                def->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
+                def->readonly = 1;
+            } else if (STREQ(values[i], "floppy"))
+                def->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
+        } else if (STREQ(keywords[i], "format")) {
+            def->driverName = strdup("qemu");
+            if (!def->driverName) {
+                virDomainDiskDefFree(def);
+                def = NULL;
+                virReportOOMError();
+                goto cleanup;
+            }
+            def->driverType = values[i];
+            values[i] = NULL;
+        } else if (STREQ(keywords[i], "cache")) {
+            if (STREQ(values[i], "off") ||
+                STREQ(values[i], "none"))
+                def->cachemode = VIR_DOMAIN_DISK_CACHE_DISABLE;
+            else if (STREQ(values[i], "writeback") ||
+                     STREQ(values[i], "on"))
+                def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITEBACK;
+            else if (STREQ(values[i], "writethrough"))
+                def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITETHRU;
+        } else if (STREQ(keywords[i], "werror") ||
+                   STREQ(keywords[i], "rerror")) {
+            if (STREQ(values[i], "stop"))
+                def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_STOP;
+            else if (STREQ(values[i], "ignore"))
+                def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_IGNORE;
+            else if (STREQ(values[i], "enospace"))
+                def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE;
+        } else if (STREQ(keywords[i], "index")) {
+            if (virStrToLong_i(values[i], NULL, 10, &idx) < 0) {
+                virDomainDiskDefFree(def);
+                def = NULL;
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("cannot parse drive index '%s'"), val);
+                goto cleanup;
+            }
+        } else if (STREQ(keywords[i], "bus")) {
+            if (virStrToLong_i(values[i], NULL, 10, &busid) < 0) {
+                virDomainDiskDefFree(def);
+                def = NULL;
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("cannot parse drive bus '%s'"), val);
+                goto cleanup;
+            }
+        } else if (STREQ(keywords[i], "unit")) {
+            if (virStrToLong_i(values[i], NULL, 10, &unitid) < 0) {
+                virDomainDiskDefFree(def);
+                def = NULL;
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("cannot parse drive unit '%s'"), val);
+                goto cleanup;
+            }
+        } else if (STREQ(keywords[i], "readonly")) {
+            if ((values[i] == NULL) || STREQ(values[i], "on"))
+                def->readonly = 1;
+        }
+    }
+
+    if (!def->src &&
+        def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+        def->type != VIR_DOMAIN_DISK_TYPE_NETWORK) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("missing file parameter in drive '%s'"), val);
+        virDomainDiskDefFree(def);
+        def = NULL;
+        goto cleanup;
+    }
+    if (idx == -1 &&
+        def->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
+        idx = nvirtiodisk;
+
+    if (idx == -1 &&
+        unitid == -1 &&
+        busid == -1) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("missing index/unit/bus parameter in drive '%s'"), val);
+        virDomainDiskDefFree(def);
+        def = NULL;
+        goto cleanup;
+    }
+
+    if (idx == -1) {
+        if (unitid == -1)
+            unitid = 0;
+        if (busid == -1)
+            busid = 0;
+        switch (def->bus) {
+        case VIR_DOMAIN_DISK_BUS_IDE:
+            idx = (busid * 2) + unitid;
+            break;
+        case VIR_DOMAIN_DISK_BUS_SCSI:
+            idx = (busid * 7) + unitid;
+            break;
+        default:
+            idx = unitid;
+            break;
+        }
+    }
+
+    if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
+        def->dst = strdup("hda");
+    } else if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
+        def->dst = strdup("sda");
+    } else if (def->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
+        def->dst = strdup("vda");
+    } else if (def->bus == VIR_DOMAIN_DISK_BUS_XEN) {
+        def->dst = strdup("xvda");
+    } else {
+        def->dst = strdup("hda");
+    }
+
+    if (!def->dst) {
+        virDomainDiskDefFree(def);
+        def = NULL;
+        virReportOOMError();
+        goto cleanup;
+    }
+    if (STREQ(def->dst, "xvda"))
+        def->dst[3] = 'a' + idx;
+    else
+        def->dst[2] = 'a' + idx;
+
+    if (virDomainDiskDefAssignAddress(caps, def) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("invalid device name '%s'"), def->dst);
+        virDomainDiskDefFree(def);
+        def = NULL;
+        /* fall through to "cleanup" */
+    }
+
+cleanup:
+    for (i = 0 ; i < nkeywords ; i++) {
+        VIR_FREE(keywords[i]);
+        VIR_FREE(values[i]);
+    }
+    VIR_FREE(keywords);
+    VIR_FREE(values);
+    return def;
+}
+
+/*
+ * Tries to find a NIC definition matching a vlan we want
+ */
+static const char *
+qemuFindNICForVLAN(int nnics,
+                   const char **nics,
+                   int wantvlan)
+{
+    int i;
+    for (i = 0 ; i < nnics ; i++) {
+        int gotvlan;
+        const char *tmp = strstr(nics[i], "vlan=");
+        char *end;
+        if (!tmp)
+            continue;
+
+        tmp += strlen("vlan=");
+
+        if (virStrToLong_i(tmp, &end, 10, &gotvlan) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot parse NIC vlan in '%s'"), nics[i]);
+            return NULL;
+        }
+
+        if (gotvlan == wantvlan)
+            return nics[i];
+    }
+
+    if (wantvlan == 0 && nnics > 0)
+        return nics[0];
+
+    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                    _("cannot find NIC definition for vlan %d"), wantvlan);
+    return NULL;
+}
+
+
+/*
+ * Tries to parse a QEMU -net backend argument. Gets given
+ * a list of all known -net frontend arguments to try and
+ * match up against. Horribly complicated stuff
+ */
+static virDomainNetDefPtr
+qemuParseCommandLineNet(virCapsPtr caps,
+                        const char *val,
+                        int nnics,
+                        const char **nics)
+{
+    virDomainNetDefPtr def = NULL;
+    char **keywords = NULL;
+    char **values = NULL;
+    int nkeywords;
+    const char *nic;
+    int wantvlan = 0;
+    const char *tmp;
+    int genmac = 1;
+    int i;
+
+    tmp = strchr(val, ',');
+
+    if (tmp) {
+        if ((nkeywords = qemuParseKeywords(tmp+1,
+                                           &keywords,
+                                           &values, 0)) < 0)
+            return NULL;
+    } else {
+        nkeywords = 0;
+    }
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    /* 'tap' could turn into libvirt type=ethernet, type=bridge or
+     * type=network, but we can't tell, so use the generic config */
+    if (STRPREFIX(val, "tap,"))
+        def->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+    else if (STRPREFIX(val, "socket"))
+        def->type = VIR_DOMAIN_NET_TYPE_CLIENT;
+    else if (STRPREFIX(val, "user"))
+        def->type = VIR_DOMAIN_NET_TYPE_USER;
+    else
+        def->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
+
+    for (i = 0 ; i < nkeywords ; i++) {
+        if (STREQ(keywords[i], "vlan")) {
+            if (virStrToLong_i(values[i], NULL, 10, &wantvlan) < 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("cannot parse vlan in '%s'"), val);
+                virDomainNetDefFree(def);
+                def = NULL;
+                goto cleanup;
+            }
+        } else if (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
+                   STREQ(keywords[i], "script") && STRNEQ(values[i], "")) {
+            def->data.ethernet.script = values[i];
+            values[i] = NULL;
+        } else if (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
+                   STREQ(keywords[i], "ifname")) {
+            def->ifname = values[i];
+            values[i] = NULL;
+        }
+    }
+
+
+    /* Done parsing the nic backend. Now to try and find corresponding
+     * frontend, based off vlan number. NB this assumes a 1-1 mapping
+     */
+
+    nic = qemuFindNICForVLAN(nnics, nics, wantvlan);
+    if (!nic) {
+        virDomainNetDefFree(def);
+        def = NULL;
+        goto cleanup;
+    }
+
+    if (!STRPREFIX(nic, "nic")) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot parse NIC definition '%s'"), nic);
+        virDomainNetDefFree(def);
+        def = NULL;
+        goto cleanup;
+    }
+
+    for (i = 0 ; i < nkeywords ; i++) {
+        VIR_FREE(keywords[i]);
+        VIR_FREE(values[i]);
+    }
+    VIR_FREE(keywords);
+    VIR_FREE(values);
+
+    if (STRPREFIX(nic, "nic,")) {
+        if ((nkeywords = qemuParseKeywords(nic + strlen("nic,"),
+                                           &keywords,
+                                           &values, 0)) < 0) {
+            virDomainNetDefFree(def);
+            def = NULL;
+            goto cleanup;
+        }
+    } else {
+        nkeywords = 0;
+    }
+
+    for (i = 0 ; i < nkeywords ; i++) {
+        if (STREQ(keywords[i], "macaddr")) {
+            genmac = 0;
+            if (virParseMacAddr(values[i], def->mac) < 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("unable to parse mac address '%s'"),
+                                values[i]);
+                virDomainNetDefFree(def);
+                def = NULL;
+                goto cleanup;
+            }
+        } else if (STREQ(keywords[i], "model")) {
+            def->model = values[i];
+            values[i] = NULL;
+        }
+    }
+
+    if (genmac)
+        virCapabilitiesGenerateMac(caps, def->mac);
+
+cleanup:
+    for (i = 0 ; i < nkeywords ; i++) {
+        VIR_FREE(keywords[i]);
+        VIR_FREE(values[i]);
+    }
+    VIR_FREE(keywords);
+    VIR_FREE(values);
+    return def;
+}
+
+
+/*
+ * Tries to parse a QEMU PCI device
+ */
+static virDomainHostdevDefPtr
+qemuParseCommandLinePCI(const char *val)
+{
+    virDomainHostdevDefPtr def = NULL;
+    int bus = 0, slot = 0, func = 0;
+    const char *start;
+    char *end;
+
+    if (!STRPREFIX(val, "host=")) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unknown PCI device syntax '%s'"), val);
+        VIR_FREE(def);
+        goto cleanup;
+    }
+
+    start = val + strlen("host=");
+    if (virStrToLong_i(start, &end, 16, &bus) < 0 || *end != ':') {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot extract PCI device bus '%s'"), val);
+        VIR_FREE(def);
+        goto cleanup;
+    }
+    start = end + 1;
+    if (virStrToLong_i(start, &end, 16, &slot) < 0 || *end != '.') {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot extract PCI device slot '%s'"), val);
+        VIR_FREE(def);
+        goto cleanup;
+    }
+    start = end + 1;
+    if (virStrToLong_i(start, NULL, 16, &func) < 0) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("cannot extract PCI device function '%s'"), val);
+        VIR_FREE(def);
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
+    def->managed = 1;
+    def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
+    def->source.subsys.u.pci.bus = bus;
+    def->source.subsys.u.pci.slot = slot;
+    def->source.subsys.u.pci.function = func;
+
+cleanup:
+    return def;
+}
+
+
+/*
+ * Tries to parse a QEMU USB device
+ */
+static virDomainHostdevDefPtr
+qemuParseCommandLineUSB(const char *val)
+{
+    virDomainHostdevDefPtr def = NULL;
+    int first = 0, second = 0;
+    const char *start;
+    char *end;
+
+    if (!STRPREFIX(val, "host:")) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unknown USB device syntax '%s'"), val);
+        VIR_FREE(def);
+        goto cleanup;
+    }
+
+    start = val + strlen("host:");
+    if (strchr(start, ':')) {
+        if (virStrToLong_i(start, &end, 16, &first) < 0 || *end != ':') {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot extract USB device vendor '%s'"), val);
+            VIR_FREE(def);
+            goto cleanup;
+        }
+        start = end + 1;
+        if (virStrToLong_i(start, NULL, 16, &second) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot extract USB device product '%s'"), val);
+            VIR_FREE(def);
+            goto cleanup;
+        }
+    } else {
+        if (virStrToLong_i(start, &end, 10, &first) < 0 || *end != '.') {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                             _("cannot extract USB device bus '%s'"), val);
+            VIR_FREE(def);
+            goto cleanup;
+        }
+        start = end + 1;
+        if (virStrToLong_i(start, NULL, 10, &second) < 0) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot extract USB device address '%s'"), val);
+            VIR_FREE(def);
+            goto cleanup;
+        }
+    }
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
+    def->managed = 0;
+    def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
+    if (*end == '.') {
+        def->source.subsys.u.usb.bus = first;
+        def->source.subsys.u.usb.device = second;
+    } else {
+        def->source.subsys.u.usb.vendor = first;
+        def->source.subsys.u.usb.product = second;
+    }
+
+cleanup:
+    return def;
+}
+
+
+/*
+ * Tries to parse a QEMU serial/parallel device
+ */
+static virDomainChrDefPtr
+qemuParseCommandLineChr(const char *val)
+{
+    virDomainChrDefPtr def;
+
+    if (VIR_ALLOC(def) < 0)
+        goto no_memory;
+
+    if (STREQ(val, "null")) {
+        def->type = VIR_DOMAIN_CHR_TYPE_NULL;
+    } else if (STREQ(val, "vc")) {
+        def->type = VIR_DOMAIN_CHR_TYPE_VC;
+    } else if (STREQ(val, "pty")) {
+        def->type = VIR_DOMAIN_CHR_TYPE_PTY;
+    } else if (STRPREFIX(val, "file:")) {
+        def->type = VIR_DOMAIN_CHR_TYPE_FILE;
+        def->data.file.path = strdup(val+strlen("file:"));
+        if (!def->data.file.path)
+            goto no_memory;
+    } else if (STRPREFIX(val, "pipe:")) {
+        def->type = VIR_DOMAIN_CHR_TYPE_PIPE;
+        def->data.file.path = strdup(val+strlen("pipe:"));
+        if (!def->data.file.path)
+            goto no_memory;
+    } else if (STREQ(val, "stdio")) {
+        def->type = VIR_DOMAIN_CHR_TYPE_STDIO;
+    } else if (STRPREFIX(val, "udp:")) {
+        const char *svc1, *host2, *svc2;
+        def->type = VIR_DOMAIN_CHR_TYPE_UDP;
+        val += strlen("udp:");
+        svc1 = strchr(val, ':');
+        host2 = svc1 ? strchr(svc1, '@') : NULL;
+        svc2 = host2 ? strchr(host2, ':') : NULL;
+
+        if (svc1)
+            def->data.udp.connectHost = strndup(val, svc1-val);
+        else
+            def->data.udp.connectHost = strdup(val);
+
+        if (!def->data.udp.connectHost)
+            goto no_memory;
+
+        if (svc1) {
+            svc1++;
+            if (host2)
+                def->data.udp.connectService = strndup(svc1, host2-svc1);
+            else
+                def->data.udp.connectService = strdup(svc1);
+
+            if (!def->data.udp.connectService)
+                goto no_memory;
+        }
+
+        if (host2) {
+            host2++;
+            if (svc2)
+                def->data.udp.bindHost = strndup(host2, svc2-host2);
+            else
+                def->data.udp.bindHost = strdup(host2);
+
+            if (!def->data.udp.bindHost)
+                goto no_memory;
+        }
+        if (svc2) {
+            svc2++;
+            def->data.udp.bindService = strdup(svc2);
+            if (!def->data.udp.bindService)
+                goto no_memory;
+        }
+    } else if (STRPREFIX(val, "tcp:") ||
+               STRPREFIX(val, "telnet:")) {
+        const char *opt, *svc;
+        def->type = VIR_DOMAIN_CHR_TYPE_TCP;
+        if (STRPREFIX(val, "tcp:")) {
+            val += strlen("tcp:");
+        } else {
+            val += strlen("telnet:");
+            def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
+        }
+        svc = strchr(val, ':');
+        if (!svc) {
+            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                            _("cannot find port number in character device %s"), val);
+            goto error;
+        }
+        opt = strchr(svc, ',');
+        if (opt && strstr(opt, "server"))
+            def->data.tcp.listen = 1;
+
+        def->data.tcp.host = strndup(val, svc-val);
+        if (!def->data.tcp.host)
+            goto no_memory;
+        svc++;
+        if (opt) {
+            def->data.tcp.service = strndup(svc, opt-svc);
+        } else {
+            def->data.tcp.service = strdup(svc);
+        }
+        if (!def->data.tcp.service)
+            goto no_memory;
+    } else if (STRPREFIX(val, "unix:")) {
+        const char *opt;
+        val += strlen("unix:");
+        opt = strchr(val, ',');
+        def->type = VIR_DOMAIN_CHR_TYPE_UNIX;
+        if (opt) {
+            if (strstr(opt, "listen"))
+                def->data.nix.listen = 1;
+            def->data.nix.path = strndup(val, opt-val);
+        } else {
+            def->data.nix.path = strdup(val);
+        }
+        if (!def->data.nix.path)
+            goto no_memory;
+
+    } else if (STRPREFIX(val, "/dev")) {
+        def->type = VIR_DOMAIN_CHR_TYPE_DEV;
+        def->data.file.path = strdup(val);
+        if (!def->data.file.path)
+            goto no_memory;
+    } else {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unknown character device syntax %s"), val);
+        goto error;
+    }
+
+    return def;
+
+no_memory:
+    virReportOOMError();
+error:
+    virDomainChrDefFree(def);
+    return NULL;
+}
+
+
+static virCPUDefPtr
+qemuInitGuestCPU(virDomainDefPtr dom)
+{
+    if (!dom->cpu) {
+        virCPUDefPtr cpu;
+
+        if (VIR_ALLOC(cpu) < 0) {
+            virReportOOMError();
+            return NULL;
+        }
+
+        cpu->type = VIR_CPU_TYPE_GUEST;
+        cpu->match = VIR_CPU_MATCH_EXACT;
+        dom->cpu = cpu;
+    }
+
+    return dom->cpu;
+}
+
+
+static int
+qemuParseCommandLineCPU(virDomainDefPtr dom,
+                        const char *val)
+{
+    virCPUDefPtr cpu;
+    const char *p = val;
+    const char *next;
+
+    if (!(cpu = qemuInitGuestCPU(dom)))
+        goto error;
+
+    do {
+        if (*p == '\0' || *p == ',')
+            goto syntax;
+
+        if ((next = strchr(p, ',')))
+            next++;
+
+        if (!cpu->model) {
+            if (next)
+                cpu->model = strndup(p, next - p - 1);
+            else
+                cpu->model = strdup(p);
+
+            if (!cpu->model)
+                goto no_memory;
+        }
+        else if (*p == '+' || *p == '-') {
+            char *feature;
+            int policy;
+            int ret;
+
+            if (*p == '+')
+                policy = VIR_CPU_FEATURE_REQUIRE;
+            else
+                policy = VIR_CPU_FEATURE_DISABLE;
+
+            p++;
+            if (*p == '\0' || *p == ',')
+                goto syntax;
+
+            if (next)
+                feature = strndup(p, next - p - 1);
+            else
+                feature = strdup(p);
+
+            ret = virCPUDefAddFeature(cpu, feature, policy);
+            VIR_FREE(feature);
+            if (ret < 0)
+                goto error;
+        }
+    } while ((p = next));
+
+    return 0;
+
+syntax:
+    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                    _("unknown CPU syntax '%s'"), val);
+    goto error;
+
+no_memory:
+    virReportOOMError();
+error:
+    return -1;
+}
+
+
+static int
+qemuParseCommandLineSmp(virDomainDefPtr dom,
+                        const char *val)
+{
+    unsigned int sockets = 0;
+    unsigned int cores = 0;
+    unsigned int threads = 0;
+    unsigned int maxcpus = 0;
+    int i;
+    int nkws;
+    char **kws;
+    char **vals;
+    int n;
+    char *end;
+    int ret;
+
+    nkws = qemuParseKeywords(val, &kws, &vals, 1);
+    if (nkws < 0)
+        return -1;
+
+    for (i = 0; i < nkws; i++) {
+        if (vals[i] == NULL) {
+            if (i > 0 ||
+                virStrToLong_i(kws[i], &end, 10, &n) < 0 || *end != '\0')
+                goto syntax;
+            dom->vcpus = n;
+        } else {
+            if (virStrToLong_i(vals[i], &end, 10, &n) < 0 || *end != '\0')
+                goto syntax;
+            if (STREQ(kws[i], "sockets"))
+                sockets = n;
+            else if (STREQ(kws[i], "cores"))
+                cores = n;
+            else if (STREQ(kws[i], "threads"))
+                threads = n;
+            else if (STREQ(kws[i], "maxcpus"))
+                maxcpus = n;
+            else
+                goto syntax;
+        }
+    }
+
+    dom->maxvcpus = maxcpus ? maxcpus : dom->vcpus;
+
+    if (sockets && cores && threads) {
+        virCPUDefPtr cpu;
+
+        if (!(cpu = qemuInitGuestCPU(dom)))
+            goto error;
+        cpu->sockets = sockets;
+        cpu->cores = cores;
+        cpu->threads = threads;
+    } else if (sockets || cores || threads)
+        goto syntax;
+
+    ret = 0;
+
+cleanup:
+    for (i = 0; i < nkws; i++) {
+        VIR_FREE(kws[i]);
+        VIR_FREE(vals[i]);
+    }
+    VIR_FREE(kws);
+    VIR_FREE(vals);
+
+    return ret;
+
+syntax:
+    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                    _("cannot parse CPU topology '%s'"), val);
+error:
+    ret = -1;
+    goto cleanup;
+}
+
+
+/*
+ * Analyse the env and argv settings and reconstruct a
+ * virDomainDefPtr representing these settings as closely
+ * as is practical. This is not an exact science....
+ */
+virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
+                                     const char **progenv,
+                                     const char **progargv)
+{
+    virDomainDefPtr def;
+    int i;
+    int nographics = 0;
+    int fullscreen = 0;
+    char *path;
+    int nnics = 0;
+    const char **nics = NULL;
+    int video = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
+    int nvirtiodisk = 0;
+    qemuDomainCmdlineDefPtr cmd;
+
+    if (!progargv[0]) {
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("no emulator path found"));
+        return NULL;
+    }
+
+    if (VIR_ALLOC(def) < 0)
+        goto no_memory;
+
+    /* allocate the cmdlinedef up-front; if it's unused, we'll free it later */
+    if (VIR_ALLOC(cmd) < 0)
+        goto no_memory;
+
+    virUUIDGenerate(def->uuid);
+
+    def->id = -1;
+    def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024;
+    def->maxvcpus = 1;
+    def->vcpus = 1;
+    def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
+    def->features = (1 << VIR_DOMAIN_FEATURE_ACPI)
+        /*| (1 << VIR_DOMAIN_FEATURE_APIC)*/;
+    def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
+    def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
+    def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
+    def->virtType = VIR_DOMAIN_VIRT_QEMU;
+    if (!(def->emulator = strdup(progargv[0])))
+        goto no_memory;
+
+    if (strstr(def->emulator, "kvm")) {
+        def->virtType = VIR_DOMAIN_VIRT_KVM;
+        def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
+    }
+
+
+    if (strstr(def->emulator, "xenner")) {
+        def->virtType = VIR_DOMAIN_VIRT_KVM;
+        def->os.type = strdup("xen");
+    } else {
+        def->os.type = strdup("hvm");
+    }
+    if (!def->os.type)
+        goto no_memory;
+
+    if (STRPREFIX(def->emulator, "qemu"))
+        path = def->emulator;
+    else
+        path = strstr(def->emulator, "qemu");
+    if (path &&
+        STRPREFIX(path, "qemu-system-"))
+        def->os.arch = strdup(path + strlen("qemu-system-"));
+    else
+        def->os.arch = strdup("i686");
+    if (!def->os.arch)
+        goto no_memory;
+
+#define WANT_VALUE()                                                   \
+    const char *val = progargv[++i];                                   \
+    if (!val) {                                                        \
+        qemuReportError(VIR_ERR_INTERNAL_ERROR,                        \
+                        _("missing value for %s argument"), arg);      \
+        goto error;                                                    \
+    }
+
+    /* One initial loop to get list of NICs, so we
+     * can correlate them later */
+    for (i = 1 ; progargv[i] ; i++) {
+        const char *arg = progargv[i];
+        /* Make sure we have a single - for all options to
+           simplify next logic */
+        if (STRPREFIX(arg, "--"))
+            arg++;
+
+        if (STREQ(arg, "-net")) {
+            WANT_VALUE();
+            if (STRPREFIX(val, "nic")) {
+                if (VIR_REALLOC_N(nics, nnics+1) < 0)
+                    goto no_memory;
+                nics[nnics++] = val;
+            }
+        }
+    }
+
+    /* Now the real processing loop */
+    for (i = 1 ; progargv[i] ; i++) {
+        const char *arg = progargv[i];
+        /* Make sure we have a single - for all options to
+           simplify next logic */
+        if (STRPREFIX(arg, "--"))
+            arg++;
+
+        if (STREQ(arg, "-vnc")) {
+            virDomainGraphicsDefPtr vnc;
+            char *tmp;
+            WANT_VALUE();
+            if (VIR_ALLOC(vnc) < 0)
+                goto no_memory;
+            vnc->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
+
+            tmp = strchr(val, ':');
+            if (tmp) {
+                char *opts;
+                if (virStrToLong_i(tmp+1, &opts, 10, &vnc->data.vnc.port) < 0) {
+                    VIR_FREE(vnc);
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,             \
+                                    _("cannot parse VNC port '%s'"), tmp+1);
+                    goto error;
+                }
+                vnc->data.vnc.listenAddr = strndup(val, tmp-val);
+                if (!vnc->data.vnc.listenAddr) {
+                    VIR_FREE(vnc);
+                    goto no_memory;
+                }
+                vnc->data.vnc.port += 5900;
+                vnc->data.vnc.autoport = 0;
+            } else {
+                vnc->data.vnc.autoport = 1;
+            }
+
+            if (VIR_REALLOC_N(def->graphics, def->ngraphics+1) < 0) {
+                virDomainGraphicsDefFree(vnc);
+                goto no_memory;
+            }
+            def->graphics[def->ngraphics++] = vnc;
+        } else if (STREQ(arg, "-m")) {
+            int mem;
+            WANT_VALUE();
+            if (virStrToLong_i(val, NULL, 10, &mem) < 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, \
+                                _("cannot parse memory level '%s'"), val);
+                goto error;
+            }
+            def->mem.cur_balloon = def->mem.max_balloon = mem * 1024;
+        } else if (STREQ(arg, "-smp")) {
+            WANT_VALUE();
+            if (qemuParseCommandLineSmp(def, val) < 0)
+                goto error;
+        } else if (STREQ(arg, "-uuid")) {
+            WANT_VALUE();
+            if (virUUIDParse(val, def->uuid) < 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR, \
+                                _("cannot parse UUID '%s'"), val);
+                goto error;
+            }
+        } else if (STRPREFIX(arg, "-hd") ||
+                   STRPREFIX(arg, "-sd") ||
+                   STRPREFIX(arg, "-fd") ||
+                   STREQ(arg, "-cdrom")) {
+            WANT_VALUE();
+            virDomainDiskDefPtr disk;
+            if (VIR_ALLOC(disk) < 0)
+                goto no_memory;
+
+            if (STRPREFIX(val, "/dev/"))
+                disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
+            else if (STRPREFIX(val, "nbd:")) {
+                disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
+                val += strlen("nbd:");
+            } else if (STRPREFIX(val, "rbd:")) {
+                disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
+                val += strlen("rbd:");
+            } else if (STRPREFIX(val, "sheepdog:")) {
+                disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
+                val += strlen("sheepdog:");
+            } else
+                disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
+            if (STREQ(arg, "-cdrom")) {
+                disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
+                disk->dst = strdup("hdc");
+                disk->readonly = 1;
+            } else {
+                if (STRPREFIX(arg, "-fd")) {
+                    disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
+                    disk->bus = VIR_DOMAIN_DISK_BUS_FDC;
+                } else {
+                    disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+                    if (STRPREFIX(arg, "-hd"))
+                        disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
+                    else
+                        disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
+                }
+                disk->dst = strdup(arg + 1);
+            }
+            disk->src = strdup(val);
+
+            if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
+                char *host, *port;
+
+                switch (disk->protocol) {
+                case VIR_DOMAIN_DISK_PROTOCOL_NBD:
+                    host = disk->src;
+                    port = strchr(host, ':');
+                    if (!port) {
+                        def = NULL;
+                        qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                        _("cannot parse nbd filename '%s'"), disk->src);
+                        goto error;
+                    }
+                    *port++ = '\0';
+                    if (VIR_ALLOC(disk->hosts) < 0) {
+                        virReportOOMError();
+                        goto error;
+                    }
+                    disk->nhosts = 1;
+                    disk->hosts->name = host;
+                    disk->hosts->port = strdup(port);
+                    if (!disk->hosts->port) {
+                        virReportOOMError();
+                        goto error;
+                    }
+                    disk->src = NULL;
+                    break;
+                case VIR_DOMAIN_DISK_PROTOCOL_RBD:
+                    /* handled later since the hosts for all disks are in CEPH_ARGS */
+                    break;
+                case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
+                    /* disk->src must be [vdiname] or [host]:[port]:[vdiname] */
+                    port = strchr(disk->src, ':');
+                    if (port) {
+                        char *vdi;
+
+                        *port++ = '\0';
+                        vdi = strchr(port, ':');
+                        if (!vdi) {
+                            qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                            _("cannot parse sheepdog filename '%s'"), val);
+                            goto error;
+                        }
+                        *vdi++ = '\0';
+                        if (VIR_ALLOC(disk->hosts) < 0) {
+                            virReportOOMError();
+                            goto error;
+                        }
+                        disk->nhosts = 1;
+                        disk->hosts->name = disk->src;
+                        disk->hosts->port = strdup(port);
+                        if (!disk->hosts->port) {
+                            virReportOOMError();
+                            goto error;
+                        }
+                        disk->src = strdup(vdi);
+                        if (!disk->src) {
+                            virReportOOMError();
+                            goto error;
+                        }
+                    }
+                    break;
+                }
+            }
+
+            if (!(disk->src || disk->nhosts > 0) ||
+                !disk->dst) {
+                virDomainDiskDefFree(disk);
+                goto no_memory;
+            }
+
+            if (virDomainDiskDefAssignAddress(caps, disk) < 0)
+                goto error;
+
+            if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
+                virDomainDiskDefFree(disk);
+                goto no_memory;
+            }
+            def->disks[def->ndisks++] = disk;
+        } else if (STREQ(arg, "-no-acpi")) {
+            def->features &= ~(1 << VIR_DOMAIN_FEATURE_ACPI);
+        } else if (STREQ(arg, "-no-reboot")) {
+            def->onReboot = VIR_DOMAIN_LIFECYCLE_DESTROY;
+        } else if (STREQ(arg, "-no-kvm")) {
+            def->virtType = VIR_DOMAIN_VIRT_QEMU;
+        } else if (STREQ(arg, "-nographic")) {
+            nographics = 1;
+        } else if (STREQ(arg, "-full-screen")) {
+            fullscreen = 1;
+        } else if (STREQ(arg, "-localtime")) {
+            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
+        } else if (STREQ(arg, "-kernel")) {
+            WANT_VALUE();
+            if (!(def->os.kernel = strdup(val)))
+                goto no_memory;
+        } else if (STREQ(arg, "-initrd")) {
+            WANT_VALUE();
+            if (!(def->os.initrd = strdup(val)))
+                goto no_memory;
+        } else if (STREQ(arg, "-append")) {
+            WANT_VALUE();
+            if (!(def->os.cmdline = strdup(val)))
+                goto no_memory;
+        } else if (STREQ(arg, "-boot")) {
+            int n, b = 0;
+            WANT_VALUE();
+            for (n = 0 ; val[n] && b < VIR_DOMAIN_BOOT_LAST ; n++) {
+                if (val[n] == 'a')
+                    def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_FLOPPY;
+                else if (val[n] == 'c')
+                    def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_DISK;
+                else if (val[n] == 'd')
+                    def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_CDROM;
+                else if (val[n] == 'n')
+                    def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_NET;
+                else if (val[n] == ',')
+                    break;
+            }
+            def->os.nBootDevs = b;
+
+            if (strstr(val, "menu=on"))
+                def->os.bootmenu = 1;
+        } else if (STREQ(arg, "-name")) {
+            char *process;
+            WANT_VALUE();
+            process = strstr(val, ",process=");
+            if (process == NULL) {
+                if (!(def->name = strdup(val)))
+                    goto no_memory;
+            } else {
+                if (!(def->name = strndup(val, process - val)))
+                    goto no_memory;
+            }
+        } else if (STREQ(arg, "-M")) {
+            WANT_VALUE();
+            if (!(def->os.machine = strdup(val)))
+                goto no_memory;
+        } else if (STREQ(arg, "-serial")) {
+            WANT_VALUE();
+            if (STRNEQ(val, "none")) {
+                virDomainChrDefPtr chr;
+                if (!(chr = qemuParseCommandLineChr(val)))
+                    goto error;
+                if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) {
+                    virDomainChrDefFree(chr);
+                    goto no_memory;
+                }
+                chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
+                chr->target.port = def->nserials;
+                def->serials[def->nserials++] = chr;
+            }
+        } else if (STREQ(arg, "-parallel")) {
+            WANT_VALUE();
+            if (STRNEQ(val, "none")) {
+                virDomainChrDefPtr chr;
+                if (!(chr = qemuParseCommandLineChr(val)))
+                    goto error;
+                if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) {
+                    virDomainChrDefFree(chr);
+                    goto no_memory;
+                }
+                chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
+                chr->target.port = def->nparallels;
+                def->parallels[def->nparallels++] = chr;
+            }
+        } else if (STREQ(arg, "-usbdevice")) {
+            WANT_VALUE();
+            if (STREQ(val, "tablet") ||
+                STREQ(val, "mouse")) {
+                virDomainInputDefPtr input;
+                if (VIR_ALLOC(input) < 0)
+                    goto no_memory;
+                input->bus = VIR_DOMAIN_INPUT_BUS_USB;
+                if (STREQ(val, "tablet"))
+                    input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
+                else
+                    input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
+                if (VIR_REALLOC_N(def->inputs, def->ninputs+1) < 0) {
+                    virDomainInputDefFree(input);
+                    goto no_memory;
+                }
+                def->inputs[def->ninputs++] = input;
+            } else if (STRPREFIX(val, "disk:")) {
+                virDomainDiskDefPtr disk;
+                if (VIR_ALLOC(disk) < 0)
+                    goto no_memory;
+                disk->src = strdup(val + strlen("disk:"));
+                if (!disk->src) {
+                    virDomainDiskDefFree(disk);
+                    goto no_memory;
+                }
+                if (STRPREFIX(disk->src, "/dev/"))
+                    disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
+                else
+                    disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
+                disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+                disk->bus = VIR_DOMAIN_DISK_BUS_USB;
+                if (!(disk->dst = strdup("sda"))) {
+                    virDomainDiskDefFree(disk);
+                    goto no_memory;
+                }
+                if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
+                    virDomainDiskDefFree(disk);
+                    goto no_memory;
+                }
+                def->disks[def->ndisks++] = disk;
+            } else {
+                virDomainHostdevDefPtr hostdev;
+                if (!(hostdev = qemuParseCommandLineUSB(val)))
+                    goto error;
+                if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
+                    virDomainHostdevDefFree(hostdev);
+                    goto no_memory;
+                }
+                def->hostdevs[def->nhostdevs++] = hostdev;
+            }
+        } else if (STREQ(arg, "-net")) {
+            WANT_VALUE();
+            if (!STRPREFIX(val, "nic") && STRNEQ(val, "none")) {
+                virDomainNetDefPtr net;
+                if (!(net = qemuParseCommandLineNet(caps, val, nnics, nics)))
+                    goto error;
+                if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0) {
+                    virDomainNetDefFree(net);
+                    goto no_memory;
+                }
+                def->nets[def->nnets++] = net;
+            }
+        } else if (STREQ(arg, "-drive")) {
+            virDomainDiskDefPtr disk;
+            WANT_VALUE();
+            if (!(disk = qemuParseCommandLineDisk(caps, val, nvirtiodisk)))
+                goto error;
+            if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
+                virDomainDiskDefFree(disk);
+                goto no_memory;
+            }
+            def->disks[def->ndisks++] = disk;
+
+            if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
+                nvirtiodisk++;
+        } else if (STREQ(arg, "-pcidevice")) {
+            virDomainHostdevDefPtr hostdev;
+            WANT_VALUE();
+            if (!(hostdev = qemuParseCommandLinePCI(val)))
+                goto error;
+            if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
+                virDomainHostdevDefFree(hostdev);
+                goto no_memory;
+            }
+            def->hostdevs[def->nhostdevs++] = hostdev;
+        } else if (STREQ(arg, "-soundhw")) {
+            const char *start;
+            WANT_VALUE();
+            start = val;
+            while (start) {
+                const char *tmp = strchr(start, ',');
+                int type = -1;
+                if (STRPREFIX(start, "pcspk")) {
+                    type = VIR_DOMAIN_SOUND_MODEL_PCSPK;
+                } else if (STRPREFIX(start, "sb16")) {
+                    type = VIR_DOMAIN_SOUND_MODEL_SB16;
+                } else if (STRPREFIX(start, "es1370")) {
+                    type = VIR_DOMAIN_SOUND_MODEL_ES1370;
+                } else if (STRPREFIX(start, "ac97")) {
+                    type = VIR_DOMAIN_SOUND_MODEL_AC97;
+                }
+
+                if (type != -1) {
+                    virDomainSoundDefPtr snd;
+                    if (VIR_ALLOC(snd) < 0)
+                        goto no_memory;
+                    snd->model = type;
+                    if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) {
+                        VIR_FREE(snd);
+                        goto no_memory;
+                    }
+                    def->sounds[def->nsounds++] = snd;
+                }
+
+                start = tmp ? tmp + 1 : NULL;
+            }
+        } else if (STREQ(arg, "-watchdog")) {
+            WANT_VALUE();
+            int model = virDomainWatchdogModelTypeFromString (val);
+
+            if (model != -1) {
+                virDomainWatchdogDefPtr wd;
+                if (VIR_ALLOC(wd) < 0)
+                    goto no_memory;
+                wd->model = model;
+                wd->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
+                def->watchdog = wd;
+            }
+        } else if (STREQ(arg, "-watchdog-action") && def->watchdog) {
+            WANT_VALUE();
+            int action = virDomainWatchdogActionTypeFromString (val);
+
+            if (action != -1)
+                def->watchdog->action = action;
+        } else if (STREQ(arg, "-bootloader")) {
+            WANT_VALUE();
+            def->os.bootloader = strdup(val);
+            if (!def->os.bootloader)
+                goto no_memory;
+        } else if (STREQ(arg, "-vmwarevga")) {
+            video = VIR_DOMAIN_VIDEO_TYPE_VMVGA;
+        } else if (STREQ(arg, "-std-vga")) {
+            video = VIR_DOMAIN_VIDEO_TYPE_VGA;
+        } else if (STREQ(arg, "-vga")) {
+            WANT_VALUE();
+            if (STRNEQ(val, "none")) {
+                video = qemuVideoTypeFromString(val);
+                if (video < 0) {
+                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                    _("unknown video adapter type '%s'"), val);
+                    goto error;
+                }
+            }
+        } else if (STREQ(arg, "-cpu")) {
+            WANT_VALUE();
+            if (qemuParseCommandLineCPU(def, val) < 0)
+                goto error;
+        } else if (STREQ(arg, "-domid")) {
+            WANT_VALUE();
+            /* ignore, generted on the fly */
+        } else if (STREQ(arg, "-usb")) {
+            /* ignore, always added by libvirt */
+        } else if (STREQ(arg, "-pidfile")) {
+            WANT_VALUE();
+            /* ignore, used by libvirt as needed */
+        } else if (STREQ(arg, "-incoming")) {
+            WANT_VALUE();
+            /* ignore, used via restore/migrate APIs */
+        } else if (STREQ(arg, "-monitor")) {
+            WANT_VALUE();
+            /* ignore, used internally by libvirt */
+        } else if (STREQ(arg, "-S")) {
+            /* ignore, always added by libvirt */
+        } else {
+            /* something we can't yet parse.  Add it to the qemu namespace
+             * cmdline/environment advanced options and hope for the best
+             */
+            VIR_WARN("unknown QEMU argument '%s', adding to the qemu namespace",
+                     arg);
+            if (VIR_REALLOC_N(cmd->args, cmd->num_args+1) < 0)
+                goto no_memory;
+            cmd->args[cmd->num_args] = strdup(arg);
+            if (cmd->args[cmd->num_args] == NULL)
+                goto no_memory;
+            cmd->num_args++;
+        }
+    }
+
+#undef WANT_VALUE
+    if (def->ndisks > 0) {
+        const char *ceph_args = qemuFindEnv(progenv, "CEPH_ARGS");
+        if (ceph_args) {
+            char *hosts, *port, *saveptr, *token;
+            virDomainDiskDefPtr first_rbd_disk = NULL;
+            for (i = 0 ; i < def->ndisks ; i++) {
+                virDomainDiskDefPtr disk = def->disks[i];
+                if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+                    disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
+                    first_rbd_disk = disk;
+                    break;
+                }
+            }
+
+            if (!first_rbd_disk) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("CEPH_ARGS was set without an rbd disk"));
+                goto error;
+            }
+
+            /* CEPH_ARGS should be: -m host1[:port1][,host2[:port2]]... */
+            if (!STRPREFIX(ceph_args, "-m ")) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("could not parse CEPH_ARGS '%s'"), ceph_args);
+                goto error;
+            }
+            hosts = strdup(strchr(ceph_args, ' ') + 1);
+            if (!hosts)
+                goto no_memory;
+            first_rbd_disk->nhosts = 0;
+            token = strtok_r(hosts, ",", &saveptr);
+            while (token != NULL) {
+                if (VIR_REALLOC_N(first_rbd_disk->hosts, first_rbd_disk->nhosts + 1) < 0) {
+                    VIR_FREE(hosts);
+                    goto no_memory;
+                }
+                port = strchr(token, ':');
+                if (port) {
+                    *port++ = '\0';
+                    port = strdup(port);
+                    if (!port) {
+                        VIR_FREE(hosts);
+                        goto no_memory;
+                    }
+                }
+                first_rbd_disk->hosts[first_rbd_disk->nhosts].port = port;
+                first_rbd_disk->hosts[first_rbd_disk->nhosts].name = strdup(token);
+                if (!first_rbd_disk->hosts[first_rbd_disk->nhosts].name) {
+                    VIR_FREE(hosts);
+                    goto no_memory;
+                }
+                first_rbd_disk->nhosts++;
+                token = strtok_r(NULL, ",", &saveptr);
+            }
+            VIR_FREE(hosts);
+
+            if (first_rbd_disk->nhosts == 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("found no rbd hosts in CEPH_ARGS '%s'"), ceph_args);
+                goto error;
+            }
+        }
+    }
+
+    if (!nographics && def->ngraphics == 0) {
+        virDomainGraphicsDefPtr sdl;
+        const char *display = qemuFindEnv(progenv, "DISPLAY");
+        const char *xauth = qemuFindEnv(progenv, "XAUTHORITY");
+        if (VIR_ALLOC(sdl) < 0)
+            goto no_memory;
+        sdl->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
+        sdl->data.sdl.fullscreen = fullscreen;
+        if (display &&
+            !(sdl->data.sdl.display = strdup(display))) {
+            VIR_FREE(sdl);
+            goto no_memory;
+        }
+        if (xauth &&
+            !(sdl->data.sdl.xauth = strdup(xauth))) {
+            VIR_FREE(sdl);
+            goto no_memory;
+        }
+
+        if (VIR_REALLOC_N(def->graphics, def->ngraphics+1) < 0) {
+            virDomainGraphicsDefFree(sdl);
+            goto no_memory;
+        }
+        def->graphics[def->ngraphics++] = sdl;
+    }
+
+    if (def->ngraphics) {
+        virDomainVideoDefPtr vid;
+        if (VIR_ALLOC(vid) < 0)
+            goto no_memory;
+        if (def->virtType == VIR_DOMAIN_VIRT_XEN)
+            vid->type = VIR_DOMAIN_VIDEO_TYPE_XEN;
+        else
+            vid->type = video;
+        vid->vram = virDomainVideoDefaultRAM(def, vid->type);
+        vid->heads = 1;
+
+        if (VIR_REALLOC_N(def->videos, def->nvideos+1) < 0) {
+            virDomainVideoDefFree(vid);
+            goto no_memory;
+        }
+        def->videos[def->nvideos++] = vid;
+    }
+
+    /*
+     * having a balloon is the default, define one with type="none" to avoid it
+     */
+    if (!def->memballoon) {
+        virDomainMemballoonDefPtr memballoon;
+        if (VIR_ALLOC(memballoon) < 0)
+            goto no_memory;
+        memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
+
+        def->memballoon = memballoon;
+    }
+
+    VIR_FREE(nics);
+
+    if (!def->name) {
+        if (!(def->name = strdup("unnamed")))
+            goto no_memory;
+    }
+
+    if (virDomainDefAddImplicitControllers(def) < 0)
+        goto error;
+
+    if (cmd->num_args || cmd->num_env) {
+        def->ns = caps->ns;
+        def->namespaceData = cmd;
+    }
+    else
+        VIR_FREE(cmd);
+
+    return def;
+
+no_memory:
+    virReportOOMError();
+error:
+    VIR_FREE(cmd);
+    virDomainDefFree(def);
+    VIR_FREE(nics);
+    return NULL;
+}
+
+
+virDomainDefPtr qemuParseCommandLineString(virCapsPtr caps,
+                                           const char *args)
+{
+    const char **progenv = NULL;
+    const char **progargv = NULL;
+    virDomainDefPtr def = NULL;
+    int i;
+
+    if (qemuStringToArgvEnv(args, &progenv, &progargv) < 0)
+        goto cleanup;
+
+    def = qemuParseCommandLine(caps, progenv, progargv);
+
+cleanup:
+    for (i = 0 ; progargv && progargv[i] ; i++)
+        VIR_FREE(progargv[i]);
+    VIR_FREE(progargv);
+
+    for (i = 0 ; progenv && progenv[i] ; i++)
+        VIR_FREE(progenv[i]);
+    VIR_FREE(progenv);
+
+    return def;
+}
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
new file mode 100644
index 0000000..da35d3b
--- /dev/null
+++ b/src/qemu/qemu_command.h
@@ -0,0 +1,165 @@
+/*
+ * qemu_command.h: QEMU command generation
+ *
+ * Copyright (C) 2006-2007, 2009-2010 Red Hat, Inc.
+ * Copyright (C) 2006 Daniel P. Berrange
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ *
+ * Author: Daniel P. Berrange <berrange redhat com>
+ */
+
+#ifndef __QEMU_COMMAND_H__
+# define __QEMU_COMMAND_H__
+
+#include "domain_conf.h"
+#include "command.h"
+#include "capabilities.h"
+#include "qemu_conf.h"
+
+/* Config type for XML import/export conversions */
+# define QEMU_CONFIG_FORMAT_ARGV "qemu-argv"
+
+# define QEMU_DRIVE_HOST_PREFIX "drive-"
+# define QEMU_VIRTIO_SERIAL_PREFIX "virtio-serial"
+# define QEMU_FSDEV_HOST_PREFIX "fsdev-"
+
+virCommandPtr qemuBuildCommandLine(virConnectPtr conn,
+                                   struct qemud_driver *driver,
+                                   virDomainDefPtr def,
+                                   virDomainChrDefPtr monitor_chr,
+                                   bool monitor_json,
+                                   unsigned long long qemuCmdFlags,
+                                   const char *migrateFrom,
+                                   virDomainSnapshotObjPtr current_snapshot,
+                                   enum virVMOperationType vmop)
+    ATTRIBUTE_NONNULL(1);
+
+/* With vlan == -1, use netdev syntax, else old hostnet */
+char * qemuBuildHostNetStr(virDomainNetDefPtr net,
+                           char type_sep,
+                           int vlan,
+                           const char *tapfd,
+                           const char *vhostfd);
+
+/* Legacy, pre device support */
+char * qemuBuildNicStr(virDomainNetDefPtr net,
+                       const char *prefix,
+                       int vlan);
+
+/* Current, best practice */
+char * qemuBuildNicDevStr(virDomainNetDefPtr net,
+                          int vlan);
+
+char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
+                               unsigned long long qemuCmdFlags);
+
+/* Both legacy & current support */
+char *qemuBuildDriveStr(virDomainDiskDefPtr disk,
+                        int bootable,
+                        unsigned long long qemuCmdFlags);
+char *qemuBuildFSStr(virDomainFSDefPtr fs,
+                     unsigned long long qemuCmdFlags);
+
+/* Current, best practice */
+char * qemuBuildDriveDevStr(virDomainDiskDefPtr disk);
+char * qemuBuildFSDevStr(virDomainFSDefPtr fs);
+/* Current, best practice */
+char * qemuBuildControllerDevStr(virDomainControllerDefPtr def);
+
+char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev);
+
+char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev);
+
+char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev);
+
+char * qemuBuildSoundDevStr(virDomainSoundDefPtr sound);
+
+/* Legacy, pre device support */
+char * qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev);
+/* Current, best practice */
+char * qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev,
+                                 const char *configfd);
+
+int qemuOpenPCIConfig(virDomainHostdevDefPtr dev);
+
+/* Current, best practice */
+char * qemuBuildChrChardevStr(virDomainChrDefPtr dev);
+/* Legacy, pre device support */
+char * qemuBuildChrArgStr(virDomainChrDefPtr dev, const char *prefix);
+
+char * qemuBuildVirtioSerialPortDevStr(virDomainChrDefPtr dev);
+
+/* Legacy, pre device support */
+char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev);
+/* Current, best practice */
+char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev);
+
+
+
+int qemuNetworkIfaceConnect(virConnectPtr conn,
+                            struct qemud_driver *driver,
+                            virDomainNetDefPtr net,
+                            unsigned long long qemCmdFlags)
+    ATTRIBUTE_NONNULL(1);
+
+int qemuOpenVhostNet(virDomainNetDefPtr net,
+                     unsigned long long qemuCmdFlags);
+
+int qemuPhysIfaceConnect(virConnectPtr conn,
+                         struct qemud_driver *driver,
+                         virDomainNetDefPtr net,
+                         unsigned long long qemuCmdFlags,
+                         const unsigned char *vmuuid,
+                         enum virVMOperationType vmop);
+
+int qemudCanonicalizeMachine(struct qemud_driver *driver,
+                             virDomainDefPtr def);
+
+virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
+                                     const char **progenv,
+                                     const char **progargv);
+virDomainDefPtr qemuParseCommandLineString(virCapsPtr caps,
+                                           const char *args);
+
+qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def);
+int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
+                                    int slot);
+int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev);
+int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev);
+int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
+                                   virDomainDeviceInfoPtr dev);
+int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
+                                    virDomainDeviceInfoPtr dev);
+
+void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs);
+int  qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs);
+
+int qemuDomainNetVLAN(virDomainNetDefPtr def);
+int qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx);
+int qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, unsigned long long qemuCmdFlags);
+int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr net, int idx);
+int qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller);
+
+int
+qemuParseKeywords(const char *str,
+                  char ***retkeywords,
+                  char ***retvalues,
+                  int allowEmptyValue);
+
+
+#endif /* __QEMU_COMMAND_H__*/
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 0c9c676..e600a5b 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -61,43 +61,6 @@
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
-VIR_ENUM_DECL(virDomainDiskQEMUBus)
-VIR_ENUM_IMPL(virDomainDiskQEMUBus, VIR_DOMAIN_DISK_BUS_LAST,
-              "ide",
-              "floppy",
-              "scsi",
-              "virtio",
-              "xen",
-              "usb",
-              "uml",
-              "sata")
-
-
-VIR_ENUM_DECL(qemuDiskCacheV1)
-VIR_ENUM_DECL(qemuDiskCacheV2)
-
-VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST,
-              "default",
-              "off",
-              "off", /* writethrough not supported, so for safety, disable */
-              "on"); /* Old 'on' was equivalent to 'writeback' */
-
-VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST,
-              "default",
-              "none",
-              "writethrough",
-              "writeback");
-
-VIR_ENUM_DECL(qemuVideo)
-
-VIR_ENUM_IMPL(qemuVideo, VIR_DOMAIN_VIDEO_TYPE_LAST,
-              "std",
-              "cirrus",
-              "vmware",
-              "", /* no arg needed for xen */
-              "", /* don't support vbox */
-              "qxl");
-
 int qemudLoadDriverConfig(struct qemud_driver *driver,
                           const char *filename) {
     virConfPtr conf;
@@ -452,5714 +415,3 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
 }
 
 
-static void
-uname_normalize (struct utsname *ut)
-{
-    uname(ut);
-
-    /* Map i386, i486, i586 to i686.  */
-    if (ut->machine[0] == 'i' &&
-        ut->machine[1] != '\0' &&
-        ut->machine[2] == '8' &&
-        ut->machine[3] == '6' &&
-        ut->machine[4] == '\0')
-        ut->machine[1] = '6';
-}
-
-
-/**
- * qemudPhysIfaceConnect:
- * @conn: pointer to virConnect object
- * @driver: pointer to the qemud_driver
- * @net: pointer to he VM's interface description with direct device type
- * @qemuCmdFlags: flags for qemu
- * @vmuuid: The UUID of the VM (needed by 802.1Qbh)
- *
- * Returns a filedescriptor on success or -1 in case of error.
- */
-int
-qemudPhysIfaceConnect(virConnectPtr conn,
-                      struct qemud_driver *driver,
-                      virDomainNetDefPtr net,
-                      unsigned long long qemuCmdFlags,
-                      const unsigned char *vmuuid,
-                      enum virVMOperationType vmop)
-{
-    int rc;
-#if WITH_MACVTAP
-    char *res_ifname = NULL;
-    int vnet_hdr = 0;
-    int err;
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR &&
-        net->model && STREQ(net->model, "virtio"))
-        vnet_hdr = 1;
-
-    rc = openMacvtapTap(net->ifname, net->mac, net->data.direct.linkdev,
-                        net->data.direct.mode, vnet_hdr, vmuuid,
-                        &net->data.direct.virtPortProfile, &res_ifname,
-                        vmop);
-    if (rc >= 0) {
-        VIR_FREE(net->ifname);
-        net->ifname = res_ifname;
-    }
-
-    if (rc >=0 && driver->macFilter) {
-        if ((err = networkAllowMacOnPort(driver, net->ifname, net->mac))) {
-            virReportSystemError(err,
-                 _("failed to add ebtables rule to allow MAC address on  '%s'"),
-                                 net->ifname);
-        }
-    }
-
-    if (rc >= 0) {
-        if ((net->filter) && (net->ifname)) {
-            err = virDomainConfNWFilterInstantiate(conn, net);
-            if (err) {
-                VIR_FORCE_CLOSE(rc);
-                delMacvtap(net->ifname, net->mac, net->data.direct.linkdev,
-                           &net->data.direct.virtPortProfile);
-                VIR_FREE(net->ifname);
-            }
-        }
-    }
-#else
-    (void)conn;
-    (void)net;
-    (void)qemuCmdFlags;
-    (void)driver;
-    (void)vmuuid;
-    (void)vmop;
-    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                    "%s", _("No support for macvtap device"));
-    rc = -1;
-#endif
-    return rc;
-}
-
-
-int
-qemudNetworkIfaceConnect(virConnectPtr conn,
-                         struct qemud_driver *driver,
-                         virDomainNetDefPtr net,
-                         unsigned long long qemuCmdFlags)
-{
-    char *brname = NULL;
-    int err;
-    int tapfd = -1;
-    int vnet_hdr = 0;
-    int template_ifname = 0;
-    unsigned char tapmac[VIR_MAC_BUFLEN];
-
-    if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
-        int active, fail = 0;
-        virErrorPtr errobj;
-        virNetworkPtr network = virNetworkLookupByName(conn,
-                                                       net->data.network.name);
-        if (!network)
-            return -1;
-
-        active = virNetworkIsActive(network);
-        if (active != 1) {
-            fail = 1;
-
-            if (active == 0)
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("Network '%s' is not active."),
-                                net->data.network.name);
-        }
-
-        if (!fail) {
-            brname = virNetworkGetBridgeName(network);
-            if (brname == NULL)
-                fail = 1;
-        }
-
-        /* Make sure any above failure is preserved */
-        errobj = virSaveLastError();
-        virNetworkFree(network);
-        virSetError(errobj);
-        virFreeError(errobj);
-
-        if (fail)
-            return -1;
-
-    } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
-        if (!(brname = strdup(net->data.bridge.brname))) {
-            virReportOOMError();
-            return -1;
-        }
-    } else {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("Network type %d is not supported"), net->type);
-        return -1;
-    }
-
-    if (!driver->brctl && (err = brInit(&driver->brctl))) {
-        virReportSystemError(err, "%s",
-                             _("cannot initialize bridge support"));
-        goto cleanup;
-    }
-
-    if (!net->ifname ||
-        STRPREFIX(net->ifname, "vnet") ||
-        strchr(net->ifname, '%')) {
-        VIR_FREE(net->ifname);
-        if (!(net->ifname = strdup("vnet%d"))) {
-            virReportOOMError();
-            goto cleanup;
-        }
-        /* avoid exposing vnet%d in dumpxml or error outputs */
-        template_ifname = 1;
-    }
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HDR &&
-        net->model && STREQ(net->model, "virtio"))
-        vnet_hdr = 1;
-
-    memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
-    tapmac[0] = 0xFE; /* Discourage bridge from using TAP dev MAC */
-    if ((err = brAddTap(driver->brctl,
-                        brname,
-                        &net->ifname,
-                        tapmac,
-                        vnet_hdr,
-                        &tapfd))) {
-        if (err == ENOTSUP) {
-            /* In this particular case, give a better diagnostic. */
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("Failed to add tap interface to bridge. "
-                              "%s is not a bridge device"), brname);
-        } else if (err == ENOENT) {
-            /* When the tun drive is missing, give a better message. */
-            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("Failed to add tap interface to bridge. "
-                              "Your kernel is missing the 'tun' module or "
-                              "CONFIG_TUN, or you need to add the "
-                              "/dev/net/tun device node."));
-        } else if (template_ifname) {
-            virReportSystemError(err,
-                                 _("Failed to add tap interface to bridge '%s'"),
-                                 brname);
-        } else {
-            virReportSystemError(err,
-                                 _("Failed to add tap interface '%s' to bridge '%s'"),
-                                 net->ifname, brname);
-        }
-        if (template_ifname)
-            VIR_FREE(net->ifname);
-        tapfd = -1;
-    }
-
-    if (driver->macFilter) {
-        if ((err = networkAllowMacOnPort(driver, net->ifname, net->mac))) {
-            virReportSystemError(err,
-                 _("failed to add ebtables rule to allow MAC address on  '%s'"),
-                                 net->ifname);
-        }
-    }
-
-    if (tapfd >= 0) {
-        if ((net->filter) && (net->ifname)) {
-            err = virDomainConfNWFilterInstantiate(conn, net);
-            if (err)
-                VIR_FORCE_CLOSE(tapfd);
-        }
-    }
-
-cleanup:
-    VIR_FREE(brname);
-
-    return tapfd;
-}
-
-
-int
-qemudOpenVhostNet(virDomainNetDefPtr net,
-                  unsigned long long qemuCmdFlags)
-{
-
-    /* If qemu supports vhost-net mode (including the -netdev command
-     * option), the nic model is virtio, and we can open
-     * /dev/vhost_net, assume that vhost-net mode is available and
-     * return the fd to /dev/vhost_net. Otherwise, return -1.
-     */
-
-    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_VNET_HOST &&
-          qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV &&
-          qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE &&
-          net->model && STREQ(net->model, "virtio")))
-        return -1;
-
-    return open("/dev/vhost-net", O_RDWR, 0);
-}
-
-
-static int qemuDomainDeviceAliasIndex(virDomainDeviceInfoPtr info,
-                                      const char *prefix)
-{
-    int idx;
-
-    if (!info->alias)
-        return -1;
-    if (!STRPREFIX(info->alias, prefix))
-        return -1;
-
-    if (virStrToLong_i(info->alias + strlen(prefix), NULL, 10, &idx) < 0)
-        return -1;
-
-    return idx;
-}
-
-
-int qemuDomainNetVLAN(virDomainNetDefPtr def)
-{
-    return qemuDomainDeviceAliasIndex(&def->info, "net");
-}
-
-
-/* Names used before -drive existed */
-static int qemuAssignDeviceDiskAliasLegacy(virDomainDiskDefPtr disk)
-{
-    char *devname;
-
-    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
-        STREQ(disk->dst, "hdc"))
-        devname = strdup("cdrom");
-    else
-        devname = strdup(disk->dst);
-
-    if (!devname) {
-        virReportOOMError();
-        return -1;
-    }
-
-    disk->info.alias = devname;
-    return 0;
-}
-
-
-char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
-                               unsigned long long qemudCmdFlags)
-{
-    char *ret;
-
-    if (qemudCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-        if (virAsprintf(&ret, "%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias) < 0) {
-            virReportOOMError();
-            return NULL;
-        }
-    } else {
-        if (!(ret = strdup(disk->info.alias))) {
-            virReportOOMError();
-            return NULL;
-        }
-    }
-    return ret;
-}
-
-
-/* Names used before -drive supported the id= option */
-static int qemuAssignDeviceDiskAliasFixed(virDomainDiskDefPtr disk)
-{
-    int busid, devid;
-    int ret;
-    char *devname;
-
-    if (virDiskNameToBusDeviceIndex(disk, &busid, &devid) < 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("cannot convert disk '%s' to bus/device index"),
-                        disk->dst);
-        return -1;
-    }
-
-    switch (disk->bus) {
-    case VIR_DOMAIN_DISK_BUS_IDE:
-        if (disk->device== VIR_DOMAIN_DISK_DEVICE_DISK)
-            ret = virAsprintf(&devname, "ide%d-hd%d", busid, devid);
-        else
-            ret = virAsprintf(&devname, "ide%d-cd%d", busid, devid);
-        break;
-    case VIR_DOMAIN_DISK_BUS_SCSI:
-        if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK)
-            ret = virAsprintf(&devname, "scsi%d-hd%d", busid, devid);
-        else
-            ret = virAsprintf(&devname, "scsi%d-cd%d", busid, devid);
-        break;
-    case VIR_DOMAIN_DISK_BUS_FDC:
-        ret = virAsprintf(&devname, "floppy%d", devid);
-        break;
-    case VIR_DOMAIN_DISK_BUS_VIRTIO:
-        ret = virAsprintf(&devname, "virtio%d", devid);
-        break;
-    case VIR_DOMAIN_DISK_BUS_XEN:
-        ret = virAsprintf(&devname, "xenblk%d", devid);
-        break;
-    default:
-        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                        _("Unsupported disk name mapping for bus '%s'"),
-                        virDomainDiskBusTypeToString(disk->bus));
-        return -1;
-    }
-
-    if (ret == -1) {
-        virReportOOMError();
-        return -1;
-    }
-
-    disk->info.alias = devname;
-
-    return 0;
-}
-
-
-/* Our custom -drive naming scheme used with id= */
-static int qemuAssignDeviceDiskAliasCustom(virDomainDiskDefPtr disk)
-{
-    const char *prefix = virDomainDiskBusTypeToString(disk->bus);
-    if (disk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
-        if (virAsprintf(&disk->info.alias, "%s%d-%d-%d", prefix,
-                        disk->info.addr.drive.controller,
-                        disk->info.addr.drive.bus,
-                        disk->info.addr.drive.unit) < 0)
-            goto no_memory;
-    } else {
-        int idx = virDiskNameToIndex(disk->dst);
-        if (virAsprintf(&disk->info.alias, "%s-disk%d", prefix, idx) < 0)
-            goto no_memory;
-    }
-
-    return 0;
-
-no_memory:
-    virReportOOMError();
-    return -1;
-}
-
-
-int
-qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, unsigned long long qemuCmdFlags)
-{
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
-            return qemuAssignDeviceDiskAliasCustom(def);
-        else
-            return qemuAssignDeviceDiskAliasFixed(def);
-    } else {
-        return qemuAssignDeviceDiskAliasLegacy(def);
-    }
-}
-
-
-int
-qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx)
-{
-    if (idx == -1) {
-        int i;
-        idx = 0;
-        for (i = 0 ; i < def->nnets ; i++) {
-            int thisidx;
-            if ((thisidx = qemuDomainDeviceAliasIndex(&def->nets[i]->info, "net")) < 0) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                _("Unable to determine device index for network device"));
-                return -1;
-            }
-            if (thisidx >= idx)
-                idx = thisidx + 1;
-        }
-    }
-
-    if (virAsprintf(&net->info.alias, "net%d", idx) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    return 0;
-}
-
-
-int
-qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr hostdev, int idx)
-{
-    if (idx == -1) {
-        int i;
-        idx = 0;
-        for (i = 0 ; i < def->nhostdevs ; i++) {
-            int thisidx;
-            if ((thisidx = qemuDomainDeviceAliasIndex(&def->hostdevs[i]->info, "hostdev")) < 0) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                _("Unable to determine device index for hostdevwork device"));
-                return -1;
-            }
-            if (thisidx >= idx)
-                idx = thisidx + 1;
-        }
-    }
-
-    if (virAsprintf(&hostdev->info.alias, "hostdev%d", idx) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    return 0;
-}
-
-
-int
-qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
-{
-    const char *prefix = virDomainControllerTypeToString(controller->type);
-
-    if (virAsprintf(&controller->info.alias,  "%s%d", prefix,
-                    controller->idx) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    return 0;
-}
-
-
-static int
-qemuAssignDeviceAliases(virDomainDefPtr def, unsigned long long qemuCmdFlags)
-{
-    int i;
-
-    for (i = 0; i < def->ndisks ; i++) {
-        if (qemuAssignDeviceDiskAlias(def->disks[i], qemuCmdFlags) < 0)
-            return -1;
-    }
-    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NET_NAME) ||
-        (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-        for (i = 0; i < def->nnets ; i++) {
-            if (qemuAssignDeviceNetAlias(def, def->nets[i], i) < 0)
-                return -1;
-        }
-    }
-
-    if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
-        return 0;
-
-    for (i = 0; i < def->nfss ; i++) {
-        if (virAsprintf(&def->fss[i]->info.alias, "fs%d", i) < 0)
-            goto no_memory;
-    }
-    for (i = 0; i < def->nsounds ; i++) {
-        if (virAsprintf(&def->sounds[i]->info.alias, "sound%d", i) < 0)
-            goto no_memory;
-    }
-    for (i = 0; i < def->nhostdevs ; i++) {
-        if (qemuAssignDeviceHostdevAlias(def, def->hostdevs[i], i) < 0)
-            return -1;
-    }
-    for (i = 0; i < def->nvideos ; i++) {
-        if (virAsprintf(&def->videos[i]->info.alias, "video%d", i) < 0)
-            goto no_memory;
-    }
-    for (i = 0; i < def->ncontrollers ; i++) {
-        if (qemuAssignDeviceControllerAlias(def->controllers[i]) < 0)
-            return -1;
-    }
-    for (i = 0; i < def->ninputs ; i++) {
-        if (virAsprintf(&def->inputs[i]->info.alias, "input%d", i) < 0)
-            goto no_memory;
-    }
-    for (i = 0; i < def->nparallels ; i++) {
-        if (virAsprintf(&def->parallels[i]->info.alias, "parallel%d", i) < 0)
-            goto no_memory;
-    }
-    for (i = 0; i < def->nserials ; i++) {
-        if (virAsprintf(&def->serials[i]->info.alias, "serial%d", i) < 0)
-            goto no_memory;
-    }
-    for (i = 0; i < def->nchannels ; i++) {
-        if (virAsprintf(&def->channels[i]->info.alias, "channel%d", i) < 0)
-            goto no_memory;
-    }
-    if (def->console) {
-        if (virAsprintf(&def->console->info.alias, "console%d", i) < 0)
-            goto no_memory;
-    }
-    if (def->watchdog) {
-        if (virAsprintf(&def->watchdog->info.alias, "watchdog%d", 0) < 0)
-            goto no_memory;
-    }
-    if (def->memballoon) {
-        if (virAsprintf(&def->memballoon->info.alias, "balloon%d", 0) < 0)
-            goto no_memory;
-    }
-
-    return 0;
-
-    no_memory:
-    virReportOOMError();
-    return -1;
-}
-
-
-#define QEMU_PCI_ADDRESS_LAST_SLOT 31
-struct _qemuDomainPCIAddressSet {
-    virHashTablePtr used;
-    int nextslot;
-};
-
-
-static char *qemuPCIAddressAsString(virDomainDeviceInfoPtr dev)
-{
-    char *addr;
-
-    if (dev->addr.pci.domain != 0 ||
-        dev->addr.pci.bus != 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("Only PCI domain 0 and bus 0 are available"));
-        return NULL;
-    }
-
-    if (virAsprintf(&addr, "%d:%d:%d",
-                    dev->addr.pci.domain,
-                    dev->addr.pci.bus,
-                    dev->addr.pci.slot) < 0) {
-        virReportOOMError();
-        return NULL;
-    }
-    return addr;
-}
-
-
-static int qemuCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED,
-                                 virDomainDeviceInfoPtr dev,
-                                 void *opaque)
-{
-    qemuDomainPCIAddressSetPtr addrs = opaque;
-
-    if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
-        char *addr = qemuPCIAddressAsString(dev);
-        if (!addr)
-            return -1;
-
-        VIR_DEBUG("Remembering PCI addr %s", addr);
-
-        if (virHashAddEntry(addrs->used, addr, addr) < 0) {
-            VIR_FREE(addr);
-            return -1;
-        }
-    }
-
-    return 0;
-}
-
-
-qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def)
-{
-    qemuDomainPCIAddressSetPtr addrs;
-
-    if (VIR_ALLOC(addrs) < 0)
-        goto no_memory;
-
-    if (!(addrs->used = virHashCreate(10)))
-        goto no_memory;
-
-    if (virDomainDeviceInfoIterate(def, qemuCollectPCIAddress, addrs) < 0)
-        goto error;
-
-    return addrs;
-
-no_memory:
-    virReportOOMError();
-error:
-    qemuDomainPCIAddressSetFree(addrs);
-    return NULL;
-}
-
-int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
-                                    virDomainDeviceInfoPtr dev)
-{
-    char *addr;
-
-    addr = qemuPCIAddressAsString(dev);
-    if (!addr)
-        return -1;
-
-    VIR_DEBUG("Reserving PCI addr %s", addr);
-
-    if (virHashLookup(addrs->used, addr)) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("unable to reserve PCI address %s"), addr);
-        VIR_FREE(addr);
-        return -1;
-    }
-
-    if (virHashAddEntry(addrs->used, addr, addr)) {
-        VIR_FREE(addr);
-        return -1;
-    }
-
-    if (dev->addr.pci.slot > addrs->nextslot) {
-        addrs->nextslot = dev->addr.pci.slot + 1;
-        if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
-            addrs->nextslot = 0;
-    }
-
-    return 0;
-}
-
-int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
-                                    int slot)
-{
-    virDomainDeviceInfo dev;
-
-    dev.addr.pci.domain = 0;
-    dev.addr.pci.bus = 0;
-    dev.addr.pci.slot = slot;
-
-    return qemuDomainPCIAddressReserveAddr(addrs, &dev);
-}
-
-
-int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
-                                    virDomainDeviceInfoPtr dev)
-{
-    int ret = 0;
-    if (dev->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
-        ret = qemuDomainPCIAddressReserveAddr(addrs, dev);
-    else
-        ret = qemuDomainPCIAddressSetNextAddr(addrs, dev);
-    return ret;
-}
-
-static void qemuDomainPCIAddressSetFreeEntry(void *payload, const char *name ATTRIBUTE_UNUSED)
-{
-    VIR_FREE(payload);
-}
-
-
-int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
-                                    virDomainDeviceInfoPtr dev)
-{
-    char *addr;
-    int ret;
-
-    addr = qemuPCIAddressAsString(dev);
-    if (!addr)
-        return -1;
-
-    ret = virHashRemoveEntry(addrs->used, addr, qemuDomainPCIAddressSetFreeEntry);
-
-    VIR_FREE(addr);
-
-    return ret;
-}
-
-
-void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs)
-{
-    if (!addrs)
-        return;
-
-    virHashFree(addrs->used, qemuDomainPCIAddressSetFreeEntry);
-    VIR_FREE(addrs);
-}
-
-
-int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
-                                    virDomainDeviceInfoPtr dev)
-{
-    int i;
-    int iteration;
-
-    for (i = addrs->nextslot, iteration = 0;
-         iteration <= QEMU_PCI_ADDRESS_LAST_SLOT; i++, iteration++) {
-        virDomainDeviceInfo maybe;
-        char *addr;
-
-        if (QEMU_PCI_ADDRESS_LAST_SLOT < i)
-            i = 0;
-        memset(&maybe, 0, sizeof(maybe));
-        maybe.addr.pci.domain = 0;
-        maybe.addr.pci.bus = 0;
-        maybe.addr.pci.slot = i;
-
-        if (!(addr = qemuPCIAddressAsString(&maybe)))
-            return -1;
-
-        if (virHashLookup(addrs->used, addr)) {
-            VIR_DEBUG("PCI addr %s already in use", addr);
-            VIR_FREE(addr);
-            continue;
-        }
-
-        VIR_DEBUG("Allocating PCI addr %s", addr);
-
-        if (virHashAddEntry(addrs->used, addr, addr) < 0) {
-            VIR_FREE(addr);
-            return -1;
-        }
-
-        dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
-        dev->addr.pci = maybe.addr.pci;
-
-        addrs->nextslot = i + 1;
-        if (QEMU_PCI_ADDRESS_LAST_SLOT < addrs->nextslot)
-            addrs->nextslot = 0;
-
-        return 0;
-    }
-
-    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                    "%s", _("No more available PCI addresses"));
-    return -1;
-}
-
-/*
- * This assigns static PCI slots to all configured devices.
- * The ordering here is chosen to match the ordering used
- * with old QEMU < 0.12, so that if a user updates a QEMU
- * host from old QEMU to QEMU >= 0.12, their guests should
- * get PCI addresses in the same order as before.
- *
- * NB, if they previously hotplugged devices then all bets
- * are off. Hotplug for old QEMU was unfixably broken wrt
- * to stable PCI addressing.
- *
- * Order is:
- *
- *  - Host bridge (slot 0)
- *  - PIIX3 ISA bridge, IDE controller, something else unknown, USB controller (slot 1)
- *  - Video (slot 2)
- *
- * Incrementally assign slots from 3 onwards:
- *
- *  - Net
- *  - Sound
- *  - SCSI controllers
- *  - VirtIO block
- *  - VirtIO balloon
- *  - Host device passthrough
- *  - Watchdog
- *
- * Prior to this function being invoked, qemuCollectPCIAddress() will have
- * added all existing PCI addresses from the 'def' to 'addrs'. Thus this
- * function must only try to reserve addresses if info.type == NONE and
- * skip over info.type == PCI
- */
-int
-qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
-{
-    int i;
-    bool reservedIDE = false;
-
-    /* Host bridge */
-    if (qemuDomainPCIAddressReserveSlot(addrs, 0) < 0)
-        goto error;
-
-    /* Verify that first IDE controller (if any) is on the PIIX3, fn 1 */
-    for (i = 0; i < def->ncontrollers ; i++) {
-        /* First IDE controller lives on the PIIX3 at slot=1, function=1 */
-        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
-            def->controllers[i]->idx == 0) {
-            if (def->controllers[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
-                if (def->controllers[i]->info.addr.pci.domain != 0 ||
-                    def->controllers[i]->info.addr.pci.bus != 0 ||
-                    def->controllers[i]->info.addr.pci.slot != 1 ||
-                    def->controllers[i]->info.addr.pci.function != 1) {
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                    _("Primary IDE controller must have PCI address 0:0:1.1"));
-                    goto error;
-                }
-                /* If TYPE==PCI, then then qemuCollectPCIAddress() function
-                 * has already reserved the address, so we must skip */
-                reservedIDE = true;
-            } else {
-                def->controllers[i]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
-                def->controllers[i]->info.addr.pci.domain = 0;
-                def->controllers[i]->info.addr.pci.bus = 0;
-                def->controllers[i]->info.addr.pci.slot = 1;
-                def->controllers[i]->info.addr.pci.function = 1;
-            }
-        }
-    }
-
-    /* PIIX3 (ISA bridge, IDE controller, something else unknown, USB controller)
-     * hardcoded slot=1, multifunction device
-     */
-    if (!reservedIDE &&
-        qemuDomainPCIAddressReserveSlot(addrs, 1) < 0)
-        goto error;
-
-    /* First VGA is hardcoded slot=2 */
-    if (def->nvideos > 0) {
-        if (def->videos[0]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
-            if (def->videos[0]->info.addr.pci.domain != 0 ||
-                def->videos[0]->info.addr.pci.bus != 0 ||
-                def->videos[0]->info.addr.pci.slot != 2 ||
-                def->videos[0]->info.addr.pci.function != 0) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                _("Primary video card must have PCI address 0:0:2.0"));
-                goto error;
-            }
-        } else {
-            def->videos[0]->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI;
-            def->videos[0]->info.addr.pci.domain = 0;
-            def->videos[0]->info.addr.pci.bus = 0;
-            def->videos[0]->info.addr.pci.slot = 2;
-            def->videos[0]->info.addr.pci.function = 0;
-            if (qemuDomainPCIAddressReserveSlot(addrs, 2) < 0)
-                goto error;
-        }
-    }
-    for (i = 0; i < def->nfss ; i++) {
-        if (def->fss[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
-            continue;
-
-        /* Only support VirtIO-9p-pci so far. If that changes,
-         * we might need to skip devices here */
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->fss[i]->info) < 0)
-            goto error;
-    }
-
-    /* Network interfaces */
-    for (i = 0; i < def->nnets ; i++) {
-        if (def->nets[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
-            continue;
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->nets[i]->info) < 0)
-            goto error;
-    }
-
-    /* Sound cards */
-    for (i = 0; i < def->nsounds ; i++) {
-        if (def->sounds[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
-            continue;
-        /* Skip ISA sound card, and PCSPK */
-        if (def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_SB16 ||
-            def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK)
-            continue;
-
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->sounds[i]->info) < 0)
-            goto error;
-    }
-
-    /* Disk controllers (SCSI only for now) */
-    for (i = 0; i < def->ncontrollers ; i++) {
-        /* FDC lives behind the ISA bridge */
-        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC)
-            continue;
-
-        /* First IDE controller lives on the PIIX3 at slot=1, function=1,
-           dealt with earlier on*/
-        if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
-            def->controllers[i]->idx == 0)
-            continue;
-
-        if (def->controllers[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
-            continue;
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->controllers[i]->info) < 0)
-            goto error;
-    }
-
-    /* Disks (VirtIO only for now */
-    for (i = 0; i < def->ndisks ; i++) {
-        if (def->disks[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
-            continue;
-
-        /* Only VirtIO disks use PCI addrs */
-        if (def->disks[i]->bus != VIR_DOMAIN_DISK_BUS_VIRTIO)
-            continue;
-
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->disks[i]->info) < 0)
-            goto error;
-    }
-
-    /* Host PCI devices */
-    for (i = 0; i < def->nhostdevs ; i++) {
-        if (def->hostdevs[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
-            continue;
-        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
-            def->hostdevs[i]->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
-            continue;
-
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->hostdevs[i]->info) < 0)
-            goto error;
-    }
-
-    /* VirtIO balloon */
-    if (def->memballoon &&
-        def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO &&
-        def->memballoon->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->memballoon->info) < 0)
-            goto error;
-    }
-
-    /* A watchdog */
-    if (def->watchdog &&
-        def->watchdog->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->watchdog->info) < 0)
-            goto error;
-    }
-
-    /* Further non-primary video cards */
-    for (i = 1; i < def->nvideos ; i++) {
-        if (def->videos[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
-            continue;
-        if (qemuDomainPCIAddressSetNextAddr(addrs, &def->videos[i]->info) < 0)
-            goto error;
-    }
-    for (i = 0; i < def->ninputs ; i++) {
-        /* Nada - none are PCI based (yet) */
-    }
-    for (i = 0; i < def->nparallels ; i++) {
-        /* Nada - none are PCI based (yet) */
-    }
-    for (i = 0; i < def->nserials ; i++) {
-        /* Nada - none are PCI based (yet) */
-    }
-    for (i = 0; i < def->nchannels ; i++) {
-        /* Nada - none are PCI based (yet) */
-    }
-
-    return 0;
-
-error:
-    return -1;
-}
-
-
-static int
-qemuBuildDeviceAddressStr(virBufferPtr buf,
-                          virDomainDeviceInfoPtr info)
-{
-    if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
-        if (info->addr.pci.domain != 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("Only PCI device addresses with domain=0 are supported"));
-            return -1;
-        }
-        if (info->addr.pci.bus != 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("Only PCI device addresses with bus=0 are supported"));
-            return -1;
-        }
-        if (info->addr.pci.function != 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("Only PCI device addresses with function=0 are supported"));
-            return -1;
-        }
-
-        /* XXX
-         * When QEMU grows support for > 1 PCI bus, then pci.0 changes
-         * to pci.1, pci.2, etc
-         * When QEMU grows support for > 1 PCI domain, then pci.0 change
-         * to pciNN.0  where NN is the domain number
-         */
-        virBufferVSprintf(buf, ",bus=pci.0,addr=0x%x", info->addr.pci.slot);
-    }
-    return 0;
-}
-
-
-#define QEMU_SERIAL_PARAM_ACCEPTED_CHARS \
-  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
-
-static int
-qemuSafeSerialParamValue(const char *value)
-{
-    if (strspn(value, QEMU_SERIAL_PARAM_ACCEPTED_CHARS) != strlen (value)) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("driver serial '%s' contains unsafe characters"),
-                        value);
-        return -1;
-    }
-
-    return 0;
-}
-
-
-char *
-qemuBuildDriveStr(virDomainDiskDefPtr disk,
-                  int bootable,
-                  unsigned long long qemuCmdFlags)
-{
-    virBuffer opt = VIR_BUFFER_INITIALIZER;
-    const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
-    int idx = virDiskNameToIndex(disk->dst);
-    int busid = -1, unitid = -1;
-
-    if (idx < 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("unsupported disk type '%s'"), disk->dst);
-        goto error;
-    }
-
-    switch (disk->bus) {
-    case VIR_DOMAIN_DISK_BUS_SCSI:
-        if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("unexpected address type for scsi disk"));
-            goto error;
-        }
-
-        /* Setting bus= attr for SCSI drives, causes a controller
-         * to be created. Yes this is slightly odd. It is not possible
-         * to have > 1 bus on a SCSI controller (yet). */
-        if (disk->info.addr.drive.bus != 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            "%s", _("SCSI controller only supports 1 bus"));
-            goto error;
-        }
-        busid = disk->info.addr.drive.controller;
-        unitid = disk->info.addr.drive.unit;
-        break;
-
-    case VIR_DOMAIN_DISK_BUS_IDE:
-        if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("unexpected address type for ide disk"));
-            goto error;
-        }
-        /* We can only have 1 IDE controller (currently) */
-        if (disk->info.addr.drive.controller != 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("Only 1 %s controller is supported"), bus);
-            goto error;
-        }
-        busid = disk->info.addr.drive.bus;
-        unitid = disk->info.addr.drive.unit;
-        break;
-
-    case VIR_DOMAIN_DISK_BUS_FDC:
-        if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                            _("unexpected address type for fdc disk"));
-            goto error;
-        }
-        /* We can only have 1 FDC controller (currently) */
-        if (disk->info.addr.drive.controller != 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("Only 1 %s controller is supported"), bus);
-            goto error;
-        }
-        /* We can only have 1 FDC bus (currently) */
-        if (disk->info.addr.drive.bus != 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("Only 1 %s bus is supported"), bus);
-            goto error;
-        }
-        unitid = disk->info.addr.drive.unit;
-
-        break;
-
-    case VIR_DOMAIN_DISK_BUS_VIRTIO:
-        /* Each virtio drive is a separate PCI device, no unit/busid or index */
-        idx = -1;
-        break;
-
-    case VIR_DOMAIN_DISK_BUS_XEN:
-        /* Xen has no address type currently, so assign based on index */
-        break;
-    }
-
-    /* disk->src is NULL when we use nbd disks */
-    if (disk->src || (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
-                      disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_NBD)) {
-        if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
-            /* QEMU only supports magic FAT format for now */
-            if (disk->driverType &&
-                STRNEQ(disk->driverType, "fat")) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("unsupported disk driver type for '%s'"),
-                                disk->driverType);
-                goto error;
-            }
-            if (!disk->readonly) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                _("cannot create virtual FAT disks in read-write mode"));
-                goto error;
-            }
-            if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
-                virBufferVSprintf(&opt, "file=fat:floppy:%s,", disk->src);
-            else
-                virBufferVSprintf(&opt, "file=fat:%s,", disk->src);
-        } else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
-            switch (disk->protocol) {
-            case VIR_DOMAIN_DISK_PROTOCOL_NBD:
-                if (disk->nhosts != 1) {
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                    _("NBD accepts only one host"));
-                    goto error;
-                }
-                virBufferVSprintf(&opt, "file=nbd:%s:%s,",
-                                  disk->hosts->name, disk->hosts->port);
-                break;
-            case VIR_DOMAIN_DISK_PROTOCOL_RBD:
-                /* TODO: set monitor hostnames */
-                virBufferVSprintf(&opt, "file=rbd:%s,", disk->src);
-                break;
-            case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
-                if (disk->nhosts == 0)
-                    virBufferVSprintf(&opt, "file=sheepdog:%s,", disk->src);
-                else
-                    /* only one host is supported now */
-                    virBufferVSprintf(&opt, "file=sheepdog:%s:%s:%s,",
-                                      disk->hosts->name, disk->hosts->port,
-                                      disk->src);
-                break;
-            }
-        } else {
-            virBufferVSprintf(&opt, "file=%s,", disk->src);
-        }
-    }
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)
-        virBufferAddLit(&opt, "if=none");
-    else
-        virBufferVSprintf(&opt, "if=%s", bus);
-
-    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
-        virBufferAddLit(&opt, ",media=cdrom");
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-        virBufferVSprintf(&opt, ",id=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
-    } else {
-        if (busid == -1 && unitid == -1) {
-            if (idx != -1)
-                virBufferVSprintf(&opt, ",index=%d", idx);
-        } else {
-            if (busid != -1)
-                virBufferVSprintf(&opt, ",bus=%d", busid);
-            if (unitid != -1)
-                virBufferVSprintf(&opt, ",unit=%d", unitid);
-        }
-    }
-    if (bootable &&
-        disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
-        disk->bus != VIR_DOMAIN_DISK_BUS_IDE)
-        virBufferAddLit(&opt, ",boot=on");
-    if (disk->readonly &&
-        qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_READONLY)
-        virBufferAddLit(&opt, ",readonly=on");
-    if (disk->driverType && *disk->driverType != '\0' &&
-        disk->type != VIR_DOMAIN_DISK_TYPE_DIR &&
-        qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_FORMAT)
-        virBufferVSprintf(&opt, ",format=%s", disk->driverType);
-    if (disk->serial &&
-        (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_SERIAL)) {
-        if (qemuSafeSerialParamValue(disk->serial) < 0)
-            goto error;
-        virBufferVSprintf(&opt, ",serial=%s", disk->serial);
-    }
-
-    if (disk->cachemode) {
-        const char *mode =
-            (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_CACHE_V2) ?
-            qemuDiskCacheV2TypeToString(disk->cachemode) :
-            qemuDiskCacheV1TypeToString(disk->cachemode);
-
-        virBufferVSprintf(&opt, ",cache=%s", mode);
-    } else if (disk->shared && !disk->readonly) {
-        virBufferAddLit(&opt, ",cache=off");
-    }
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON) {
-        if (disk->error_policy) {
-            virBufferVSprintf(&opt, ",werror=%s,rerror=%s",
-                              virDomainDiskErrorPolicyTypeToString(disk->error_policy),
-                              virDomainDiskErrorPolicyTypeToString(disk->error_policy));
-        }
-    }
-
-    if (virBufferError(&opt)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&opt);
-
-error:
-    virBufferFreeAndReset(&opt);
-    return NULL;
-}
-
-
-char *
-qemuBuildDriveDevStr(virDomainDiskDefPtr disk)
-{
-    virBuffer opt = VIR_BUFFER_INITIALIZER;
-    const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
-    int idx = virDiskNameToIndex(disk->dst);
-
-    if (idx < 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("unsupported disk type '%s'"), disk->dst);
-        goto error;
-    }
-
-    switch (disk->bus) {
-    case VIR_DOMAIN_DISK_BUS_IDE:
-        virBufferAddLit(&opt, "ide-drive");
-        virBufferVSprintf(&opt, ",bus=ide.%d,unit=%d",
-                          disk->info.addr.drive.bus,
-                          disk->info.addr.drive.unit);
-        break;
-    case VIR_DOMAIN_DISK_BUS_SCSI:
-        virBufferAddLit(&opt, "scsi-disk");
-        virBufferVSprintf(&opt, ",bus=scsi%d.%d,scsi-id=%d",
-                          disk->info.addr.drive.controller,
-                          disk->info.addr.drive.bus,
-                          disk->info.addr.drive.unit);
-        break;
-    case VIR_DOMAIN_DISK_BUS_VIRTIO:
-        virBufferAddLit(&opt, "virtio-blk-pci");
-        qemuBuildDeviceAddressStr(&opt, &disk->info);
-        break;
-    case VIR_DOMAIN_DISK_BUS_USB:
-        virBufferAddLit(&opt, "usb-storage");
-        break;
-    default:
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("unsupported disk bus '%s' with device setup"), bus);
-        goto error;
-    }
-    virBufferVSprintf(&opt, ",drive=%s%s", QEMU_DRIVE_HOST_PREFIX, disk->info.alias);
-    virBufferVSprintf(&opt, ",id=%s", disk->info.alias);
-
-    if (virBufferError(&opt)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&opt);
-
-error:
-    virBufferFreeAndReset(&opt);
-    return NULL;
-}
-
-
-char *qemuBuildFSStr(virDomainFSDefPtr fs,
-                     unsigned long long qemuCmdFlags ATTRIBUTE_UNUSED)
-{
-    virBuffer opt = VIR_BUFFER_INITIALIZER;
-
-    if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
-        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                        _("only supports mount filesystem type"));
-        goto error;
-    }
-
-    virBufferAddLit(&opt, "local");
-    if (fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_MAPPED) {
-        virBufferAddLit(&opt, ",security_model=mapped");
-    } else if(fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_PASSTHROUGH) {
-        virBufferAddLit(&opt, ",security_model=passthrough");
-    } else if(fs->accessmode == VIR_DOMAIN_FS_ACCESSMODE_SQUASH) {
-        virBufferAddLit(&opt, ",security_model=none");
-    }
-    virBufferVSprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
-    virBufferVSprintf(&opt, ",path=%s", fs->src);
-
-    if (virBufferError(&opt)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&opt);
-
-error:
-    virBufferFreeAndReset(&opt);
-    return NULL;
-}
-
-
-char *
-qemuBuildFSDevStr(virDomainFSDefPtr fs)
-{
-    virBuffer opt = VIR_BUFFER_INITIALIZER;
-
-    if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
-        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                        _("can only passthrough directories"));
-        goto error;
-    }
-
-    virBufferAddLit(&opt, "virtio-9p-pci");
-    virBufferVSprintf(&opt, ",id=%s", fs->info.alias);
-    virBufferVSprintf(&opt, ",fsdev=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
-    virBufferVSprintf(&opt, ",mount_tag=%s", fs->dst);
-    qemuBuildDeviceAddressStr(&opt, &fs->info);
-
-    if (virBufferError(&opt)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&opt);
-
-error:
-    virBufferFreeAndReset(&opt);
-    return NULL;
-}
-
-
-char *
-qemuBuildControllerDevStr(virDomainControllerDefPtr def)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    switch (def->type) {
-    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
-        virBufferAddLit(&buf, "lsi");
-        virBufferVSprintf(&buf, ",id=scsi%d", def->idx);
-        break;
-
-    case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
-        if (def->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
-            virBufferAddLit(&buf, "virtio-serial-pci");
-        } else {
-            virBufferAddLit(&buf, "virtio-serial");
-        }
-        virBufferVSprintf(&buf, ",id=" QEMU_VIRTIO_SERIAL_PREFIX "%d",
-                          def->idx);
-        if (def->opts.vioserial.ports != -1) {
-            virBufferVSprintf(&buf, ",max_ports=%d",
-                              def->opts.vioserial.ports);
-        }
-        if (def->opts.vioserial.vectors != -1) {
-            virBufferVSprintf(&buf, ",vectors=%d",
-                              def->opts.vioserial.vectors);
-        }
-        break;
-
-    /* We always get an IDE controller, whether we want it or not. */
-    case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
-    default:
-        goto error;
-    }
-
-    if (qemuBuildDeviceAddressStr(&buf, &def->info) < 0)
-        goto error;
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-char *
-qemuBuildNicStr(virDomainNetDefPtr net,
-                const char *prefix,
-                int vlan)
-{
-    char *str;
-    if (virAsprintf(&str,
-                    "%smacaddr=%02x:%02x:%02x:%02x:%02x:%02x,vlan=%d%s%s%s%s",
-                    prefix ? prefix : "",
-                    net->mac[0], net->mac[1],
-                    net->mac[2], net->mac[3],
-                    net->mac[4], net->mac[5],
-                    vlan,
-                    (net->model ? ",model=" : ""),
-                    (net->model ? net->model : ""),
-                    (net->info.alias ? ",name=" : ""),
-                    (net->info.alias ? net->info.alias : "")) < 0) {
-        virReportOOMError();
-        return NULL;
-    }
-
-    return str;
-}
-
-
-char *
-qemuBuildNicDevStr(virDomainNetDefPtr net, int vlan)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-    const char *nic;
-
-    if (!net->model) {
-        nic = "rtl8139";
-    } else if (STREQ(net->model, "virtio")) {
-        nic = "virtio-net-pci";
-    } else {
-        nic = net->model;
-    }
-
-    virBufferAdd(&buf, nic, strlen(nic));
-    if (vlan == -1)
-        virBufferVSprintf(&buf, ",netdev=host%s", net->info.alias);
-    else
-        virBufferVSprintf(&buf, ",vlan=%d", vlan);
-    virBufferVSprintf(&buf, ",id=%s", net->info.alias);
-    virBufferVSprintf(&buf, ",mac=%02x:%02x:%02x:%02x:%02x:%02x",
-                      net->mac[0], net->mac[1],
-                      net->mac[2], net->mac[3],
-                      net->mac[4], net->mac[5]);
-    if (qemuBuildDeviceAddressStr(&buf, &net->info) < 0)
-        goto error;
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-char *
-qemuBuildHostNetStr(virDomainNetDefPtr net,
-                    char type_sep,
-                    int vlan,
-                    const char *tapfd,
-                    const char *vhostfd)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    switch (net->type) {
-    case VIR_DOMAIN_NET_TYPE_NETWORK:
-    case VIR_DOMAIN_NET_TYPE_BRIDGE:
-    case VIR_DOMAIN_NET_TYPE_DIRECT:
-        virBufferAddLit(&buf, "tap");
-        virBufferVSprintf(&buf, "%cfd=%s", type_sep, tapfd);
-        type_sep = ',';
-        break;
-
-    case VIR_DOMAIN_NET_TYPE_ETHERNET:
-        virBufferAddLit(&buf, "tap");
-        if (net->ifname) {
-            virBufferVSprintf(&buf, "%cifname=%s", type_sep, net->ifname);
-            type_sep = ',';
-        }
-        if (net->data.ethernet.script) {
-            virBufferVSprintf(&buf, "%cscript=%s", type_sep,
-                              net->data.ethernet.script);
-            type_sep = ',';
-        }
-        break;
-
-    case VIR_DOMAIN_NET_TYPE_CLIENT:
-    case VIR_DOMAIN_NET_TYPE_SERVER:
-    case VIR_DOMAIN_NET_TYPE_MCAST:
-        virBufferAddLit(&buf, "socket");
-        switch (net->type) {
-        case VIR_DOMAIN_NET_TYPE_CLIENT:
-            virBufferVSprintf(&buf, "%cconnect=%s:%d",
-                              type_sep,
-                              net->data.socket.address,
-                              net->data.socket.port);
-            break;
-        case VIR_DOMAIN_NET_TYPE_SERVER:
-            virBufferVSprintf(&buf, "%clisten=%s:%d",
-                              type_sep,
-                              net->data.socket.address,
-                              net->data.socket.port);
-            break;
-        case VIR_DOMAIN_NET_TYPE_MCAST:
-            virBufferVSprintf(&buf, "%cmcast=%s:%d",
-                              type_sep,
-                              net->data.socket.address,
-                              net->data.socket.port);
-            break;
-        case VIR_DOMAIN_NET_TYPE_USER:
-        case VIR_DOMAIN_NET_TYPE_ETHERNET:
-        case VIR_DOMAIN_NET_TYPE_NETWORK:
-        case VIR_DOMAIN_NET_TYPE_BRIDGE:
-        case VIR_DOMAIN_NET_TYPE_INTERNAL:
-        case VIR_DOMAIN_NET_TYPE_DIRECT:
-        case VIR_DOMAIN_NET_TYPE_LAST:
-            break;
-        }
-        type_sep = ',';
-        break;
-
-    case VIR_DOMAIN_NET_TYPE_USER:
-    default:
-        virBufferAddLit(&buf, "user");
-        break;
-    }
-
-    if (vlan >= 0) {
-        virBufferVSprintf(&buf, "%cvlan=%d", type_sep, vlan);
-        if (net->info.alias)
-            virBufferVSprintf(&buf, ",name=host%s",
-                              net->info.alias);
-    } else {
-        virBufferVSprintf(&buf, "%cid=host%s",
-                          type_sep, net->info.alias);
-    }
-
-    if (vhostfd && *vhostfd) {
-        virBufferVSprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd);
-    }
-
-    if (virBufferError(&buf)) {
-        virBufferFreeAndReset(&buf);
-        virReportOOMError();
-        return NULL;
-    }
-
-    return virBufferContentAndReset(&buf);
-}
-
-
-char *
-qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    const char *model = virDomainWatchdogModelTypeToString(dev->model);
-    if (!model) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        "%s", _("missing watchdog model"));
-        goto error;
-    }
-
-    virBufferVSprintf(&buf, "%s", model);
-    virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
-    if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
-        goto error;
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-char *
-qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    virBufferAddLit(&buf, "virtio-balloon-pci");
-    virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
-    if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
-        goto error;
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-char *
-qemuBuildUSBInputDevStr(virDomainInputDefPtr dev)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    virBufferVSprintf(&buf, "%s",
-                      dev->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
-                      "usb-mouse" : "usb-tablet");
-    virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-char *
-qemuBuildSoundDevStr(virDomainSoundDefPtr sound)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-    const char *model = virDomainSoundModelTypeToString(sound->model);
-
-    if (!model) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        "%s", _("invalid sound model"));
-        goto error;
-    }
-
-    /* Hack for 2 wierdly unusal devices name in QEMU */
-    if (STREQ(model, "es1370"))
-        model = "ES1370";
-    else if (STREQ(model, "ac97"))
-        model = "AC97";
-
-    virBufferVSprintf(&buf, "%s", model);
-    virBufferVSprintf(&buf, ",id=%s", sound->info.alias);
-    if (qemuBuildDeviceAddressStr(&buf, &sound->info) < 0)
-        goto error;
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-static char *
-qemuBuildVideoDevStr(virDomainVideoDefPtr video)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-    const char *model = qemuVideoTypeToString(video->type);
-
-    if (!model) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        "%s", _("invalid video model"));
-        goto error;
-    }
-
-    virBufferVSprintf(&buf, "%s", model);
-    virBufferVSprintf(&buf, ",id=%s", video->info.alias);
-    if (qemuBuildDeviceAddressStr(&buf, &video->info) < 0)
-        goto error;
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-int
-qemudOpenPCIConfig(virDomainHostdevDefPtr dev)
-{
-    char *path = NULL;
-    int configfd = -1;
-
-    if (virAsprintf(&path, "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/config",
-                    dev->source.subsys.u.pci.domain,
-                    dev->source.subsys.u.pci.bus,
-                    dev->source.subsys.u.pci.slot,
-                    dev->source.subsys.u.pci.function) < 0) {
-        virReportOOMError();
-        return -1;
-    }
-
-    configfd = open(path, O_RDWR, 0);
-
-    if (configfd < 0)
-        virReportSystemError(errno, _("Failed opening %s"), path);
-
-    VIR_FREE(path);
-
-    return configfd;
-}
-
-char *
-qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev, const char *configfd)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    virBufferAddLit(&buf, "pci-assign");
-    virBufferVSprintf(&buf, ",host=%.2x:%.2x.%.1x",
-                      dev->source.subsys.u.pci.bus,
-                      dev->source.subsys.u.pci.slot,
-                      dev->source.subsys.u.pci.function);
-    virBufferVSprintf(&buf, ",id=%s", dev->info.alias);
-    if (configfd && *configfd)
-        virBufferVSprintf(&buf, ",configfd=%s", configfd);
-    if (qemuBuildDeviceAddressStr(&buf, &dev->info) < 0)
-        goto error;
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-char *
-qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev)
-{
-    char *ret = NULL;
-
-    if (virAsprintf(&ret, "host=%.2x:%.2x.%.1x",
-                    dev->source.subsys.u.pci.bus,
-                    dev->source.subsys.u.pci.slot,
-                    dev->source.subsys.u.pci.function) < 0)
-        virReportOOMError();
-
-    return ret;
-}
-
-
-char *
-qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev)
-{
-    char *ret = NULL;
-
-    if (!dev->source.subsys.u.usb.bus &&
-        !dev->source.subsys.u.usb.device) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("USB host device is missing bus/device information"));
-        return NULL;
-    }
-
-    if (virAsprintf(&ret, "usb-host,hostbus=%d,hostaddr=%d,id=%s",
-                    dev->source.subsys.u.usb.bus,
-                    dev->source.subsys.u.usb.device,
-                    dev->info.alias) < 0)
-        virReportOOMError();
-
-    return ret;
-}
-
-
-char *
-qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev)
-{
-    char *ret = NULL;
-
-    if (!dev->source.subsys.u.usb.bus &&
-        !dev->source.subsys.u.usb.device) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                        _("USB host device is missing bus/device information"));
-        return NULL;
-    }
-
-    if (virAsprintf(&ret, "host:%d.%d",
-                    dev->source.subsys.u.usb.bus,
-                    dev->source.subsys.u.usb.device) < 0)
-        virReportOOMError();
-
-    return ret;
-}
-
-
-
-/* This function outputs a -chardev command line option which describes only the
- * host side of the character device */
-char *
-qemuBuildChrChardevStr(virDomainChrDefPtr dev)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-    bool telnet;
-
-    switch(dev->type) {
-    case VIR_DOMAIN_CHR_TYPE_NULL:
-        virBufferVSprintf(&buf, "null,id=%s", dev->info.alias);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_VC:
-        virBufferVSprintf(&buf, "vc,id=%s", dev->info.alias);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_PTY:
-        virBufferVSprintf(&buf, "pty,id=%s", dev->info.alias);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_DEV:
-        virBufferVSprintf(&buf, "tty,id=%s,path=%s", dev->info.alias, dev->data.file.path);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_FILE:
-        virBufferVSprintf(&buf, "file,id=%s,path=%s", dev->info.alias, dev->data.file.path);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_PIPE:
-        virBufferVSprintf(&buf, "pipe,id=%s,path=%s", dev->info.alias, dev->data.file.path);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_STDIO:
-        virBufferVSprintf(&buf, "stdio,id=%s", dev->info.alias);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_UDP:
-        virBufferVSprintf(&buf,
-                          "udp,id=%s,host=%s,port=%s,localaddr=%s,localport=%s",
-                          dev->info.alias,
-                          dev->data.udp.connectHost,
-                          dev->data.udp.connectService,
-                          dev->data.udp.bindHost,
-                          dev->data.udp.bindService);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_TCP:
-        telnet = dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
-        virBufferVSprintf(&buf,
-                          "socket,id=%s,host=%s,port=%s%s%s",
-                          dev->info.alias,
-                          dev->data.tcp.host,
-                          dev->data.tcp.service,
-                          telnet ? ",telnet" : "",
-                          dev->data.tcp.listen ? ",server,nowait" : "");
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_UNIX:
-        virBufferVSprintf(&buf,
-                          "socket,id=%s,path=%s%s",
-                          dev->info.alias,
-                          dev->data.nix.path,
-                          dev->data.nix.listen ? ",server,nowait" : "");
-        break;
-    }
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-char *
-qemuBuildChrArgStr(virDomainChrDefPtr dev, const char *prefix)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    if (prefix)
-        virBufferAdd(&buf, prefix, strlen(prefix));
-
-    switch (dev->type) {
-    case VIR_DOMAIN_CHR_TYPE_NULL:
-        virBufferAddLit(&buf, "null");
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_VC:
-        virBufferAddLit(&buf, "vc");
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_PTY:
-        virBufferAddLit(&buf, "pty");
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_DEV:
-        virBufferStrcat(&buf, dev->data.file.path, NULL);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_FILE:
-        virBufferVSprintf(&buf, "file:%s", dev->data.file.path);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_PIPE:
-        virBufferVSprintf(&buf, "pipe:%s", dev->data.file.path);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_STDIO:
-        virBufferAddLit(&buf, "stdio");
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_UDP:
-        virBufferVSprintf(&buf, "udp:%s:%s %s:%s",
-                          dev->data.udp.connectHost,
-                          dev->data.udp.connectService,
-                          dev->data.udp.bindHost,
-                          dev->data.udp.bindService);
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_TCP:
-        if (dev->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET) {
-            virBufferVSprintf(&buf, "telnet:%s:%s%s",
-                              dev->data.tcp.host,
-                              dev->data.tcp.service,
-                              dev->data.tcp.listen ? ",server,nowait" : "");
-        } else {
-            virBufferVSprintf(&buf, "tcp:%s:%s%s",
-                              dev->data.tcp.host,
-                              dev->data.tcp.service,
-                              dev->data.tcp.listen ? ",server,nowait" : "");
-        }
-        break;
-
-    case VIR_DOMAIN_CHR_TYPE_UNIX:
-        virBufferVSprintf(&buf, "unix:%s%s",
-                          dev->data.nix.path,
-                          dev->data.nix.listen ? ",server,nowait" : "");
-        break;
-    }
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-char *
-qemuBuildVirtioSerialPortDevStr(virDomainChrDefPtr dev)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-    if (dev->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)
-        virBufferAddLit(&buf, "virtconsole");
-    else
-        virBufferAddLit(&buf, "virtserialport");
-
-    if (dev->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) {
-        /* Check it's a virtio-serial address */
-        if (dev->info.type !=
-            VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL)
-        {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            "%s", _("virtio serial device has invalid address type"));
-            goto error;
-        }
-
-        virBufferVSprintf(&buf,
-                          ",bus=" QEMU_VIRTIO_SERIAL_PREFIX "%d.%d",
-                          dev->info.addr.vioserial.controller,
-                          dev->info.addr.vioserial.bus);
-        virBufferVSprintf(&buf,
-                          ",nr=%d",
-                          dev->info.addr.vioserial.port);
-    }
-
-    virBufferVSprintf(&buf, ",chardev=%s", dev->info.alias);
-    if (dev->target.name) {
-        virBufferVSprintf(&buf, ",name=%s", dev->target.name);
-    }
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-static char *qemuBuildSmbiosBiosStr(virSysinfoDefPtr def)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    if ((def->bios_vendor == NULL) && (def->bios_version == NULL) &&
-        (def->bios_date == NULL) && (def->bios_release == NULL))
-        return(NULL);
-
-    virBufferAddLit(&buf, "type=0");
-
-    /* 0:Vendor */
-    if (def->bios_vendor)
-        virBufferVSprintf(&buf, ",vendor=%s", def->bios_vendor);
-    /* 0:BIOS Version */
-    if (def->bios_version)
-        virBufferVSprintf(&buf, ",version=%s", def->bios_version);
-    /* 0:BIOS Release Date */
-    if (def->bios_date)
-        virBufferVSprintf(&buf, ",date=%s", def->bios_date);
-    /* 0:System BIOS Major Release and 0:System BIOS Minor Release */
-    if (def->bios_release)
-        virBufferVSprintf(&buf, ",release=%s", def->bios_release);
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return(NULL);
-}
-
-static char *qemuBuildSmbiosSystemStr(virSysinfoDefPtr def, bool skip_uuid)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    if ((def->system_manufacturer == NULL) && (def->system_sku == NULL) &&
-        (def->system_product == NULL) && (def->system_version == NULL) &&
-        (def->system_serial == NULL) && (def->system_family == NULL) &&
-        (def->system_uuid == NULL || skip_uuid))
-        return NULL;
-
-    virBufferAddLit(&buf, "type=1");
-
-    /* 1:Manufacturer */
-    if (def->system_manufacturer)
-        virBufferVSprintf(&buf, ",manufacturer=%s",
-                          def->system_manufacturer);
-     /* 1:Product Name */
-    if (def->system_product)
-        virBufferVSprintf(&buf, ",product=%s", def->system_product);
-    /* 1:Version */
-    if (def->system_version)
-        virBufferVSprintf(&buf, ",version=%s", def->system_version);
-    /* 1:Serial Number */
-    if (def->system_serial)
-        virBufferVSprintf(&buf, ",serial=%s", def->system_serial);
-    /* 1:UUID */
-    if (def->system_uuid && !skip_uuid)
-        virBufferVSprintf(&buf, ",uuid=%s", def->system_uuid);
-    /* 1:SKU Number */
-    if (def->system_sku)
-        virBufferVSprintf(&buf, ",sku=%s", def->system_sku);
-    /* 1:Family */
-    if (def->system_family)
-        virBufferVSprintf(&buf, ",family=%s", def->system_family);
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return(NULL);
-}
-
-static char *
-qemuBuildClockArgStr(virDomainClockDefPtr def)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    switch (def->offset) {
-    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
-        virBufferAddLit(&buf, "base=utc");
-        break;
-
-    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
-    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
-        virBufferAddLit(&buf, "base=localtime");
-        break;
-
-    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE: {
-        time_t now = time(NULL);
-        struct tm nowbits;
-
-        now += def->data.adjustment;
-        gmtime_r(&now, &nowbits);
-
-        virBufferVSprintf(&buf, "base=%d-%02d-%02dT%02d:%02d:%02d",
-                          nowbits.tm_year + 1900,
-                          nowbits.tm_mon + 1,
-                          nowbits.tm_mday,
-                          nowbits.tm_hour,
-                          nowbits.tm_min,
-                          nowbits.tm_sec);
-    }   break;
-
-    default:
-        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                        _("unsupported clock offset '%s'"),
-                        virDomainClockOffsetTypeToString(def->offset));
-        goto error;
-    }
-
-    /* Look for an 'rtc' timer element, and add in appropriate clock= and driftfix= */
-    int i;
-    for (i = 0; i < def->ntimers; i++) {
-        if (def->timers[i]->name == VIR_DOMAIN_TIMER_NAME_RTC) {
-            switch (def->timers[i]->track) {
-            case -1: /* unspecified - use hypervisor default */
-                break;
-            case VIR_DOMAIN_TIMER_TRACK_BOOT:
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                _("unsupported rtc timer track '%s'"),
-                                virDomainTimerTrackTypeToString(def->timers[i]->track));
-                goto error;
-            case VIR_DOMAIN_TIMER_TRACK_GUEST:
-                virBufferAddLit(&buf, ",clock=vm");
-                break;
-            case VIR_DOMAIN_TIMER_TRACK_WALL:
-                virBufferAddLit(&buf, ",clock=host");
-                break;
-            }
-
-            switch (def->timers[i]->tickpolicy) {
-            case -1:
-            case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
-                /* This is the default - missed ticks delivered when
-                   next scheduled, at normal rate */
-                break;
-            case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
-                /* deliver ticks at a faster rate until caught up */
-                virBufferAddLit(&buf, ",driftfix=slew");
-                break;
-            case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
-            case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                _("unsupported rtc timer tickpolicy '%s'"),
-                                virDomainTimerTickpolicyTypeToString(def->timers[i]->tickpolicy));
-                goto error;
-            }
-            break; /* no need to check other timers - there is only one rtc */
-        }
-    }
-
-    if (virBufferError(&buf)) {
-        virReportOOMError();
-        goto error;
-    }
-
-    return virBufferContentAndReset(&buf);
-
-error:
-    virBufferFreeAndReset(&buf);
-    return NULL;
-}
-
-
-static int
-qemuBuildCpuArgStr(const struct qemud_driver *driver,
-                   const virDomainDefPtr def,
-                   const char *emulator,
-                   unsigned long long qemuCmdFlags,
-                   const struct utsname *ut,
-                   char **opt,
-                   bool *hasHwVirt)
-{
-    const virCPUDefPtr host = driver->caps->host.cpu;
-    virCPUDefPtr guest = NULL;
-    unsigned int ncpus = 0;
-    const char **cpus = NULL;
-    union cpuData *data = NULL;
-    int ret = -1;
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-    int i;
-
-    *hasHwVirt = false;
-
-    if (def->cpu && def->cpu->model) {
-        if (qemuCapsProbeCPUModels(emulator, qemuCmdFlags, ut->machine,
-                                   &ncpus, &cpus) < 0)
-            goto cleanup;
-
-        if (!ncpus || !host) {
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                            _("CPU specification not supported by hypervisor"));
-            goto cleanup;
-        }
-    }
-
-    if (ncpus > 0 && host) {
-        virCPUCompareResult cmp;
-        const char *preferred;
-        int hasSVM;
-
-        cmp = cpuGuestData(host, def->cpu, &data);
-        switch (cmp) {
-        case VIR_CPU_COMPARE_INCOMPATIBLE:
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            "%s", _("guest CPU is not compatible with host CPU"));
-            /* fall through */
-        case VIR_CPU_COMPARE_ERROR:
-            goto cleanup;
-
-        default:
-            break;
-        }
-
-        if (VIR_ALLOC(guest) < 0 || !(guest->arch = strdup(ut->machine)))
-            goto no_memory;
-
-        if (def->cpu->match == VIR_CPU_MATCH_MINIMUM)
-            preferred = host->model;
-        else
-            preferred = def->cpu->model;
-
-        guest->type = VIR_CPU_TYPE_GUEST;
-        if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
-            goto cleanup;
-
-        /* Only 'svm' requires --enable-nesting. The nested
-         * 'vmx' patches now simply hook off the CPU features
-         */
-        hasSVM = cpuHasFeature(guest->arch, data, "svm");
-        if (hasSVM < 0)
-            goto cleanup;
-        *hasHwVirt = hasSVM > 0 ? true : false;
-
-        virBufferVSprintf(&buf, "%s", guest->model);
-        for (i = 0; i < guest->nfeatures; i++) {
-            char sign;
-            if (guest->features[i].policy == VIR_CPU_FEATURE_DISABLE)
-                sign = '-';
-            else
-                sign = '+';
-
-            virBufferVSprintf(&buf, ",%c%s", sign, guest->features[i].name);
-        }
-    }
-    else {
-        /*
-         * Need to force a 32-bit guest CPU type if
-         *
-         *  1. guest OS is i686
-         *  2. host OS is x86_64
-         *  3. emulator is qemu-kvm or kvm
-         *
-         * Or
-         *
-         *  1. guest OS is i686
-         *  2. emulator is qemu-system-x86_64
-         */
-        if (STREQ(def->os.arch, "i686") &&
-            ((STREQ(ut->machine, "x86_64") &&
-              strstr(emulator, "kvm")) ||
-             strstr(emulator, "x86_64")))
-            virBufferAddLit(&buf, "qemu32");
-    }
-
-    if (virBufferError(&buf))
-        goto no_memory;
-
-    *opt = virBufferContentAndReset(&buf);
-
-    ret = 0;
-
-cleanup:
-    virCPUDefFree(guest);
-    cpuDataFree(ut->machine, data);
-
-    if (cpus) {
-        for (i = 0; i < ncpus; i++)
-            VIR_FREE(cpus[i]);
-        VIR_FREE(cpus);
-    }
-
-    return ret;
-
-no_memory:
-    virReportOOMError();
-    goto cleanup;
-}
-
-static char *
-qemuBuildSmpArgStr(const virDomainDefPtr def,
-                   unsigned long long qemuCmdFlags)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-
-    virBufferVSprintf(&buf, "%u", def->vcpus);
-
-    if ((qemuCmdFlags & QEMUD_CMD_FLAG_SMP_TOPOLOGY)) {
-        if (def->vcpus != def->maxvcpus)
-            virBufferVSprintf(&buf, ",maxcpus=%u", def->maxvcpus);
-        /* sockets, cores, and threads are either all zero
-         * or all non-zero, thus checking one of them is enough */
-        if (def->cpu && def->cpu->sockets) {
-            virBufferVSprintf(&buf, ",sockets=%u", def->cpu->sockets);
-            virBufferVSprintf(&buf, ",cores=%u", def->cpu->cores);
-            virBufferVSprintf(&buf, ",threads=%u", def->cpu->threads);
-        }
-        else {
-            virBufferVSprintf(&buf, ",sockets=%u", def->maxvcpus);
-            virBufferVSprintf(&buf, ",cores=%u", 1);
-            virBufferVSprintf(&buf, ",threads=%u", 1);
-        }
-    } else if (def->vcpus != def->maxvcpus) {
-        virBufferFreeAndReset(&buf);
-        /* FIXME - consider hot-unplugging cpus after boot for older qemu */
-        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                        _("setting current vcpu count less than maximum is "
-                          "not supported with this QEMU binary"));
-        return NULL;
-    }
-
-    if (virBufferError(&buf)) {
-        virBufferFreeAndReset(&buf);
-        virReportOOMError();
-        return NULL;
-    }
-
-    return virBufferContentAndReset(&buf);
-}
-
-
-/*
- * Constructs a argv suitable for launching qemu with config defined
- * for a given virtual machine.
- *
- * XXX 'conn' is only required to resolve network -> bridge name
- * figure out how to remove this requirement some day
- */
-virCommandPtr
-qemudBuildCommandLine(virConnectPtr conn,
-                      struct qemud_driver *driver,
-                      virDomainDefPtr def,
-                      virDomainChrDefPtr monitor_chr,
-                      bool monitor_json,
-                      unsigned long long qemuCmdFlags,
-                      const char *migrateFrom,
-                      virDomainSnapshotObjPtr current_snapshot,
-                      enum virVMOperationType vmop)
-{
-    int i;
-    char boot[VIR_DOMAIN_BOOT_LAST+1];
-    struct utsname ut;
-    int disableKQEMU = 0;
-    int enableKQEMU = 0;
-    int disableKVM = 0;
-    int enableKVM = 0;
-    const char *emulator;
-    char uuid[VIR_UUID_STRING_BUFLEN];
-    char *cpu;
-    char *smp;
-    int last_good_net = -1;
-    bool hasHwVirt = false;
-    virCommandPtr cmd;
-    bool has_rbd_hosts = false;
-    virBuffer rbd_hosts = VIR_BUFFER_INITIALIZER;
-
-    uname_normalize(&ut);
-
-    if (qemuAssignDeviceAliases(def, qemuCmdFlags) < 0)
-        return NULL;
-
-    virUUIDFormat(def->uuid, uuid);
-
-    /* Migration is very annoying due to wildly varying syntax & capabilities
-     * over time of KVM / QEMU codebases
-     */
-    if (migrateFrom) {
-        if (STRPREFIX(migrateFrom, "tcp")) {
-            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP)) {
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                "%s", _("TCP migration is not supported with this QEMU binary"));
-                return NULL;
-            }
-        } else if (STREQ(migrateFrom, "stdio")) {
-            if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
-                migrateFrom = "exec:cat";
-            } 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 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 NULL;
-            }
-        }
-    }
-
-    emulator = def->emulator;
-
-    /*
-     * do not use boot=on for drives when not using KVM since this
-     * is not supported at all in upstream QEmu.
-     */
-    if ((qemuCmdFlags & QEMUD_CMD_FLAG_KVM) &&
-        (def->virtType == VIR_DOMAIN_VIRT_QEMU) &&
-        (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT))
-        qemuCmdFlags -= QEMUD_CMD_FLAG_DRIVE_BOOT;
-
-    switch (def->virtType) {
-    case VIR_DOMAIN_VIRT_QEMU:
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU)
-            disableKQEMU = 1;
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_KVM)
-            disableKVM = 1;
-        break;
-
-    case VIR_DOMAIN_VIRT_KQEMU:
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_KVM)
-            disableKVM = 1;
-
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_ENABLE_KQEMU) {
-            enableKQEMU = 1;
-        } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU)) {
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                            _("the QEMU binary %s does not support kqemu"),
-                            emulator);
-        }
-        break;
-
-    case VIR_DOMAIN_VIRT_KVM:
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU)
-            disableKQEMU = 1;
-
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_ENABLE_KVM) {
-            enableKVM = 1;
-        } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_KVM)) {
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                            _("the QEMU binary %s does not support kvm"),
-                            emulator);
-        }
-        break;
-
-    case VIR_DOMAIN_VIRT_XEN:
-        /* XXX better check for xenner */
-        break;
-
-    default:
-        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                        _("the QEMU binary %s does not support %s"),
-                        emulator, virDomainVirtTypeToString(def->virtType));
-        break;
-    }
-
-    cmd = virCommandNewArgList(emulator, "-S", NULL);
-
-    virCommandAddEnvPassCommon(cmd);
-
-    /* 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)
-        virCommandAddArgList(cmd, "-M", def->os.machine, NULL);
-
-    if (qemuBuildCpuArgStr(driver, def, emulator, qemuCmdFlags,
-                           &ut, &cpu, &hasHwVirt) < 0)
-        goto error;
-
-    if (cpu) {
-        virCommandAddArgList(cmd, "-cpu", cpu, NULL);
-        VIR_FREE(cpu);
-
-        if ((qemuCmdFlags & QEMUD_CMD_FLAG_NESTING) &&
-            hasHwVirt)
-            virCommandAddArg(cmd, "-enable-nesting");
-    }
-
-    if (disableKQEMU)
-        virCommandAddArg(cmd, "-no-kqemu");
-    else if (enableKQEMU)
-        virCommandAddArgList(cmd, "-enable-kqemu", "-kernel-kqemu", NULL);
-    if (disableKVM)
-        virCommandAddArg(cmd, "-no-kvm");
-    if (enableKVM)
-        virCommandAddArg(cmd, "-enable-kvm");
-
-    /* Set '-m MB' based on maxmem, because the lower 'memory' limit
-     * is set post-startup using the balloon driver. If balloon driver
-     * is not supported, then they're out of luck anyway
-     */
-    virCommandAddArg(cmd, "-m");
-    virCommandAddArgFormat(cmd, "%lu", def->mem.max_balloon / 1024);
-    if (def->mem.hugepage_backed) {
-        if (!driver->hugetlbfs_mount) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            "%s", _("hugetlbfs filesystem is not mounted"));
-            goto error;
-        }
-        if (!driver->hugepage_path) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            "%s", _("hugepages are disabled by administrator config"));
-            goto error;
-        }
-        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_MEM_PATH)) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("hugepage backing not supported by '%s'"),
-                            def->emulator);
-            goto error;
-        }
-        virCommandAddArgList(cmd, "-mem-prealloc", "-mem-path",
-                             driver->hugepage_path, NULL);
-    }
-
-    virCommandAddArg(cmd, "-smp");
-    if (!(smp = qemuBuildSmpArgStr(def, qemuCmdFlags)))
-        goto error;
-    virCommandAddArg(cmd, smp);
-    VIR_FREE(smp);
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_NAME) {
-        virCommandAddArg(cmd, "-name");
-        if (driver->setProcessName &&
-            (qemuCmdFlags & QEMUD_CMD_FLAG_NAME_PROCESS)) {
-            virCommandAddArgFormat(cmd, "%s,process=qemu:%s",
-                                   def->name, def->name);
-        } else {
-            virCommandAddArg(cmd, def->name);
-        }
-    }
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_UUID)
-        virCommandAddArgList(cmd, "-uuid", uuid, NULL);
-    if (def->virtType == VIR_DOMAIN_VIRT_XEN ||
-        STREQ(def->os.type, "xen") ||
-        STREQ(def->os.type, "linux")) {
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_DOMID) {
-            virCommandAddArg(cmd, "-domid");
-            virCommandAddArgFormat(cmd, "%d", def->id);
-        } else if (qemuCmdFlags & QEMUD_CMD_FLAG_XEN_DOMID) {
-            virCommandAddArg(cmd, "-xen-attach");
-            virCommandAddArg(cmd, "-xen-domid");
-            virCommandAddArgFormat(cmd, "%d", def->id);
-        } else {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("qemu emulator '%s' does not support xen"),
-                            def->emulator);
-            goto error;
-        }
-    }
-
-    if ((def->os.smbios_mode != VIR_DOMAIN_SMBIOS_NONE) &&
-        (def->os.smbios_mode != VIR_DOMAIN_SMBIOS_EMULATE)) {
-        virSysinfoDefPtr source = NULL;
-        bool skip_uuid = false;
-
-        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_SMBIOS_TYPE)) {
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                    _("the QEMU binary %s does not support smbios settings"),
-                            emulator);
-            goto error;
-        }
-
-        /* should we really error out or just warn in those cases ? */
-        if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) {
-            if (driver->hostsysinfo == NULL) {
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                            _("Host SMBIOS information is not available"));
-                goto error;
-            }
-            source = driver->hostsysinfo;
-            /* Host and guest uuid must differ, by definition of UUID. */
-            skip_uuid = true;
-        } else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_SYSINFO) {
-            if (def->sysinfo == NULL) {
-                qemuReportError(VIR_ERR_XML_ERROR,
-                            _("Domain '%s' sysinfo are not available"),
-                               def->name);
-                goto error;
-            }
-            source = def->sysinfo;
-            /* domain_conf guaranteed that system_uuid matches guest uuid. */
-        }
-        if (source != NULL) {
-            char *smbioscmd;
-
-            smbioscmd = qemuBuildSmbiosBiosStr(source);
-            if (smbioscmd != NULL) {
-                virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
-                VIR_FREE(smbioscmd);
-            }
-            smbioscmd = qemuBuildSmbiosSystemStr(source, skip_uuid);
-            if (smbioscmd != NULL) {
-                virCommandAddArgList(cmd, "-smbios", smbioscmd, NULL);
-                VIR_FREE(smbioscmd);
-            }
-        }
-    }
-
-    /*
-     * NB, -nographic *MUST* come before any serial, or monitor
-     * or parallel port flags due to QEMU craziness, where it
-     * decides to change the serial port & monitor to be on stdout
-     * if you ask for nographic. So we have to make sure we override
-     * these defaults ourselves...
-     */
-    if (!def->graphics)
-        virCommandAddArg(cmd, "-nographic");
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_NODEFCONFIG)
-            virCommandAddArg(cmd,
-                             "-nodefconfig"); /* Disable global config files */
-        virCommandAddArg(cmd,
-                         "-nodefaults");  /* Disable default guest devices */
-    }
-
-    if (monitor_chr) {
-        char *chrdev;
-        /* Use -chardev if it's available */
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) {
-
-            virCommandAddArg(cmd, "-chardev");
-            if (!(chrdev = qemuBuildChrChardevStr(monitor_chr)))
-                goto error;
-            virCommandAddArg(cmd, chrdev);
-            VIR_FREE(chrdev);
-
-            virCommandAddArg(cmd, "-mon");
-            virCommandAddArgFormat(cmd, "chardev=monitor,mode=%s",
-                                   monitor_json ? "control" : "readline");
-        } else {
-            const char *prefix = NULL;
-            if (monitor_json)
-                prefix = "control,";
-
-            virCommandAddArg(cmd, "-monitor");
-            if (!(chrdev = qemuBuildChrArgStr(monitor_chr, prefix)))
-                goto error;
-            virCommandAddArg(cmd, chrdev);
-            VIR_FREE(chrdev);
-        }
-    }
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_RTC) {
-        const char *rtcopt;
-        virCommandAddArg(cmd, "-rtc");
-        if (!(rtcopt = qemuBuildClockArgStr(&def->clock)))
-            goto error;
-        virCommandAddArg(cmd, rtcopt);
-        VIR_FREE(rtcopt);
-    } else {
-        switch (def->clock.offset) {
-        case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
-        case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
-            virCommandAddArg(cmd, "-localtime");
-            break;
-
-        case VIR_DOMAIN_CLOCK_OFFSET_UTC:
-            /* Nothing, its the default */
-            break;
-
-        default:
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                            _("unsupported clock offset '%s'"),
-                            virDomainClockOffsetTypeToString(def->clock.offset));
-            goto error;
-        }
-    }
-    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_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) {
-        default:
-        case VIR_DOMAIN_TIMER_NAME_PLATFORM:
-        case VIR_DOMAIN_TIMER_NAME_TSC:
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                            _("unsupported timer type (name) '%s'"),
-                            virDomainTimerNameTypeToString(def->clock.timers[i]->name));
-            goto error;
-
-        case VIR_DOMAIN_TIMER_NAME_RTC:
-            /* This has already been taken care of (in qemuBuildClockArgStr)
-               if QEMUD_CMD_FLAG_RTC is set (mutually exclusive with
-               QEMUD_FLAG_RTC_TD_HACK) */
-            if (qemuCmdFlags & QEMUD_CMD_FLAG_RTC_TD_HACK) {
-                switch (def->clock.timers[i]->tickpolicy) {
-                case -1:
-                case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
-                    /* the default - do nothing */
-                    break;
-                case VIR_DOMAIN_TIMER_TICKPOLICY_CATCHUP:
-                    virCommandAddArg(cmd, "-rtc-td-hack");
-                    break;
-                case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
-                case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
-                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                    _("unsupported rtc tickpolicy '%s'"),
-                                    virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
-                goto error;
-                }
-            } else if (!(qemuCmdFlags & QEMUD_CMD_FLAG_RTC)
-                       && (def->clock.timers[i]->tickpolicy
-                           != VIR_DOMAIN_TIMER_TICKPOLICY_DELAY)
-                       && (def->clock.timers[i]->tickpolicy != -1)) {
-                /* a non-default rtc policy was given, but there is no
-                   way to implement it in this version of qemu */
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                _("unsupported rtc tickpolicy '%s'"),
-                                virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
-                goto error;
-            }
-            break;
-
-        case VIR_DOMAIN_TIMER_NAME_PIT:
-            switch (def->clock.timers[i]->tickpolicy) {
-            case -1:
-            case VIR_DOMAIN_TIMER_TICKPOLICY_DELAY:
-                /* 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)
-                    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. */
-                    virCommandAddArg(cmd, "-tdf");
-                } else {
-                    /* can't catchup if we have neither pit mode */
-                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                    _("unsupported pit tickpolicy '%s'"),
-                                    virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
-                    goto error;
-                }
-                break;
-            case VIR_DOMAIN_TIMER_TICKPOLICY_MERGE:
-            case VIR_DOMAIN_TIMER_TICKPOLICY_DISCARD:
-                /* no way to support these modes for pit in qemu */
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                _("unsupported pit tickpolicy '%s'"),
-                                virDomainTimerTickpolicyTypeToString(def->clock.timers[i]->tickpolicy));
-                goto error;
-            }
-            break;
-
-        case VIR_DOMAIN_TIMER_NAME_HPET:
-            /* the only meaningful attribute for hpet is "present". If
-             * present is -1, that means it wasn't specified, and
-             * should be left at the default for the
-             * hypervisor. "default" when -no-hpet exists is "yes",
-             * and when -no-hpet doesn't exist is "no". "confusing"?
-             * "yes"! */
-
-            if (qemuCmdFlags & QEMUD_CMD_FLAG_NO_HPET) {
-                if (def->clock.timers[i]->present == 0)
-                    virCommandAddArg(cmd, "-no-hpet");
-            } else {
-                /* no hpet timer available. The only possible action
-                   is to raise an error if present="yes" */
-                if (def->clock.timers[i]->present == 1) {
-                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                    "%s", _("pit timer is not supported"));
-                }
-            }
-            break;
-        }
-    }
-
-    if ((qemuCmdFlags & QEMUD_CMD_FLAG_NO_REBOOT) &&
-        def->onReboot != VIR_DOMAIN_LIFECYCLE_RESTART)
-        virCommandAddArg(cmd, "-no-reboot");
-
-    if (!(def->features & (1 << VIR_DOMAIN_FEATURE_ACPI)))
-        virCommandAddArg(cmd, "-no-acpi");
-
-    if (!def->os.bootloader) {
-        for (i = 0 ; i < def->os.nBootDevs ; i++) {
-            switch (def->os.bootDevs[i]) {
-            case VIR_DOMAIN_BOOT_CDROM:
-                boot[i] = 'd';
-                break;
-            case VIR_DOMAIN_BOOT_FLOPPY:
-                boot[i] = 'a';
-                break;
-            case VIR_DOMAIN_BOOT_DISK:
-                boot[i] = 'c';
-                break;
-            case VIR_DOMAIN_BOOT_NET:
-                boot[i] = 'n';
-                break;
-            default:
-                boot[i] = 'c';
-                break;
-            }
-        }
-        if (def->os.nBootDevs) {
-            virBuffer boot_buf = VIR_BUFFER_INITIALIZER;
-            virCommandAddArg(cmd, "-boot");
-
-            boot[def->os.nBootDevs] = '\0';
-
-            if (qemuCmdFlags & QEMUD_CMD_FLAG_BOOT_MENU &&
-                def->os.bootmenu != VIR_DOMAIN_BOOT_MENU_DEFAULT) {
-                if (def->os.bootmenu == VIR_DOMAIN_BOOT_MENU_ENABLED)
-                    virBufferVSprintf(&boot_buf, "order=%s,menu=on", boot);
-                else if (def->os.bootmenu == VIR_DOMAIN_BOOT_MENU_DISABLED)
-                    virBufferVSprintf(&boot_buf, "order=%s,menu=off", boot);
-            } else {
-                virBufferVSprintf(&boot_buf, "%s", boot);
-            }
-
-            virCommandAddArgBuffer(cmd, &boot_buf);
-        }
-
-        if (def->os.kernel)
-            virCommandAddArgList(cmd, "-kernel", def->os.kernel, NULL);
-        if (def->os.initrd)
-            virCommandAddArgList(cmd, "-initrd", def->os.initrd, NULL);
-        if (def->os.cmdline)
-            virCommandAddArgList(cmd, "-append", def->os.cmdline, NULL);
-    } else {
-        virCommandAddArgList(cmd, "-bootloader", def->os.bootloader, NULL);
-    }
-
-    for (i = 0 ; i < def->ndisks ; i++) {
-        virDomainDiskDefPtr disk = def->disks[i];
-
-        if (disk->driverName != NULL &&
-            !STREQ(disk->driverName, "qemu")) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("unsupported driver name '%s' for disk '%s'"),
-                            disk->driverName, disk->src);
-            goto error;
-        }
-    }
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-        for (i = 0 ; i < def->ncontrollers ; i++) {
-            virDomainControllerDefPtr cont = def->controllers[i];
-
-            /* We don't add an explicit IDE or FD controller because the
-             * provided PIIX4 device already includes one. It isn't possible to
-             * remove the PIIX4. */
-            if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE ||
-                cont->type == VIR_DOMAIN_CONTROLLER_TYPE_FDC)
-                continue;
-
-            /* QEMU doesn't implement a SATA driver */
-            if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_SATA) {
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                "%s", _("SATA is not supported with this QEMU binary"));
-                goto error;
-            }
-
-            virCommandAddArg(cmd, "-device");
-
-            char *devstr;
-            if (!(devstr = qemuBuildControllerDevStr(def->controllers[i])))
-                goto no_memory;
-
-            virCommandAddArg(cmd, devstr);
-            VIR_FREE(devstr);
-        }
-    }
-
-    /* If QEMU supports -drive param instead of old -hda, -hdb, -cdrom .. */
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE) {
-        int bootCD = 0, bootFloppy = 0, bootDisk = 0;
-
-        /* If QEMU supports boot=on for -drive param... */
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_DRIVE_BOOT) {
-            for (i = 0 ; i < def->os.nBootDevs ; i++) {
-                switch (def->os.bootDevs[i]) {
-                case VIR_DOMAIN_BOOT_CDROM:
-                    bootCD = 1;
-                    break;
-                case VIR_DOMAIN_BOOT_FLOPPY:
-                    bootFloppy = 1;
-                    break;
-                case VIR_DOMAIN_BOOT_DISK:
-                    bootDisk = 1;
-                    break;
-                }
-            }
-        }
-
-        for (i = 0 ; i < def->ndisks ; i++) {
-            char *optstr;
-            int bootable = 0;
-            virDomainDiskDefPtr disk = def->disks[i];
-            int withDeviceArg = 0;
-            int j;
-
-            /* Unless we have -device, then USB disks need special
-               handling */
-            if ((disk->bus == VIR_DOMAIN_DISK_BUS_USB) &&
-                !(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
-                    virCommandAddArg(cmd, "-usbdevice");
-                    virCommandAddArgFormat(cmd, "disk:%s", disk->src);
-                } else {
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                    _("unsupported usb disk type for '%s'"),
-                                    disk->src);
-                    goto error;
-                }
-                continue;
-            }
-
-            switch (disk->device) {
-            case VIR_DOMAIN_DISK_DEVICE_CDROM:
-                bootable = bootCD;
-                bootCD = 0;
-                break;
-            case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
-                bootable = bootFloppy;
-                bootFloppy = 0;
-                break;
-            case VIR_DOMAIN_DISK_DEVICE_DISK:
-                bootable = bootDisk;
-                bootDisk = 0;
-                break;
-            }
-
-            virCommandAddArg(cmd, "-drive");
-
-            /* Unfortunately it is not possible to use
-               -device for floppies, or Xen paravirt
-               devices. Fortunately, those don't need
-               static PCI addresses, so we don't really
-               care that we can't use -device */
-            if ((qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
-                (disk->bus != VIR_DOMAIN_DISK_BUS_XEN))
-                withDeviceArg = 1;
-            if (!(optstr = qemuBuildDriveStr(disk, bootable,
-                                             (withDeviceArg ? qemuCmdFlags :
-                                              (qemuCmdFlags & ~QEMUD_CMD_FLAG_DEVICE)))))
-                goto error;
-            virCommandAddArg(cmd, optstr);
-            VIR_FREE(optstr);
-
-            if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
-                disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
-                for (j = 0 ; j < disk->nhosts ; j++) {
-                    if (!has_rbd_hosts) {
-                        virBufferAddLit(&rbd_hosts, "CEPH_ARGS=-m ");
-                        has_rbd_hosts = true;
-                    } else {
-                        virBufferAddLit(&rbd_hosts, ",");
-                    }
-                    virDomainDiskHostDefPtr host = &disk->hosts[j];
-                    if (host->port) {
-                        virBufferVSprintf(&rbd_hosts, "%s:%s",
-                                          host->name,
-                                          host->port);
-                    } else {
-                        virBufferVSprintf(&rbd_hosts, "%s",
-                                          host->name);
-                    }
-                }
-            }
-
-            if (withDeviceArg) {
-                if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
-                    virCommandAddArg(cmd, "-global");
-                    virCommandAddArgFormat(cmd, "isa-fdc.drive%c=drive-%s",
-                                           disk->info.addr.drive.unit
-                                           ? 'B' : 'A',
-                                           disk->info.alias);
-                } else {
-                    virCommandAddArg(cmd, "-device");
-
-                    if (!(optstr = qemuBuildDriveDevStr(disk)))
-                        goto error;
-                    virCommandAddArg(cmd, optstr);
-                    VIR_FREE(optstr);
-                }
-            }
-        }
-    } else {
-        for (i = 0 ; i < def->ndisks ; i++) {
-            char dev[NAME_MAX];
-            char file[PATH_MAX];
-            virDomainDiskDefPtr disk = def->disks[i];
-            int j;
-
-            if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
-                if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
-                    virCommandAddArg(cmd, "-usbdevice");
-                    virCommandAddArgFormat(cmd, "disk:%s", disk->src);
-                } else {
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                    _("unsupported usb disk type for '%s'"),
-                                    disk->src);
-                    goto error;
-                }
-                continue;
-            }
-
-            if (STREQ(disk->dst, "hdc") &&
-                disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
-                if (disk->src) {
-                    snprintf(dev, NAME_MAX, "-%s", "cdrom");
-                } else {
-                    continue;
-                }
-            } else {
-                if (STRPREFIX(disk->dst, "hd") ||
-                    STRPREFIX(disk->dst, "fd")) {
-                    snprintf(dev, NAME_MAX, "-%s", disk->dst);
-                } else {
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                    _("unsupported disk type '%s'"), disk->dst);
-                    goto error;
-                }
-            }
-
-            if (disk->type == VIR_DOMAIN_DISK_TYPE_DIR) {
-                /* QEMU only supports magic FAT format for now */
-                if (disk->driverType &&
-                    STRNEQ(disk->driverType, "fat")) {
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                    _("unsupported disk driver type for '%s'"),
-                                    disk->driverType);
-                    goto error;
-                }
-                if (!disk->readonly) {
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                    _("cannot create virtual FAT disks in read-write mode"));
-                    goto error;
-                }
-                if (disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
-                    snprintf(file, PATH_MAX, "fat:floppy:%s", disk->src);
-                else
-                    snprintf(file, PATH_MAX, "fat:%s", disk->src);
-            } else if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
-                switch (disk->protocol) {
-                case VIR_DOMAIN_DISK_PROTOCOL_NBD:
-                    if (disk->nhosts != 1) {
-                        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                                        _("NBD accepts only one host"));
-                        goto error;
-                    }
-                    snprintf(file, PATH_MAX, "nbd:%s:%s,",
-                             disk->hosts->name, disk->hosts->port);
-                    break;
-                case VIR_DOMAIN_DISK_PROTOCOL_RBD:
-                    snprintf(file, PATH_MAX, "rbd:%s,", disk->src);
-                    for (j = 0 ; j < disk->nhosts ; j++) {
-                        if (!has_rbd_hosts) {
-                            virBufferAddLit(&rbd_hosts, "CEPH_ARGS=-m ");
-                            has_rbd_hosts = true;
-                        } else {
-                            virBufferAddLit(&rbd_hosts, ",");
-                        }
-                        virDomainDiskHostDefPtr host = &disk->hosts[j];
-                        if (host->port) {
-                            virBufferVSprintf(&rbd_hosts, "%s:%s",
-                                              host->name,
-                                              host->port);
-                        } else {
-                            virBufferVSprintf(&rbd_hosts, "%s",
-                                              host->name);
-                        }
-                    }
-                    break;
-                case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
-                    if (disk->nhosts == 0)
-                        snprintf(file, PATH_MAX, "sheepdog:%s,", disk->src);
-                    else
-                        /* only one host is supported now */
-                        snprintf(file, PATH_MAX, "sheepdog:%s:%s:%s,",
-                                 disk->hosts->name, disk->hosts->port,
-                                 disk->src);
-                    break;
-                }
-            } else {
-                snprintf(file, PATH_MAX, "%s", disk->src);
-            }
-
-            virCommandAddArgList(cmd, dev, file, NULL);
-        }
-    }
-
-    if (has_rbd_hosts)
-        virCommandAddEnvBuffer(cmd, &rbd_hosts);
-
-    if (qemuCmdFlags & QEMUD_CMD_FLAG_FSDEV) {
-        for (i = 0 ; i < def->nfss ; i++) {
-            char *optstr;
-            virDomainFSDefPtr fs = def->fss[i];
-
-            virCommandAddArg(cmd, "-fsdev");
-            if (!(optstr = qemuBuildFSStr(fs, qemuCmdFlags)))
-                goto error;
-            virCommandAddArg(cmd, optstr);
-            VIR_FREE(optstr);
-
-            virCommandAddArg(cmd, "-device");
-            if (!(optstr = qemuBuildFSDevStr(fs)))
-                goto error;
-            virCommandAddArg(cmd, optstr);
-            VIR_FREE(optstr);
-        }
-    } else {
-        if (def->nfss) {
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                            _("filesystem passthrough not supported by this QEMU"));
-            goto error;
-        }
-    }
-
-    if (!def->nnets) {
-        /* If we have -device, then we set -nodefault already */
-        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
-            virCommandAddArgList(cmd, "-net", "none", NULL);
-    } else {
-        for (i = 0 ; i < def->nnets ; i++) {
-            virDomainNetDefPtr net = def->nets[i];
-            char *nic, *host;
-            char tapfd_name[50];
-            char vhostfd_name[50] = "";
-            int vlan;
-
-            /* VLANs are not used with -netdev, so don't record them */
-            if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
-                (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
-                vlan = -1;
-            else
-                vlan = i;
-
-            if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
-                net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
-                int tapfd = qemudNetworkIfaceConnect(conn, driver, net,
-                                                     qemuCmdFlags);
-                if (tapfd < 0)
-                    goto error;
-
-                last_good_net = i;
-                virCommandTransferFD(cmd, tapfd);
-
-                if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
-                             tapfd) >= sizeof(tapfd_name))
-                    goto no_memory;
-            } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
-                int tapfd = qemudPhysIfaceConnect(conn, driver, net,
-                                                  qemuCmdFlags,
-                                                  def->uuid,
-                                                  vmop);
-                if (tapfd < 0)
-                    goto error;
-
-                last_good_net = i;
-                virCommandTransferFD(cmd, tapfd);
-
-                if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
-                             tapfd) >= sizeof(tapfd_name))
-                    goto no_memory;
-            }
-
-            if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK ||
-                net->type == VIR_DOMAIN_NET_TYPE_BRIDGE ||
-                net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
-                /* Attempt to use vhost-net mode for these types of
-                   network device */
-                int vhostfd = qemudOpenVhostNet(net, qemuCmdFlags);
-                if (vhostfd >= 0) {
-                    virCommandTransferFD(cmd, vhostfd);
-
-                    if (snprintf(vhostfd_name, sizeof(vhostfd_name), "%d",
-                                 vhostfd) >= sizeof(vhostfd_name))
-                        goto no_memory;
-                }
-            }
-            /* Possible combinations:
-             *
-             *  1. Old way:   -net nic,model=e1000,vlan=1 -net tap,vlan=1
-             *  2. Semi-new:  -device e1000,vlan=1        -net tap,vlan=1
-             *  3. Best way:  -netdev type=tap,id=netdev1 -device e1000,id=netdev1
-             *
-             * NB, no support for -netdev without use of -device
-             */
-            if ((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
-                (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                virCommandAddArg(cmd, "-netdev");
-                if (!(host = qemuBuildHostNetStr(net, ',', vlan,
-                                                 tapfd_name, vhostfd_name)))
-                    goto error;
-                virCommandAddArg(cmd, host);
-                VIR_FREE(host);
-            }
-            if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-                virCommandAddArg(cmd, "-device");
-                if (!(nic = qemuBuildNicDevStr(net, vlan)))
-                    goto error;
-                virCommandAddArg(cmd, nic);
-                VIR_FREE(nic);
-            } else {
-                virCommandAddArg(cmd, "-net");
-                if (!(nic = qemuBuildNicStr(net, "nic,", vlan)))
-                    goto error;
-                virCommandAddArg(cmd, nic);
-                VIR_FREE(nic);
-            }
-            if (!((qemuCmdFlags & QEMUD_CMD_FLAG_NETDEV) &&
-                  (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))) {
-                virCommandAddArg(cmd, "-net");
-                if (!(host = qemuBuildHostNetStr(net, ',', vlan,
-                                                 tapfd_name, vhostfd_name)))
-                    goto error;
-                virCommandAddArg(cmd, host);
-                VIR_FREE(host);
-            }
-        }
-    }
-
-    if (!def->nserials) {
-        /* If we have -device, then we set -nodefault already */
-        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
-            virCommandAddArgList(cmd, "-serial", "none", NULL);
-    } else {
-        for (i = 0 ; i < def->nserials ; i++) {
-            virDomainChrDefPtr serial = def->serials[i];
-            char *devstr;
-
-            /* Use -chardev with -device if they are available */
-            if ((qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) &&
-                (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                virCommandAddArg(cmd, "-chardev");
-                if (!(devstr = qemuBuildChrChardevStr(serial)))
-                    goto error;
-                virCommandAddArg(cmd, devstr);
-                VIR_FREE(devstr);
-
-                virCommandAddArg(cmd, "-device");
-                virCommandAddArgFormat(cmd, "isa-serial,chardev=%s",
-                                       serial->info.alias);
-            } else {
-                virCommandAddArg(cmd, "-serial");
-                if (!(devstr = qemuBuildChrArgStr(serial, NULL)))
-                    goto error;
-                virCommandAddArg(cmd, devstr);
-                VIR_FREE(devstr);
-            }
-        }
-    }
-
-    if (!def->nparallels) {
-        /* If we have -device, then we set -nodefault already */
-        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
-            virCommandAddArgList(cmd, "-parallel", "none", NULL);
-    } else {
-        for (i = 0 ; i < def->nparallels ; i++) {
-            virDomainChrDefPtr parallel = def->parallels[i];
-            char *devstr;
-
-            /* Use -chardev with -device if they are available */
-            if ((qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) &&
-                (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                virCommandAddArg(cmd, "-chardev");
-                if (!(devstr = qemuBuildChrChardevStr(parallel)))
-                    goto error;
-                virCommandAddArg(cmd, devstr);
-                VIR_FREE(devstr);
-
-                virCommandAddArg(cmd, "-device");
-                virCommandAddArgFormat(cmd, "isa-parallel,chardev=%s",
-                                       parallel->info.alias);
-            } else {
-                virCommandAddArg(cmd, "-parallel");
-                if (!(devstr = qemuBuildChrArgStr(parallel, NULL)))
-                      goto error;
-                virCommandAddArg(cmd, devstr);
-                VIR_FREE(devstr);
-            }
-        }
-    }
-
-    for (i = 0 ; i < def->nchannels ; i++) {
-        virDomainChrDefPtr channel = def->channels[i];
-        char *devstr;
-
-        switch(channel->targetType) {
-        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_GUESTFWD:
-            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_CHARDEV) ||
-                !(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                "%s", _("guestfwd requires QEMU to support -chardev & -device"));
-                goto error;
-            }
-
-            virCommandAddArg(cmd, "-chardev");
-            if (!(devstr = qemuBuildChrChardevStr(channel)))
-                goto error;
-            virCommandAddArg(cmd, devstr);
-            VIR_FREE(devstr);
-
-            char *addr = virSocketFormatAddr(channel->target.addr);
-            if (!addr)
-                goto error;
-            int port = virSocketGetPort(channel->target.addr);
-
-            virCommandAddArg(cmd, "-netdev");
-            virCommandAddArgFormat(cmd,
-                                   "user,guestfwd=tcp:%s:%i,chardev=%s,id=user-%s",
-                                   addr, port, channel->info.alias,
-                                   channel->info.alias);
-            VIR_FREE(addr);
-            break;
-
-        case VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO:
-            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                    _("virtio channel requires QEMU to support -device"));
-                goto error;
-            }
-
-            virCommandAddArg(cmd, "-chardev");
-            if (!(devstr = qemuBuildChrChardevStr(channel)))
-                goto error;
-            virCommandAddArg(cmd, devstr);
-            VIR_FREE(devstr);
-
-            virCommandAddArg(cmd, "-device");
-            if (!(devstr = qemuBuildVirtioSerialPortDevStr(channel)))
-                goto error;
-            virCommandAddArg(cmd, devstr);
-            VIR_FREE(devstr);
-            break;
-        }
-    }
-
-    /* Explicit console devices */
-    if (def->console) {
-        virDomainChrDefPtr console = def->console;
-        char *devstr;
-
-        switch(console->targetType) {
-        case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_VIRTIO:
-            if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
-                qemuReportError(VIR_ERR_NO_SUPPORT, "%s",
-                    _("virtio channel requires QEMU to support -device"));
-                goto error;
-            }
-
-            virCommandAddArg(cmd, "-chardev");
-            if (!(devstr = qemuBuildChrChardevStr(console)))
-                goto error;
-            virCommandAddArg(cmd, devstr);
-            VIR_FREE(devstr);
-
-            virCommandAddArg(cmd, "-device");
-            if (!(devstr = qemuBuildVirtioSerialPortDevStr(console)))
-                goto error;
-            virCommandAddArg(cmd, devstr);
-            VIR_FREE(devstr);
-            break;
-
-        case VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL:
-            break;
-
-        default:
-            qemuReportError(VIR_ERR_NO_SUPPORT,
-                            _("unsupported console target type %s"),
-                            NULLSTR(virDomainChrConsoleTargetTypeToString(console->targetType)));
-            goto error;
-        }
-    }
-
-    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;
-                virCommandAddArg(cmd, "-device");
-                if (!(optstr = qemuBuildUSBInputDevStr(input)))
-                    goto error;
-                virCommandAddArg(cmd, optstr);
-                VIR_FREE(optstr);
-            } else {
-                virCommandAddArgList(cmd, "-usbdevice",
-                                     input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE
-                                     ? "mouse" : "tablet", NULL);
-            }
-        }
-    }
-
-    if (def->ngraphics > 1) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        "%s", _("only 1 graphics device is supported"));
-        goto error;
-    }
-
-    if ((def->ngraphics == 1) &&
-        def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
-        virBuffer opt = VIR_BUFFER_INITIALIZER;
-
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) {
-            if (def->graphics[0]->data.vnc.listenAddr)
-                virBufferAdd(&opt, def->graphics[0]->data.vnc.listenAddr, -1);
-            else if (driver->vncListen)
-                virBufferAdd(&opt, driver->vncListen, -1);
-
-            virBufferVSprintf(&opt, ":%d",
-                              def->graphics[0]->data.vnc.port - 5900);
-
-            if (def->graphics[0]->data.vnc.auth.passwd ||
-                driver->vncPassword)
-                virBufferAddLit(&opt, ",password");
-
-            if (driver->vncTLS) {
-                virBufferAddLit(&opt, ",tls");
-                if (driver->vncTLSx509verify) {
-                    virBufferVSprintf(&opt, ",x509verify=%s",
-                                      driver->vncTLSx509certdir);
-                } else {
-                    virBufferVSprintf(&opt, ",x509=%s",
-                                      driver->vncTLSx509certdir);
-                }
-            }
-
-            if (driver->vncSASL) {
-                virBufferAddLit(&opt, ",sasl");
-
-                if (driver->vncSASLdir)
-                    virCommandAddEnvPair(cmd, "SASL_CONF_DIR",
-                                         driver->vncSASLdir);
-
-                /* TODO: Support ACLs later */
-            }
-        } else {
-            virBufferVSprintf(&opt, "%d",
-                              def->graphics[0]->data.vnc.port - 5900);
-        }
-
-        virCommandAddArg(cmd, "-vnc");
-        virCommandAddArgBuffer(cmd, &opt);
-        if (def->graphics[0]->data.vnc.keymap) {
-            virCommandAddArgList(cmd, "-k", def->graphics[0]->data.vnc.keymap,
-                                 NULL);
-        }
-
-        /* Unless user requested it, set the audio backend to none, to
-         * prevent it opening the host OS audio devices, since that causes
-         * security issues and might not work when using VNC.
-         */
-        if (driver->vncAllowHostAudio) {
-            virCommandAddEnvPass(cmd, "QEMU_AUDIO_DRV");
-        } else {
-            virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=none");
-        }
-    } else if ((def->ngraphics == 1) &&
-               def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
-        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.fullscreen)
-            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
-         */
-        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)
-            virCommandAddArg(cmd, "-sdl");
-
-    } else if ((def->ngraphics == 1) &&
-               def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
-        virBuffer opt = VIR_BUFFER_INITIALIZER;
-
-        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_SPICE)) {
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                            _("spice graphics are not supported with this QEMU"));
-            goto error;
-        }
-
-        virBufferVSprintf(&opt, "port=%u", def->graphics[0]->data.spice.port);
-
-        if (driver->spiceTLS && def->graphics[0]->data.spice.tlsPort != -1)
-            virBufferVSprintf(&opt, ",tls-port=%u", def->graphics[0]->data.spice.tlsPort);
-
-        if (def->graphics[0]->data.spice.listenAddr)
-            virBufferVSprintf(&opt, ",addr=%s", def->graphics[0]->data.spice.listenAddr);
-        else if (driver->spiceListen)
-            virBufferVSprintf(&opt, ",addr=%s", driver->spiceListen);
-
-        /* In the password case we set it via monitor command, to avoid
-         * making it visible on CLI, so there's no use of password=XXX
-         * in this bit of the code */
-        if (!def->graphics[0]->data.spice.auth.passwd &&
-            !driver->spicePassword)
-            virBufferAddLit(&opt, ",disable-ticketing");
-
-        if (driver->spiceTLS)
-            virBufferVSprintf(&opt, ",x509-dir=%s",
-                              driver->spiceTLSx509certdir);
-
-        for (i = 0 ; i < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST ; i++) {
-            int mode = def->graphics[0]->data.spice.channels[i];
-            switch (mode) {
-            case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
-                virBufferVSprintf(&opt, ",tls-channel=%s",
-                                  virDomainGraphicsSpiceChannelNameTypeToString(i));
-                break;
-            case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
-                virBufferVSprintf(&opt, ",plaintext-channel=%s",
-                                  virDomainGraphicsSpiceChannelNameTypeToString(i));
-                break;
-            }
-        }
-
-        virCommandAddArg(cmd, "-spice");
-        virCommandAddArgBuffer(cmd, &opt);
-        if (def->graphics[0]->data.spice.keymap)
-            virCommandAddArgList(cmd, "-k",
-                                 def->graphics[0]->data.spice.keymap, NULL);
-        /* SPICE includes native support for tunnelling audio, so we
-         * set the audio backend to point at SPICE's own driver
-         */
-        virCommandAddEnvString(cmd, "QEMU_AUDIO_DRV=spice");
-
-    } else if ((def->ngraphics == 1)) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                    _("unsupported graphics type '%s'"),
-                    virDomainGraphicsTypeToString(def->graphics[0]->type));
-        goto error;
-    }
-
-    if (def->nvideos > 0) {
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_VGA) {
-            if (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_XEN) {
-                /* nothing - vga has no effect on Xen pvfb */
-            } else {
-                if ((def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_QXL) &&
-                    !(qemuCmdFlags & QEMUD_CMD_FLAG_VGA_QXL)) {
-                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                                    _("This QEMU does not support QXL graphics adapters"));
-                    goto error;
-                }
-
-                const char *vgastr = qemuVideoTypeToString(def->videos[0]->type);
-                if (!vgastr || STREQ(vgastr, "")) {
-                    qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                    _("video type %s is not supported with QEMU"),
-                                    virDomainVideoTypeToString(def->videos[0]->type));
-                    goto error;
-                }
-
-                virCommandAddArgList(cmd, "-vga", vgastr, NULL);
-            }
-        } else {
-
-            switch (def->videos[0]->type) {
-            case VIR_DOMAIN_VIDEO_TYPE_VGA:
-                virCommandAddArg(cmd, "-std-vga");
-                break;
-
-            case VIR_DOMAIN_VIDEO_TYPE_VMVGA:
-                virCommandAddArg(cmd, "-vmwarevga");
-                break;
-
-            case VIR_DOMAIN_VIDEO_TYPE_XEN:
-            case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
-                /* No special args - this is the default */
-                break;
-
-            default:
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                _("video type %s is not supported with this QEMU"),
-                                virDomainVideoTypeToString(def->videos[0]->type));
-                goto error;
-            }
-        }
-
-        if (def->nvideos > 1) {
-            if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-                for (i = 1 ; i < def->nvideos ; i++) {
-                    char *str;
-                    if (def->videos[i]->type != VIR_DOMAIN_VIDEO_TYPE_QXL) {
-                        qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                        _("video type %s is only valid as primary video card"),
-                                        virDomainVideoTypeToString(def->videos[0]->type));
-                        goto error;
-                    }
-
-                    virCommandAddArg(cmd, "-device");
-
-                    if (!(str = qemuBuildVideoDevStr(def->videos[i])))
-                        goto error;
-
-                    virCommandAddArg(cmd, str);
-                    VIR_FREE(str);
-                }
-            } else {
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                                "%s", _("only one video card is currently supported"));
-                goto error;
-            }
-        }
-
-    } else {
-        /* If we have -device, then we set -nodefault already */
-        if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) &&
-            (qemuCmdFlags & QEMUD_CMD_FLAG_VGA) &&
-            (qemuCmdFlags & QEMUD_CMD_FLAG_VGA_NONE))
-            virCommandAddArgList(cmd, "-vga", "none", NULL);
-    }
-
-    /* Add sound hardware */
-    if (def->nsounds) {
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-            for (i = 0 ; i < def->nsounds ; i++) {
-                virDomainSoundDefPtr sound = def->sounds[i];
-                char *str = NULL;
-
-                /* Sadly pcspk device doesn't use -device syntax. Fortunately
-                 * 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) {
-                    virCommandAddArgList(cmd, "-soundhw", "pcspk", NULL);
-                } else {
-                    virCommandAddArg(cmd, "-device");
-
-                    if (!(str = qemuBuildSoundDevStr(sound)))
-                        goto error;
-
-                    virCommandAddArg(cmd, str);
-                    VIR_FREE(str);
-                }
-            }
-        } else {
-            int size = 100;
-            char *modstr;
-            if (VIR_ALLOC_N(modstr, size+1) < 0)
-                goto no_memory;
-
-            for (i = 0 ; i < def->nsounds && size > 0 ; i++) {
-                virDomainSoundDefPtr sound = def->sounds[i];
-                const char *model = virDomainSoundModelTypeToString(sound->model);
-                if (!model) {
-                    VIR_FREE(modstr);
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                    "%s", _("invalid sound model"));
-                    goto error;
-                }
-                strncat(modstr, model, size);
-                size -= strlen(model);
-                if (i < (def->nsounds - 1))
-                    strncat(modstr, ",", size--);
-            }
-            virCommandAddArgList(cmd, "-soundhw", modstr, NULL);
-            VIR_FREE(modstr);
-        }
-    }
-
-    /* Add watchdog hardware */
-    if (def->watchdog) {
-        virDomainWatchdogDefPtr watchdog = def->watchdog;
-        char *optstr;
-
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-            virCommandAddArg(cmd, "-device");
-
-            optstr = qemuBuildWatchdogDevStr(watchdog);
-            if (!optstr)
-                goto error;
-        } else {
-            virCommandAddArg(cmd, "-watchdog");
-
-            const char *model = virDomainWatchdogModelTypeToString(watchdog->model);
-            if (!model) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                "%s", _("missing watchdog model"));
-                goto error;
-            }
-
-            if (!(optstr = strdup(model)))
-                goto no_memory;
-        }
-        virCommandAddArg(cmd, optstr);
-        VIR_FREE(optstr);
-
-        int act = watchdog->action;
-        if (act == VIR_DOMAIN_WATCHDOG_ACTION_DUMP)
-            act = VIR_DOMAIN_WATCHDOG_ACTION_PAUSE;
-        const char *action = virDomainWatchdogActionTypeToString(act);
-        if (!action) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            "%s", _("invalid watchdog action"));
-            goto error;
-        }
-        virCommandAddArgList(cmd, "-watchdog-action", action, NULL);
-    }
-
-    /* Add host passthrough hardware */
-    for (i = 0 ; i < def->nhostdevs ; i++) {
-        virDomainHostdevDefPtr hostdev = def->hostdevs[i];
-        char *devstr;
-
-        /* USB */
-        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
-            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
-
-            if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-                virCommandAddArg(cmd, "-device");
-                if (!(devstr = qemuBuildUSBHostdevDevStr(hostdev)))
-                    goto error;
-                virCommandAddArg(cmd, devstr);
-                VIR_FREE(devstr);
-            } else {
-                virCommandAddArg(cmd, "-usbdevice");
-                if (!(devstr = qemuBuildUSBHostdevUsbDevStr(hostdev)))
-                    goto error;
-                virCommandAddArg(cmd, devstr);
-                VIR_FREE(devstr);
-            }
-        }
-
-        /* PCI */
-        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
-            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
-            if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-                char *configfd_name = NULL;
-                if (qemuCmdFlags & QEMUD_CMD_FLAG_PCI_CONFIGFD) {
-                    int configfd = qemudOpenPCIConfig(hostdev);
-
-                    if (configfd >= 0) {
-                        if (virAsprintf(&configfd_name, "%d", configfd) < 0) {
-                            VIR_FORCE_CLOSE(configfd);
-                            virReportOOMError();
-                            goto no_memory;
-                        }
-
-                        virCommandTransferFD(cmd, configfd);
-                    }
-                }
-                virCommandAddArg(cmd, "-device");
-                devstr = qemuBuildPCIHostdevDevStr(hostdev, configfd_name);
-                VIR_FREE(configfd_name);
-                if (!devstr)
-                    goto error;
-                virCommandAddArg(cmd, devstr);
-                VIR_FREE(devstr);
-            } else if (qemuCmdFlags & QEMUD_CMD_FLAG_PCIDEVICE) {
-                virCommandAddArg(cmd, "-pcidevice");
-                if (!(devstr = qemuBuildPCIHostdevPCIDevStr(hostdev)))
-                    goto error;
-                virCommandAddArg(cmd, devstr);
-                VIR_FREE(devstr);
-            } else {
-                qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
-                                _("PCI device assignment is not supported by this version of qemu"));
-                goto error;
-            }
-        }
-    }
-
-    if (migrateFrom)
-        virCommandAddArgList(cmd, "-incoming", migrateFrom, NULL);
-
-    /* QEMU changed its default behavior to not include the virtio balloon
-     * device.  Explicitly request it to ensure it will be present.
-     *
-     * NB: Earlier we declared that VirtIO balloon will always be in
-     * slot 0x3 on bus 0x0
-     */
-    if ((def->memballoon) &&
-        (def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
-        if (def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO) {
-            qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED,
-                            _("Memory balloon device type '%s' is not supported by this version of qemu"),
-                            virDomainMemballoonModelTypeToString(def->memballoon->model));
-            goto error;
-        }
-        if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
-            char *optstr;
-            virCommandAddArg(cmd, "-device");
-
-            optstr = qemuBuildMemballoonDevStr(def->memballoon);
-            if (!optstr)
-                goto error;
-            virCommandAddArg(cmd, optstr);
-            VIR_FREE(optstr);
-        } else if (qemuCmdFlags & QEMUD_CMD_FLAG_BALLOON) {
-            virCommandAddArgList(cmd, "-balloon", "virtio", NULL);
-        }
-    }
-
-    if (current_snapshot && current_snapshot->def->active)
-        virCommandAddArgList(cmd, "-loadvm", current_snapshot->def->name,
-                             NULL);
-
-    if (def->namespaceData) {
-        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++)
-            virCommandAddEnvPair(cmd, qemucmd->env_name[i],
-                                 qemucmd->env_value[i]
-                                 ? qemucmd->env_value[i] : "");
-    }
-
-    return cmd;
-
- no_memory:
-    virReportOOMError();
- error:
-    for (i = 0; i <= last_good_net; i++)
-        virDomainConfNWFilterTeardown(def->nets[i]);
-    virBufferFreeAndReset(&rbd_hosts);
-    virCommandFree(cmd);
-    return NULL;
-}
-
-
-/*
- * This method takes a string representing a QEMU command line ARGV set
- * optionally prefixed by a list of environment variables. It then tries
- * to split it up into a NULL terminated list of env & argv, splitting
- * on space
- */
-static int qemuStringToArgvEnv(const char *args,
-                               const char ***retenv,
-                               const char ***retargv)
-{
-    char **arglist = NULL;
-    int argcount = 0;
-    int argalloc = 0;
-    int envend;
-    int i;
-    const char *curr = args;
-    const char *start;
-    const char **progenv = NULL;
-    const char **progargv = NULL;
-
-    /* Iterate over string, splitting on sequences of ' ' */
-    while (curr && *curr != '\0') {
-        char *arg;
-        const char *next;
-
-        start = curr;
-        /* accept a space in CEPH_ARGS */
-        if (STRPREFIX(curr, "CEPH_ARGS=-m ")) {
-            start += strlen("CEPH_ARGS=-m ");
-        }
-        if (*start == '\'') {
-            if (start == curr)
-                curr++;
-            next = strchr(start + 1, '\'');
-        } else if (*start == '"') {
-            if (start == curr)
-                curr++;
-            next = strchr(start + 1, '"');
-        } else {
-            next = strchr(start, ' ');
-        }
-        if (!next)
-            next = strchr(curr, '\n');
-
-        if (next) {
-            arg = strndup(curr, next-curr);
-            if (*next == '\'' ||
-                *next == '"')
-                next++;
-        } else {
-            arg = strdup(curr);
-        }
-
-        if (!arg)
-            goto no_memory;
-
-        if (argalloc == argcount) {
-            if (VIR_REALLOC_N(arglist, argalloc+10) < 0) {
-                VIR_FREE(arg);
-                goto no_memory;
-            }
-            argalloc+=10;
-        }
-
-        arglist[argcount++] = arg;
-
-        while (next && c_isspace(*next))
-            next++;
-
-        curr = next;
-    }
-
-    /* Iterate over list of args, finding first arg not containing
-     * the '=' character (eg, skip over env vars FOO=bar) */
-    for (envend = 0 ; ((envend < argcount) &&
-                       (strchr(arglist[envend], '=') != NULL));
-         envend++)
-        ; /* nada */
-
-    /* Copy the list of env vars */
-    if (envend > 0) {
-        if (VIR_REALLOC_N(progenv, envend+1) < 0)
-            goto no_memory;
-        for (i = 0 ; i < envend ; i++) {
-            progenv[i] = arglist[i];
-            arglist[i] = NULL;
-        }
-        progenv[i] = NULL;
-    }
-
-    /* Copy the list of argv */
-    if (VIR_REALLOC_N(progargv, argcount-envend + 1) < 0)
-        goto no_memory;
-    for (i = envend ; i < argcount ; i++)
-        progargv[i-envend] = arglist[i];
-    progargv[i-envend] = NULL;
-
-    VIR_FREE(arglist);
-
-    *retenv = progenv;
-    *retargv = progargv;
-
-    return 0;
-
-no_memory:
-    for (i = 0 ; progenv && progenv[i] ; i++)
-        VIR_FREE(progenv[i]);
-    VIR_FREE(progenv);
-    for (i = 0 ; i < argcount ; i++)
-        VIR_FREE(arglist[i]);
-    VIR_FREE(arglist);
-    virReportOOMError();
-    return -1;
-}
-
-
-/*
- * Search for a named env variable, and return the value part
- */
-static const char *qemuFindEnv(const char **progenv,
-                               const char *name)
-{
-    int i;
-    int len = strlen(name);
-
-    for (i = 0 ; progenv && progenv[i] ; i++) {
-        if (STREQLEN(progenv[i], name, len) &&
-            progenv[i][len] == '=')
-            return progenv[i] + len + 1;
-    }
-    return NULL;
-}
-
-/*
- * Takes a string containing a set of key=value,key=value,key...
- * parameters and splits them up, returning two arrays with
- * the individual keys and values. If allowEmptyValue is nonzero,
- * the "=value" part is optional and if a key with no value is found,
- * NULL is be placed into corresponding place in retvalues.
- */
-int
-qemuParseKeywords(const char *str,
-                  char ***retkeywords,
-                  char ***retvalues,
-                  int allowEmptyValue)
-{
-    int keywordCount = 0;
-    int keywordAlloc = 0;
-    char **keywords = NULL;
-    char **values = NULL;
-    const char *start = str;
-    const char *end;
-    int i;
-
-    *retkeywords = NULL;
-    *retvalues = NULL;
-    end = start + strlen(str);
-
-    while (start) {
-        const char *separator;
-        const char *endmark;
-        char *keyword;
-        char *value = NULL;
-
-        if (!(endmark = strchr(start, ',')))
-            endmark = end;
-        if (!(separator = strchr(start, '=')))
-            separator = end;
-
-        if (separator >= endmark) {
-            if (!allowEmptyValue) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("malformed keyword arguments in '%s'"), str);
-                goto error;
-            }
-            separator = endmark;
-        }
-
-        if (!(keyword = strndup(start, separator - start)))
-            goto no_memory;
-
-        if (separator < endmark) {
-            separator++;
-            if (!(value = strndup(separator, endmark - separator))) {
-                VIR_FREE(keyword);
-                goto no_memory;
-            }
-        }
-
-        if (keywordAlloc == keywordCount) {
-            if (VIR_REALLOC_N(keywords, keywordAlloc + 10) < 0 ||
-                VIR_REALLOC_N(values, keywordAlloc + 10) < 0) {
-                VIR_FREE(keyword);
-                VIR_FREE(value);
-                goto no_memory;
-            }
-            keywordAlloc += 10;
-        }
-
-        keywords[keywordCount] = keyword;
-        values[keywordCount] = value;
-        keywordCount++;
-
-        start = endmark < end ? endmark + 1 : NULL;
-    }
-
-    *retkeywords = keywords;
-    *retvalues = values;
-
-    return keywordCount;
-
-no_memory:
-    virReportOOMError();
-error:
-    for (i = 0 ; i < keywordCount ; i++) {
-        VIR_FREE(keywords[i]);
-        VIR_FREE(values[i]);
-    }
-    VIR_FREE(keywords);
-    VIR_FREE(values);
-    return -1;
-}
-
-/*
- * Tries to parse new style QEMU -drive  args.
- *
- * eg -drive file=/dev/HostVG/VirtData1,if=ide,index=1
- *
- * Will fail if not using the 'index' keyword
- */
-static virDomainDiskDefPtr
-qemuParseCommandLineDisk(virCapsPtr caps,
-                         const char *val,
-                         int nvirtiodisk)
-{
-    virDomainDiskDefPtr def = NULL;
-    char **keywords;
-    char **values;
-    int nkeywords;
-    int i;
-    int idx = -1;
-    int busid = -1;
-    int unitid = -1;
-
-    if ((nkeywords = qemuParseKeywords(val,
-                                       &keywords,
-                                       &values, 0)) < 0)
-        return NULL;
-
-    if (VIR_ALLOC(def) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    def->bus = VIR_DOMAIN_DISK_BUS_IDE;
-    def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
-    def->type = VIR_DOMAIN_DISK_TYPE_FILE;
-
-    for (i = 0 ; i < nkeywords ; i++) {
-        if (STREQ(keywords[i], "file")) {
-            if (values[i] && STRNEQ(values[i], "")) {
-                def->src = values[i];
-                values[i] = NULL;
-                if (STRPREFIX(def->src, "/dev/"))
-                    def->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
-                else if (STRPREFIX(def->src, "nbd:")) {
-                    char *host, *port;
-
-                    def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
-                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
-                    host = def->src + strlen("nbd:");
-                    port = strchr(host, ':');
-                    if (!port) {
-                        def = NULL;
-                        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                        _("cannot parse nbd filename '%s'"), def->src);
-                        goto cleanup;
-                    }
-                    *port++ = '\0';
-                    if (VIR_ALLOC(def->hosts) < 0) {
-                        virReportOOMError();
-                        goto cleanup;
-                    }
-                    def->nhosts = 1;
-                    def->hosts->name = strdup(host);
-                    if (!def->hosts->name) {
-                        virReportOOMError();
-                        goto cleanup;
-                    }
-                    def->hosts->port = strdup(port);
-                    if (!def->hosts->port) {
-                        virReportOOMError();
-                        goto cleanup;
-                    }
-
-                    VIR_FREE(def->src);
-                    def->src = NULL;
-                } else if (STRPREFIX(def->src, "rbd:")) {
-                    char *p = def->src;
-
-                    def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
-                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
-                    def->src = strdup(p + strlen("rbd:"));
-                    if (!def->src) {
-                        virReportOOMError();
-                        goto cleanup;
-                    }
-
-                    VIR_FREE(p);
-                } else if (STRPREFIX(def->src, "sheepdog:")) {
-                    char *p = def->src;
-                    char *port, *vdi;
-
-                    def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
-                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
-                    def->src = strdup(p + strlen("sheepdog:"));
-                    if (!def->src) {
-                        virReportOOMError();
-                        goto cleanup;
-                    }
-
-                    /* def->src must be [vdiname] or [host]:[port]:[vdiname] */
-                    port = strchr(def->src, ':');
-                    if (port) {
-                        *port++ = '\0';
-                        vdi = strchr(port, ':');
-                        if (!vdi) {
-                            def = NULL;
-                            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                            _("cannot parse sheepdog filename '%s'"), p);
-                            goto cleanup;
-                        }
-                        *vdi++ = '\0';
-                        if (VIR_ALLOC(def->hosts) < 0) {
-                            virReportOOMError();
-                            goto cleanup;
-                        }
-                        def->nhosts = 1;
-                        def->hosts->name = def->src;
-                        def->hosts->port = strdup(port);
-                        if (!def->hosts->port) {
-                            virReportOOMError();
-                            goto cleanup;
-                        }
-                        def->src = strdup(vdi);
-                        if (!def->src) {
-                            virReportOOMError();
-                            goto cleanup;
-                        }
-                    }
-
-                    VIR_FREE(p);
-                } else
-                    def->type = VIR_DOMAIN_DISK_TYPE_FILE;
-            } else {
-                def->type = VIR_DOMAIN_DISK_TYPE_FILE;
-            }
-        } else if (STREQ(keywords[i], "if")) {
-            if (STREQ(values[i], "ide"))
-                def->bus = VIR_DOMAIN_DISK_BUS_IDE;
-            else if (STREQ(values[i], "scsi"))
-                def->bus = VIR_DOMAIN_DISK_BUS_SCSI;
-            else if (STREQ(values[i], "virtio"))
-                def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
-            else if (STREQ(values[i], "xen"))
-                def->bus = VIR_DOMAIN_DISK_BUS_XEN;
-        } else if (STREQ(keywords[i], "media")) {
-            if (STREQ(values[i], "cdrom")) {
-                def->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
-                def->readonly = 1;
-            } else if (STREQ(values[i], "floppy"))
-                def->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
-        } else if (STREQ(keywords[i], "format")) {
-            def->driverName = strdup("qemu");
-            if (!def->driverName) {
-                virDomainDiskDefFree(def);
-                def = NULL;
-                virReportOOMError();
-                goto cleanup;
-            }
-            def->driverType = values[i];
-            values[i] = NULL;
-        } else if (STREQ(keywords[i], "cache")) {
-            if (STREQ(values[i], "off") ||
-                STREQ(values[i], "none"))
-                def->cachemode = VIR_DOMAIN_DISK_CACHE_DISABLE;
-            else if (STREQ(values[i], "writeback") ||
-                     STREQ(values[i], "on"))
-                def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITEBACK;
-            else if (STREQ(values[i], "writethrough"))
-                def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITETHRU;
-        } else if (STREQ(keywords[i], "werror") ||
-                   STREQ(keywords[i], "rerror")) {
-            if (STREQ(values[i], "stop"))
-                def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_STOP;
-            else if (STREQ(values[i], "ignore"))
-                def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_IGNORE;
-            else if (STREQ(values[i], "enospace"))
-                def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE;
-        } else if (STREQ(keywords[i], "index")) {
-            if (virStrToLong_i(values[i], NULL, 10, &idx) < 0) {
-                virDomainDiskDefFree(def);
-                def = NULL;
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("cannot parse drive index '%s'"), val);
-                goto cleanup;
-            }
-        } else if (STREQ(keywords[i], "bus")) {
-            if (virStrToLong_i(values[i], NULL, 10, &busid) < 0) {
-                virDomainDiskDefFree(def);
-                def = NULL;
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("cannot parse drive bus '%s'"), val);
-                goto cleanup;
-            }
-        } else if (STREQ(keywords[i], "unit")) {
-            if (virStrToLong_i(values[i], NULL, 10, &unitid) < 0) {
-                virDomainDiskDefFree(def);
-                def = NULL;
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("cannot parse drive unit '%s'"), val);
-                goto cleanup;
-            }
-        } else if (STREQ(keywords[i], "readonly")) {
-            if ((values[i] == NULL) || STREQ(values[i], "on"))
-                def->readonly = 1;
-        }
-    }
-
-    if (!def->src &&
-        def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
-        def->type != VIR_DOMAIN_DISK_TYPE_NETWORK) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("missing file parameter in drive '%s'"), val);
-        virDomainDiskDefFree(def);
-        def = NULL;
-        goto cleanup;
-    }
-    if (idx == -1 &&
-        def->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
-        idx = nvirtiodisk;
-
-    if (idx == -1 &&
-        unitid == -1 &&
-        busid == -1) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("missing index/unit/bus parameter in drive '%s'"), val);
-        virDomainDiskDefFree(def);
-        def = NULL;
-        goto cleanup;
-    }
-
-    if (idx == -1) {
-        if (unitid == -1)
-            unitid = 0;
-        if (busid == -1)
-            busid = 0;
-        switch (def->bus) {
-        case VIR_DOMAIN_DISK_BUS_IDE:
-            idx = (busid * 2) + unitid;
-            break;
-        case VIR_DOMAIN_DISK_BUS_SCSI:
-            idx = (busid * 7) + unitid;
-            break;
-        default:
-            idx = unitid;
-            break;
-        }
-    }
-
-    if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
-        def->dst = strdup("hda");
-    } else if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
-        def->dst = strdup("sda");
-    } else if (def->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
-        def->dst = strdup("vda");
-    } else if (def->bus == VIR_DOMAIN_DISK_BUS_XEN) {
-        def->dst = strdup("xvda");
-    } else {
-        def->dst = strdup("hda");
-    }
-
-    if (!def->dst) {
-        virDomainDiskDefFree(def);
-        def = NULL;
-        virReportOOMError();
-        goto cleanup;
-    }
-    if (STREQ(def->dst, "xvda"))
-        def->dst[3] = 'a' + idx;
-    else
-        def->dst[2] = 'a' + idx;
-
-    if (virDomainDiskDefAssignAddress(caps, def) < 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("invalid device name '%s'"), def->dst);
-        virDomainDiskDefFree(def);
-        def = NULL;
-        /* fall through to "cleanup" */
-    }
-
-cleanup:
-    for (i = 0 ; i < nkeywords ; i++) {
-        VIR_FREE(keywords[i]);
-        VIR_FREE(values[i]);
-    }
-    VIR_FREE(keywords);
-    VIR_FREE(values);
-    return def;
-}
-
-/*
- * Tries to find a NIC definition matching a vlan we want
- */
-static const char *
-qemuFindNICForVLAN(int nnics,
-                   const char **nics,
-                   int wantvlan)
-{
-    int i;
-    for (i = 0 ; i < nnics ; i++) {
-        int gotvlan;
-        const char *tmp = strstr(nics[i], "vlan=");
-        char *end;
-        if (!tmp)
-            continue;
-
-        tmp += strlen("vlan=");
-
-        if (virStrToLong_i(tmp, &end, 10, &gotvlan) < 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("cannot parse NIC vlan in '%s'"), nics[i]);
-            return NULL;
-        }
-
-        if (gotvlan == wantvlan)
-            return nics[i];
-    }
-
-    if (wantvlan == 0 && nnics > 0)
-        return nics[0];
-
-    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                    _("cannot find NIC definition for vlan %d"), wantvlan);
-    return NULL;
-}
-
-
-/*
- * Tries to parse a QEMU -net backend argument. Gets given
- * a list of all known -net frontend arguments to try and
- * match up against. Horribly complicated stuff
- */
-static virDomainNetDefPtr
-qemuParseCommandLineNet(virCapsPtr caps,
-                        const char *val,
-                        int nnics,
-                        const char **nics)
-{
-    virDomainNetDefPtr def = NULL;
-    char **keywords = NULL;
-    char **values = NULL;
-    int nkeywords;
-    const char *nic;
-    int wantvlan = 0;
-    const char *tmp;
-    int genmac = 1;
-    int i;
-
-    tmp = strchr(val, ',');
-
-    if (tmp) {
-        if ((nkeywords = qemuParseKeywords(tmp+1,
-                                           &keywords,
-                                           &values, 0)) < 0)
-            return NULL;
-    } else {
-        nkeywords = 0;
-    }
-
-    if (VIR_ALLOC(def) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    /* 'tap' could turn into libvirt type=ethernet, type=bridge or
-     * type=network, but we can't tell, so use the generic config */
-    if (STRPREFIX(val, "tap,"))
-        def->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
-    else if (STRPREFIX(val, "socket"))
-        def->type = VIR_DOMAIN_NET_TYPE_CLIENT;
-    else if (STRPREFIX(val, "user"))
-        def->type = VIR_DOMAIN_NET_TYPE_USER;
-    else
-        def->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
-
-    for (i = 0 ; i < nkeywords ; i++) {
-        if (STREQ(keywords[i], "vlan")) {
-            if (virStrToLong_i(values[i], NULL, 10, &wantvlan) < 0) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("cannot parse vlan in '%s'"), val);
-                virDomainNetDefFree(def);
-                def = NULL;
-                goto cleanup;
-            }
-        } else if (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
-                   STREQ(keywords[i], "script") && STRNEQ(values[i], "")) {
-            def->data.ethernet.script = values[i];
-            values[i] = NULL;
-        } else if (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
-                   STREQ(keywords[i], "ifname")) {
-            def->ifname = values[i];
-            values[i] = NULL;
-        }
-    }
-
-
-    /* Done parsing the nic backend. Now to try and find corresponding
-     * frontend, based off vlan number. NB this assumes a 1-1 mapping
-     */
-
-    nic = qemuFindNICForVLAN(nnics, nics, wantvlan);
-    if (!nic) {
-        virDomainNetDefFree(def);
-        def = NULL;
-        goto cleanup;
-    }
-
-    if (!STRPREFIX(nic, "nic")) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("cannot parse NIC definition '%s'"), nic);
-        virDomainNetDefFree(def);
-        def = NULL;
-        goto cleanup;
-    }
-
-    for (i = 0 ; i < nkeywords ; i++) {
-        VIR_FREE(keywords[i]);
-        VIR_FREE(values[i]);
-    }
-    VIR_FREE(keywords);
-    VIR_FREE(values);
-
-    if (STRPREFIX(nic, "nic,")) {
-        if ((nkeywords = qemuParseKeywords(nic + strlen("nic,"),
-                                           &keywords,
-                                           &values, 0)) < 0) {
-            virDomainNetDefFree(def);
-            def = NULL;
-            goto cleanup;
-        }
-    } else {
-        nkeywords = 0;
-    }
-
-    for (i = 0 ; i < nkeywords ; i++) {
-        if (STREQ(keywords[i], "macaddr")) {
-            genmac = 0;
-            if (virParseMacAddr(values[i], def->mac) < 0) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("unable to parse mac address '%s'"),
-                                values[i]);
-                virDomainNetDefFree(def);
-                def = NULL;
-                goto cleanup;
-            }
-        } else if (STREQ(keywords[i], "model")) {
-            def->model = values[i];
-            values[i] = NULL;
-        }
-    }
-
-    if (genmac)
-        virCapabilitiesGenerateMac(caps, def->mac);
-
-cleanup:
-    for (i = 0 ; i < nkeywords ; i++) {
-        VIR_FREE(keywords[i]);
-        VIR_FREE(values[i]);
-    }
-    VIR_FREE(keywords);
-    VIR_FREE(values);
-    return def;
-}
-
-
-/*
- * Tries to parse a QEMU PCI device
- */
-static virDomainHostdevDefPtr
-qemuParseCommandLinePCI(const char *val)
-{
-    virDomainHostdevDefPtr def = NULL;
-    int bus = 0, slot = 0, func = 0;
-    const char *start;
-    char *end;
-
-    if (!STRPREFIX(val, "host=")) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("unknown PCI device syntax '%s'"), val);
-        VIR_FREE(def);
-        goto cleanup;
-    }
-
-    start = val + strlen("host=");
-    if (virStrToLong_i(start, &end, 16, &bus) < 0 || *end != ':') {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("cannot extract PCI device bus '%s'"), val);
-        VIR_FREE(def);
-        goto cleanup;
-    }
-    start = end + 1;
-    if (virStrToLong_i(start, &end, 16, &slot) < 0 || *end != '.') {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("cannot extract PCI device slot '%s'"), val);
-        VIR_FREE(def);
-        goto cleanup;
-    }
-    start = end + 1;
-    if (virStrToLong_i(start, NULL, 16, &func) < 0) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("cannot extract PCI device function '%s'"), val);
-        VIR_FREE(def);
-        goto cleanup;
-    }
-
-    if (VIR_ALLOC(def) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
-    def->managed = 1;
-    def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
-    def->source.subsys.u.pci.bus = bus;
-    def->source.subsys.u.pci.slot = slot;
-    def->source.subsys.u.pci.function = func;
-
-cleanup:
-    return def;
-}
-
-
-/*
- * Tries to parse a QEMU USB device
- */
-static virDomainHostdevDefPtr
-qemuParseCommandLineUSB(const char *val)
-{
-    virDomainHostdevDefPtr def = NULL;
-    int first = 0, second = 0;
-    const char *start;
-    char *end;
-
-    if (!STRPREFIX(val, "host:")) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("unknown USB device syntax '%s'"), val);
-        VIR_FREE(def);
-        goto cleanup;
-    }
-
-    start = val + strlen("host:");
-    if (strchr(start, ':')) {
-        if (virStrToLong_i(start, &end, 16, &first) < 0 || *end != ':') {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("cannot extract USB device vendor '%s'"), val);
-            VIR_FREE(def);
-            goto cleanup;
-        }
-        start = end + 1;
-        if (virStrToLong_i(start, NULL, 16, &second) < 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("cannot extract USB device product '%s'"), val);
-            VIR_FREE(def);
-            goto cleanup;
-        }
-    } else {
-        if (virStrToLong_i(start, &end, 10, &first) < 0 || *end != '.') {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                             _("cannot extract USB device bus '%s'"), val);
-            VIR_FREE(def);
-            goto cleanup;
-        }
-        start = end + 1;
-        if (virStrToLong_i(start, NULL, 10, &second) < 0) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("cannot extract USB device address '%s'"), val);
-            VIR_FREE(def);
-            goto cleanup;
-        }
-    }
-
-    if (VIR_ALLOC(def) < 0) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    def->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
-    def->managed = 0;
-    def->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
-    if (*end == '.') {
-        def->source.subsys.u.usb.bus = first;
-        def->source.subsys.u.usb.device = second;
-    } else {
-        def->source.subsys.u.usb.vendor = first;
-        def->source.subsys.u.usb.product = second;
-    }
-
-cleanup:
-    return def;
-}
-
-
-/*
- * Tries to parse a QEMU serial/parallel device
- */
-static virDomainChrDefPtr
-qemuParseCommandLineChr(const char *val)
-{
-    virDomainChrDefPtr def;
-
-    if (VIR_ALLOC(def) < 0)
-        goto no_memory;
-
-    if (STREQ(val, "null")) {
-        def->type = VIR_DOMAIN_CHR_TYPE_NULL;
-    } else if (STREQ(val, "vc")) {
-        def->type = VIR_DOMAIN_CHR_TYPE_VC;
-    } else if (STREQ(val, "pty")) {
-        def->type = VIR_DOMAIN_CHR_TYPE_PTY;
-    } else if (STRPREFIX(val, "file:")) {
-        def->type = VIR_DOMAIN_CHR_TYPE_FILE;
-        def->data.file.path = strdup(val+strlen("file:"));
-        if (!def->data.file.path)
-            goto no_memory;
-    } else if (STRPREFIX(val, "pipe:")) {
-        def->type = VIR_DOMAIN_CHR_TYPE_PIPE;
-        def->data.file.path = strdup(val+strlen("pipe:"));
-        if (!def->data.file.path)
-            goto no_memory;
-    } else if (STREQ(val, "stdio")) {
-        def->type = VIR_DOMAIN_CHR_TYPE_STDIO;
-    } else if (STRPREFIX(val, "udp:")) {
-        const char *svc1, *host2, *svc2;
-        def->type = VIR_DOMAIN_CHR_TYPE_UDP;
-        val += strlen("udp:");
-        svc1 = strchr(val, ':');
-        host2 = svc1 ? strchr(svc1, '@') : NULL;
-        svc2 = host2 ? strchr(host2, ':') : NULL;
-
-        if (svc1)
-            def->data.udp.connectHost = strndup(val, svc1-val);
-        else
-            def->data.udp.connectHost = strdup(val);
-
-        if (!def->data.udp.connectHost)
-            goto no_memory;
-
-        if (svc1) {
-            svc1++;
-            if (host2)
-                def->data.udp.connectService = strndup(svc1, host2-svc1);
-            else
-                def->data.udp.connectService = strdup(svc1);
-
-            if (!def->data.udp.connectService)
-                goto no_memory;
-        }
-
-        if (host2) {
-            host2++;
-            if (svc2)
-                def->data.udp.bindHost = strndup(host2, svc2-host2);
-            else
-                def->data.udp.bindHost = strdup(host2);
-
-            if (!def->data.udp.bindHost)
-                goto no_memory;
-        }
-        if (svc2) {
-            svc2++;
-            def->data.udp.bindService = strdup(svc2);
-            if (!def->data.udp.bindService)
-                goto no_memory;
-        }
-    } else if (STRPREFIX(val, "tcp:") ||
-               STRPREFIX(val, "telnet:")) {
-        const char *opt, *svc;
-        def->type = VIR_DOMAIN_CHR_TYPE_TCP;
-        if (STRPREFIX(val, "tcp:")) {
-            val += strlen("tcp:");
-        } else {
-            val += strlen("telnet:");
-            def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
-        }
-        svc = strchr(val, ':');
-        if (!svc) {
-            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                            _("cannot find port number in character device %s"), val);
-            goto error;
-        }
-        opt = strchr(svc, ',');
-        if (opt && strstr(opt, "server"))
-            def->data.tcp.listen = 1;
-
-        def->data.tcp.host = strndup(val, svc-val);
-        if (!def->data.tcp.host)
-            goto no_memory;
-        svc++;
-        if (opt) {
-            def->data.tcp.service = strndup(svc, opt-svc);
-        } else {
-            def->data.tcp.service = strdup(svc);
-        }
-        if (!def->data.tcp.service)
-            goto no_memory;
-    } else if (STRPREFIX(val, "unix:")) {
-        const char *opt;
-        val += strlen("unix:");
-        opt = strchr(val, ',');
-        def->type = VIR_DOMAIN_CHR_TYPE_UNIX;
-        if (opt) {
-            if (strstr(opt, "listen"))
-                def->data.nix.listen = 1;
-            def->data.nix.path = strndup(val, opt-val);
-        } else {
-            def->data.nix.path = strdup(val);
-        }
-        if (!def->data.nix.path)
-            goto no_memory;
-
-    } else if (STRPREFIX(val, "/dev")) {
-        def->type = VIR_DOMAIN_CHR_TYPE_DEV;
-        def->data.file.path = strdup(val);
-        if (!def->data.file.path)
-            goto no_memory;
-    } else {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        _("unknown character device syntax %s"), val);
-        goto error;
-    }
-
-    return def;
-
-no_memory:
-    virReportOOMError();
-error:
-    virDomainChrDefFree(def);
-    return NULL;
-}
-
-
-static virCPUDefPtr
-qemuInitGuestCPU(virDomainDefPtr dom)
-{
-    if (!dom->cpu) {
-        virCPUDefPtr cpu;
-
-        if (VIR_ALLOC(cpu) < 0) {
-            virReportOOMError();
-            return NULL;
-        }
-
-        cpu->type = VIR_CPU_TYPE_GUEST;
-        cpu->match = VIR_CPU_MATCH_EXACT;
-        dom->cpu = cpu;
-    }
-
-    return dom->cpu;
-}
-
-
-static int
-qemuParseCommandLineCPU(virDomainDefPtr dom,
-                        const char *val)
-{
-    virCPUDefPtr cpu;
-    const char *p = val;
-    const char *next;
-
-    if (!(cpu = qemuInitGuestCPU(dom)))
-        goto error;
-
-    do {
-        if (*p == '\0' || *p == ',')
-            goto syntax;
-
-        if ((next = strchr(p, ',')))
-            next++;
-
-        if (!cpu->model) {
-            if (next)
-                cpu->model = strndup(p, next - p - 1);
-            else
-                cpu->model = strdup(p);
-
-            if (!cpu->model)
-                goto no_memory;
-        }
-        else if (*p == '+' || *p == '-') {
-            char *feature;
-            int policy;
-            int ret;
-
-            if (*p == '+')
-                policy = VIR_CPU_FEATURE_REQUIRE;
-            else
-                policy = VIR_CPU_FEATURE_DISABLE;
-
-            p++;
-            if (*p == '\0' || *p == ',')
-                goto syntax;
-
-            if (next)
-                feature = strndup(p, next - p - 1);
-            else
-                feature = strdup(p);
-
-            ret = virCPUDefAddFeature(cpu, feature, policy);
-            VIR_FREE(feature);
-            if (ret < 0)
-                goto error;
-        }
-    } while ((p = next));
-
-    return 0;
-
-syntax:
-    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                    _("unknown CPU syntax '%s'"), val);
-    goto error;
-
-no_memory:
-    virReportOOMError();
-error:
-    return -1;
-}
-
-
-static int
-qemuParseCommandLineSmp(virDomainDefPtr dom,
-                        const char *val)
-{
-    unsigned int sockets = 0;
-    unsigned int cores = 0;
-    unsigned int threads = 0;
-    unsigned int maxcpus = 0;
-    int i;
-    int nkws;
-    char **kws;
-    char **vals;
-    int n;
-    char *end;
-    int ret;
-
-    nkws = qemuParseKeywords(val, &kws, &vals, 1);
-    if (nkws < 0)
-        return -1;
-
-    for (i = 0; i < nkws; i++) {
-        if (vals[i] == NULL) {
-            if (i > 0 ||
-                virStrToLong_i(kws[i], &end, 10, &n) < 0 || *end != '\0')
-                goto syntax;
-            dom->vcpus = n;
-        } else {
-            if (virStrToLong_i(vals[i], &end, 10, &n) < 0 || *end != '\0')
-                goto syntax;
-            if (STREQ(kws[i], "sockets"))
-                sockets = n;
-            else if (STREQ(kws[i], "cores"))
-                cores = n;
-            else if (STREQ(kws[i], "threads"))
-                threads = n;
-            else if (STREQ(kws[i], "maxcpus"))
-                maxcpus = n;
-            else
-                goto syntax;
-        }
-    }
-
-    dom->maxvcpus = maxcpus ? maxcpus : dom->vcpus;
-
-    if (sockets && cores && threads) {
-        virCPUDefPtr cpu;
-
-        if (!(cpu = qemuInitGuestCPU(dom)))
-            goto error;
-        cpu->sockets = sockets;
-        cpu->cores = cores;
-        cpu->threads = threads;
-    } else if (sockets || cores || threads)
-        goto syntax;
-
-    ret = 0;
-
-cleanup:
-    for (i = 0; i < nkws; i++) {
-        VIR_FREE(kws[i]);
-        VIR_FREE(vals[i]);
-    }
-    VIR_FREE(kws);
-    VIR_FREE(vals);
-
-    return ret;
-
-syntax:
-    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                    _("cannot parse CPU topology '%s'"), val);
-error:
-    ret = -1;
-    goto cleanup;
-}
-
-
-/*
- * Analyse the env and argv settings and reconstruct a
- * virDomainDefPtr representing these settings as closely
- * as is practical. This is not an exact science....
- */
-virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
-                                     const char **progenv,
-                                     const char **progargv)
-{
-    virDomainDefPtr def;
-    int i;
-    int nographics = 0;
-    int fullscreen = 0;
-    char *path;
-    int nnics = 0;
-    const char **nics = NULL;
-    int video = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
-    int nvirtiodisk = 0;
-    qemuDomainCmdlineDefPtr cmd;
-
-    if (!progargv[0]) {
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                        "%s", _("no emulator path found"));
-        return NULL;
-    }
-
-    if (VIR_ALLOC(def) < 0)
-        goto no_memory;
-
-    /* allocate the cmdlinedef up-front; if it's unused, we'll free it later */
-    if (VIR_ALLOC(cmd) < 0)
-        goto no_memory;
-
-    virUUIDGenerate(def->uuid);
-
-    def->id = -1;
-    def->mem.cur_balloon = def->mem.max_balloon = 64 * 1024;
-    def->maxvcpus = 1;
-    def->vcpus = 1;
-    def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
-    def->features = (1 << VIR_DOMAIN_FEATURE_ACPI)
-        /*| (1 << VIR_DOMAIN_FEATURE_APIC)*/;
-    def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
-    def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
-    def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
-    def->virtType = VIR_DOMAIN_VIRT_QEMU;
-    if (!(def->emulator = strdup(progargv[0])))
-        goto no_memory;
-
-    if (strstr(def->emulator, "kvm")) {
-        def->virtType = VIR_DOMAIN_VIRT_KVM;
-        def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
-    }
-
-
-    if (strstr(def->emulator, "xenner")) {
-        def->virtType = VIR_DOMAIN_VIRT_KVM;
-        def->os.type = strdup("xen");
-    } else {
-        def->os.type = strdup("hvm");
-    }
-    if (!def->os.type)
-        goto no_memory;
-
-    if (STRPREFIX(def->emulator, "qemu"))
-        path = def->emulator;
-    else
-        path = strstr(def->emulator, "qemu");
-    if (path &&
-        STRPREFIX(path, "qemu-system-"))
-        def->os.arch = strdup(path + strlen("qemu-system-"));
-    else
-        def->os.arch = strdup("i686");
-    if (!def->os.arch)
-        goto no_memory;
-
-#define WANT_VALUE()                                                   \
-    const char *val = progargv[++i];                                   \
-    if (!val) {                                                        \
-        qemuReportError(VIR_ERR_INTERNAL_ERROR,                        \
-                        _("missing value for %s argument"), arg);      \
-        goto error;                                                    \
-    }
-
-    /* One initial loop to get list of NICs, so we
-     * can correlate them later */
-    for (i = 1 ; progargv[i] ; i++) {
-        const char *arg = progargv[i];
-        /* Make sure we have a single - for all options to
-           simplify next logic */
-        if (STRPREFIX(arg, "--"))
-            arg++;
-
-        if (STREQ(arg, "-net")) {
-            WANT_VALUE();
-            if (STRPREFIX(val, "nic")) {
-                if (VIR_REALLOC_N(nics, nnics+1) < 0)
-                    goto no_memory;
-                nics[nnics++] = val;
-            }
-        }
-    }
-
-    /* Now the real processing loop */
-    for (i = 1 ; progargv[i] ; i++) {
-        const char *arg = progargv[i];
-        /* Make sure we have a single - for all options to
-           simplify next logic */
-        if (STRPREFIX(arg, "--"))
-            arg++;
-
-        if (STREQ(arg, "-vnc")) {
-            virDomainGraphicsDefPtr vnc;
-            char *tmp;
-            WANT_VALUE();
-            if (VIR_ALLOC(vnc) < 0)
-                goto no_memory;
-            vnc->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
-
-            tmp = strchr(val, ':');
-            if (tmp) {
-                char *opts;
-                if (virStrToLong_i(tmp+1, &opts, 10, &vnc->data.vnc.port) < 0) {
-                    VIR_FREE(vnc);
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR,             \
-                                    _("cannot parse VNC port '%s'"), tmp+1);
-                    goto error;
-                }
-                vnc->data.vnc.listenAddr = strndup(val, tmp-val);
-                if (!vnc->data.vnc.listenAddr) {
-                    VIR_FREE(vnc);
-                    goto no_memory;
-                }
-                vnc->data.vnc.port += 5900;
-                vnc->data.vnc.autoport = 0;
-            } else {
-                vnc->data.vnc.autoport = 1;
-            }
-
-            if (VIR_REALLOC_N(def->graphics, def->ngraphics+1) < 0) {
-                virDomainGraphicsDefFree(vnc);
-                goto no_memory;
-            }
-            def->graphics[def->ngraphics++] = vnc;
-        } else if (STREQ(arg, "-m")) {
-            int mem;
-            WANT_VALUE();
-            if (virStrToLong_i(val, NULL, 10, &mem) < 0) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR, \
-                                _("cannot parse memory level '%s'"), val);
-                goto error;
-            }
-            def->mem.cur_balloon = def->mem.max_balloon = mem * 1024;
-        } else if (STREQ(arg, "-smp")) {
-            WANT_VALUE();
-            if (qemuParseCommandLineSmp(def, val) < 0)
-                goto error;
-        } else if (STREQ(arg, "-uuid")) {
-            WANT_VALUE();
-            if (virUUIDParse(val, def->uuid) < 0) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR, \
-                                _("cannot parse UUID '%s'"), val);
-                goto error;
-            }
-        } else if (STRPREFIX(arg, "-hd") ||
-                   STRPREFIX(arg, "-sd") ||
-                   STRPREFIX(arg, "-fd") ||
-                   STREQ(arg, "-cdrom")) {
-            WANT_VALUE();
-            virDomainDiskDefPtr disk;
-            if (VIR_ALLOC(disk) < 0)
-                goto no_memory;
-
-            if (STRPREFIX(val, "/dev/"))
-                disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
-            else if (STRPREFIX(val, "nbd:")) {
-                disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
-                disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
-                val += strlen("nbd:");
-            } else if (STRPREFIX(val, "rbd:")) {
-                disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
-                disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
-                val += strlen("rbd:");
-            } else if (STRPREFIX(val, "sheepdog:")) {
-                disk->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
-                disk->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
-                val += strlen("sheepdog:");
-            } else
-                disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
-            if (STREQ(arg, "-cdrom")) {
-                disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
-                disk->dst = strdup("hdc");
-                disk->readonly = 1;
-            } else {
-                if (STRPREFIX(arg, "-fd")) {
-                    disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
-                    disk->bus = VIR_DOMAIN_DISK_BUS_FDC;
-                } else {
-                    disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
-                    if (STRPREFIX(arg, "-hd"))
-                        disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
-                    else
-                        disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
-                }
-                disk->dst = strdup(arg + 1);
-            }
-            disk->src = strdup(val);
-
-            if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK) {
-                char *host, *port;
-
-                switch (disk->protocol) {
-                case VIR_DOMAIN_DISK_PROTOCOL_NBD:
-                    host = disk->src;
-                    port = strchr(host, ':');
-                    if (!port) {
-                        def = NULL;
-                        qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                        _("cannot parse nbd filename '%s'"), disk->src);
-                        goto error;
-                    }
-                    *port++ = '\0';
-                    if (VIR_ALLOC(disk->hosts) < 0) {
-                        virReportOOMError();
-                        goto error;
-                    }
-                    disk->nhosts = 1;
-                    disk->hosts->name = host;
-                    disk->hosts->port = strdup(port);
-                    if (!disk->hosts->port) {
-                        virReportOOMError();
-                        goto error;
-                    }
-                    disk->src = NULL;
-                    break;
-                case VIR_DOMAIN_DISK_PROTOCOL_RBD:
-                    /* handled later since the hosts for all disks are in CEPH_ARGS */
-                    break;
-                case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
-                    /* disk->src must be [vdiname] or [host]:[port]:[vdiname] */
-                    port = strchr(disk->src, ':');
-                    if (port) {
-                        char *vdi;
-
-                        *port++ = '\0';
-                        vdi = strchr(port, ':');
-                        if (!vdi) {
-                            qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                            _("cannot parse sheepdog filename '%s'"), val);
-                            goto error;
-                        }
-                        *vdi++ = '\0';
-                        if (VIR_ALLOC(disk->hosts) < 0) {
-                            virReportOOMError();
-                            goto error;
-                        }
-                        disk->nhosts = 1;
-                        disk->hosts->name = disk->src;
-                        disk->hosts->port = strdup(port);
-                        if (!disk->hosts->port) {
-                            virReportOOMError();
-                            goto error;
-                        }
-                        disk->src = strdup(vdi);
-                        if (!disk->src) {
-                            virReportOOMError();
-                            goto error;
-                        }
-                    }
-                    break;
-                }
-            }
-
-            if (!(disk->src || disk->nhosts > 0) ||
-                !disk->dst) {
-                virDomainDiskDefFree(disk);
-                goto no_memory;
-            }
-
-            if (virDomainDiskDefAssignAddress(caps, disk) < 0)
-                goto error;
-
-            if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
-                virDomainDiskDefFree(disk);
-                goto no_memory;
-            }
-            def->disks[def->ndisks++] = disk;
-        } else if (STREQ(arg, "-no-acpi")) {
-            def->features &= ~(1 << VIR_DOMAIN_FEATURE_ACPI);
-        } else if (STREQ(arg, "-no-reboot")) {
-            def->onReboot = VIR_DOMAIN_LIFECYCLE_DESTROY;
-        } else if (STREQ(arg, "-no-kvm")) {
-            def->virtType = VIR_DOMAIN_VIRT_QEMU;
-        } else if (STREQ(arg, "-nographic")) {
-            nographics = 1;
-        } else if (STREQ(arg, "-full-screen")) {
-            fullscreen = 1;
-        } else if (STREQ(arg, "-localtime")) {
-            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
-        } else if (STREQ(arg, "-kernel")) {
-            WANT_VALUE();
-            if (!(def->os.kernel = strdup(val)))
-                goto no_memory;
-        } else if (STREQ(arg, "-initrd")) {
-            WANT_VALUE();
-            if (!(def->os.initrd = strdup(val)))
-                goto no_memory;
-        } else if (STREQ(arg, "-append")) {
-            WANT_VALUE();
-            if (!(def->os.cmdline = strdup(val)))
-                goto no_memory;
-        } else if (STREQ(arg, "-boot")) {
-            int n, b = 0;
-            WANT_VALUE();
-            for (n = 0 ; val[n] && b < VIR_DOMAIN_BOOT_LAST ; n++) {
-                if (val[n] == 'a')
-                    def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_FLOPPY;
-                else if (val[n] == 'c')
-                    def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_DISK;
-                else if (val[n] == 'd')
-                    def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_CDROM;
-                else if (val[n] == 'n')
-                    def->os.bootDevs[b++] = VIR_DOMAIN_BOOT_NET;
-                else if (val[n] == ',')
-                    break;
-            }
-            def->os.nBootDevs = b;
-
-            if (strstr(val, "menu=on"))
-                def->os.bootmenu = 1;
-        } else if (STREQ(arg, "-name")) {
-            char *process;
-            WANT_VALUE();
-            process = strstr(val, ",process=");
-            if (process == NULL) {
-                if (!(def->name = strdup(val)))
-                    goto no_memory;
-            } else {
-                if (!(def->name = strndup(val, process - val)))
-                    goto no_memory;
-            }
-        } else if (STREQ(arg, "-M")) {
-            WANT_VALUE();
-            if (!(def->os.machine = strdup(val)))
-                goto no_memory;
-        } else if (STREQ(arg, "-serial")) {
-            WANT_VALUE();
-            if (STRNEQ(val, "none")) {
-                virDomainChrDefPtr chr;
-                if (!(chr = qemuParseCommandLineChr(val)))
-                    goto error;
-                if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) {
-                    virDomainChrDefFree(chr);
-                    goto no_memory;
-                }
-                chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
-                chr->target.port = def->nserials;
-                def->serials[def->nserials++] = chr;
-            }
-        } else if (STREQ(arg, "-parallel")) {
-            WANT_VALUE();
-            if (STRNEQ(val, "none")) {
-                virDomainChrDefPtr chr;
-                if (!(chr = qemuParseCommandLineChr(val)))
-                    goto error;
-                if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) {
-                    virDomainChrDefFree(chr);
-                    goto no_memory;
-                }
-                chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
-                chr->target.port = def->nparallels;
-                def->parallels[def->nparallels++] = chr;
-            }
-        } else if (STREQ(arg, "-usbdevice")) {
-            WANT_VALUE();
-            if (STREQ(val, "tablet") ||
-                STREQ(val, "mouse")) {
-                virDomainInputDefPtr input;
-                if (VIR_ALLOC(input) < 0)
-                    goto no_memory;
-                input->bus = VIR_DOMAIN_INPUT_BUS_USB;
-                if (STREQ(val, "tablet"))
-                    input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
-                else
-                    input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
-                if (VIR_REALLOC_N(def->inputs, def->ninputs+1) < 0) {
-                    virDomainInputDefFree(input);
-                    goto no_memory;
-                }
-                def->inputs[def->ninputs++] = input;
-            } else if (STRPREFIX(val, "disk:")) {
-                virDomainDiskDefPtr disk;
-                if (VIR_ALLOC(disk) < 0)
-                    goto no_memory;
-                disk->src = strdup(val + strlen("disk:"));
-                if (!disk->src) {
-                    virDomainDiskDefFree(disk);
-                    goto no_memory;
-                }
-                if (STRPREFIX(disk->src, "/dev/"))
-                    disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
-                else
-                    disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
-                disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
-                disk->bus = VIR_DOMAIN_DISK_BUS_USB;
-                if (!(disk->dst = strdup("sda"))) {
-                    virDomainDiskDefFree(disk);
-                    goto no_memory;
-                }
-                if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
-                    virDomainDiskDefFree(disk);
-                    goto no_memory;
-                }
-                def->disks[def->ndisks++] = disk;
-            } else {
-                virDomainHostdevDefPtr hostdev;
-                if (!(hostdev = qemuParseCommandLineUSB(val)))
-                    goto error;
-                if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
-                    virDomainHostdevDefFree(hostdev);
-                    goto no_memory;
-                }
-                def->hostdevs[def->nhostdevs++] = hostdev;
-            }
-        } else if (STREQ(arg, "-net")) {
-            WANT_VALUE();
-            if (!STRPREFIX(val, "nic") && STRNEQ(val, "none")) {
-                virDomainNetDefPtr net;
-                if (!(net = qemuParseCommandLineNet(caps, val, nnics, nics)))
-                    goto error;
-                if (VIR_REALLOC_N(def->nets, def->nnets+1) < 0) {
-                    virDomainNetDefFree(net);
-                    goto no_memory;
-                }
-                def->nets[def->nnets++] = net;
-            }
-        } else if (STREQ(arg, "-drive")) {
-            virDomainDiskDefPtr disk;
-            WANT_VALUE();
-            if (!(disk = qemuParseCommandLineDisk(caps, val, nvirtiodisk)))
-                goto error;
-            if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
-                virDomainDiskDefFree(disk);
-                goto no_memory;
-            }
-            def->disks[def->ndisks++] = disk;
-
-            if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
-                nvirtiodisk++;
-        } else if (STREQ(arg, "-pcidevice")) {
-            virDomainHostdevDefPtr hostdev;
-            WANT_VALUE();
-            if (!(hostdev = qemuParseCommandLinePCI(val)))
-                goto error;
-            if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
-                virDomainHostdevDefFree(hostdev);
-                goto no_memory;
-            }
-            def->hostdevs[def->nhostdevs++] = hostdev;
-        } else if (STREQ(arg, "-soundhw")) {
-            const char *start;
-            WANT_VALUE();
-            start = val;
-            while (start) {
-                const char *tmp = strchr(start, ',');
-                int type = -1;
-                if (STRPREFIX(start, "pcspk")) {
-                    type = VIR_DOMAIN_SOUND_MODEL_PCSPK;
-                } else if (STRPREFIX(start, "sb16")) {
-                    type = VIR_DOMAIN_SOUND_MODEL_SB16;
-                } else if (STRPREFIX(start, "es1370")) {
-                    type = VIR_DOMAIN_SOUND_MODEL_ES1370;
-                } else if (STRPREFIX(start, "ac97")) {
-                    type = VIR_DOMAIN_SOUND_MODEL_AC97;
-                }
-
-                if (type != -1) {
-                    virDomainSoundDefPtr snd;
-                    if (VIR_ALLOC(snd) < 0)
-                        goto no_memory;
-                    snd->model = type;
-                    if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) {
-                        VIR_FREE(snd);
-                        goto no_memory;
-                    }
-                    def->sounds[def->nsounds++] = snd;
-                }
-
-                start = tmp ? tmp + 1 : NULL;
-            }
-        } else if (STREQ(arg, "-watchdog")) {
-            WANT_VALUE();
-            int model = virDomainWatchdogModelTypeFromString (val);
-
-            if (model != -1) {
-                virDomainWatchdogDefPtr wd;
-                if (VIR_ALLOC(wd) < 0)
-                    goto no_memory;
-                wd->model = model;
-                wd->action = VIR_DOMAIN_WATCHDOG_ACTION_RESET;
-                def->watchdog = wd;
-            }
-        } else if (STREQ(arg, "-watchdog-action") && def->watchdog) {
-            WANT_VALUE();
-            int action = virDomainWatchdogActionTypeFromString (val);
-
-            if (action != -1)
-                def->watchdog->action = action;
-        } else if (STREQ(arg, "-bootloader")) {
-            WANT_VALUE();
-            def->os.bootloader = strdup(val);
-            if (!def->os.bootloader)
-                goto no_memory;
-        } else if (STREQ(arg, "-vmwarevga")) {
-            video = VIR_DOMAIN_VIDEO_TYPE_VMVGA;
-        } else if (STREQ(arg, "-std-vga")) {
-            video = VIR_DOMAIN_VIDEO_TYPE_VGA;
-        } else if (STREQ(arg, "-vga")) {
-            WANT_VALUE();
-            if (STRNEQ(val, "none")) {
-                video = qemuVideoTypeFromString(val);
-                if (video < 0) {
-                    qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                    _("unknown video adapter type '%s'"), val);
-                    goto error;
-                }
-            }
-        } else if (STREQ(arg, "-cpu")) {
-            WANT_VALUE();
-            if (qemuParseCommandLineCPU(def, val) < 0)
-                goto error;
-        } else if (STREQ(arg, "-domid")) {
-            WANT_VALUE();
-            /* ignore, generted on the fly */
-        } else if (STREQ(arg, "-usb")) {
-            /* ignore, always added by libvirt */
-        } else if (STREQ(arg, "-pidfile")) {
-            WANT_VALUE();
-            /* ignore, used by libvirt as needed */
-        } else if (STREQ(arg, "-incoming")) {
-            WANT_VALUE();
-            /* ignore, used via restore/migrate APIs */
-        } else if (STREQ(arg, "-monitor")) {
-            WANT_VALUE();
-            /* ignore, used internally by libvirt */
-        } else if (STREQ(arg, "-S")) {
-            /* ignore, always added by libvirt */
-        } else {
-            /* something we can't yet parse.  Add it to the qemu namespace
-             * cmdline/environment advanced options and hope for the best
-             */
-            VIR_WARN("unknown QEMU argument '%s', adding to the qemu namespace",
-                     arg);
-            if (VIR_REALLOC_N(cmd->args, cmd->num_args+1) < 0)
-                goto no_memory;
-            cmd->args[cmd->num_args] = strdup(arg);
-            if (cmd->args[cmd->num_args] == NULL)
-                goto no_memory;
-            cmd->num_args++;
-        }
-    }
-
-#undef WANT_VALUE
-    if (def->ndisks > 0) {
-        const char *ceph_args = qemuFindEnv(progenv, "CEPH_ARGS");
-        if (ceph_args) {
-            char *hosts, *port, *saveptr, *token;
-            virDomainDiskDefPtr first_rbd_disk = NULL;
-            for (i = 0 ; i < def->ndisks ; i++) {
-                virDomainDiskDefPtr disk = def->disks[i];
-                if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
-                    disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
-                    first_rbd_disk = disk;
-                    break;
-                }
-            }
-
-            if (!first_rbd_disk) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("CEPH_ARGS was set without an rbd disk"));
-                goto error;
-            }
-
-            /* CEPH_ARGS should be: -m host1[:port1][,host2[:port2]]... */
-            if (!STRPREFIX(ceph_args, "-m ")) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("could not parse CEPH_ARGS '%s'"), ceph_args);
-                goto error;
-            }
-            hosts = strdup(strchr(ceph_args, ' ') + 1);
-            if (!hosts)
-                goto no_memory;
-            first_rbd_disk->nhosts = 0;
-            token = strtok_r(hosts, ",", &saveptr);
-            while (token != NULL) {
-                if (VIR_REALLOC_N(first_rbd_disk->hosts, first_rbd_disk->nhosts + 1) < 0) {
-                    VIR_FREE(hosts);
-                    goto no_memory;
-                }
-                port = strchr(token, ':');
-                if (port) {
-                    *port++ = '\0';
-                    port = strdup(port);
-                    if (!port) {
-                        VIR_FREE(hosts);
-                        goto no_memory;
-                    }
-                }
-                first_rbd_disk->hosts[first_rbd_disk->nhosts].port = port;
-                first_rbd_disk->hosts[first_rbd_disk->nhosts].name = strdup(token);
-                if (!first_rbd_disk->hosts[first_rbd_disk->nhosts].name) {
-                    VIR_FREE(hosts);
-                    goto no_memory;
-                }
-                first_rbd_disk->nhosts++;
-                token = strtok_r(NULL, ",", &saveptr);
-            }
-            VIR_FREE(hosts);
-
-            if (first_rbd_disk->nhosts == 0) {
-                qemuReportError(VIR_ERR_INTERNAL_ERROR,
-                                _("found no rbd hosts in CEPH_ARGS '%s'"), ceph_args);
-                goto error;
-            }
-        }
-    }
-
-    if (!nographics && def->ngraphics == 0) {
-        virDomainGraphicsDefPtr sdl;
-        const char *display = qemuFindEnv(progenv, "DISPLAY");
-        const char *xauth = qemuFindEnv(progenv, "XAUTHORITY");
-        if (VIR_ALLOC(sdl) < 0)
-            goto no_memory;
-        sdl->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
-        sdl->data.sdl.fullscreen = fullscreen;
-        if (display &&
-            !(sdl->data.sdl.display = strdup(display))) {
-            VIR_FREE(sdl);
-            goto no_memory;
-        }
-        if (xauth &&
-            !(sdl->data.sdl.xauth = strdup(xauth))) {
-            VIR_FREE(sdl);
-            goto no_memory;
-        }
-
-        if (VIR_REALLOC_N(def->graphics, def->ngraphics+1) < 0) {
-            virDomainGraphicsDefFree(sdl);
-            goto no_memory;
-        }
-        def->graphics[def->ngraphics++] = sdl;
-    }
-
-    if (def->ngraphics) {
-        virDomainVideoDefPtr vid;
-        if (VIR_ALLOC(vid) < 0)
-            goto no_memory;
-        if (def->virtType == VIR_DOMAIN_VIRT_XEN)
-            vid->type = VIR_DOMAIN_VIDEO_TYPE_XEN;
-        else
-            vid->type = video;
-        vid->vram = virDomainVideoDefaultRAM(def, vid->type);
-        vid->heads = 1;
-
-        if (VIR_REALLOC_N(def->videos, def->nvideos+1) < 0) {
-            virDomainVideoDefFree(vid);
-            goto no_memory;
-        }
-        def->videos[def->nvideos++] = vid;
-    }
-
-    /*
-     * having a balloon is the default, define one with type="none" to avoid it
-     */
-    if (!def->memballoon) {
-        virDomainMemballoonDefPtr memballoon;
-        if (VIR_ALLOC(memballoon) < 0)
-            goto no_memory;
-        memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_VIRTIO;
-
-        def->memballoon = memballoon;
-    }
-
-    VIR_FREE(nics);
-
-    if (!def->name) {
-        if (!(def->name = strdup("unnamed")))
-            goto no_memory;
-    }
-
-    if (virDomainDefAddImplicitControllers(def) < 0)
-        goto error;
-
-    if (cmd->num_args || cmd->num_env) {
-        def->ns = caps->ns;
-        def->namespaceData = cmd;
-    }
-    else
-        VIR_FREE(cmd);
-
-    return def;
-
-no_memory:
-    virReportOOMError();
-error:
-    VIR_FREE(cmd);
-    virDomainDefFree(def);
-    VIR_FREE(nics);
-    return NULL;
-}
-
-
-virDomainDefPtr qemuParseCommandLineString(virCapsPtr caps,
-                                           const char *args)
-{
-    const char **progenv = NULL;
-    const char **progargv = NULL;
-    virDomainDefPtr def = NULL;
-    int i;
-
-    if (qemuStringToArgvEnv(args, &progenv, &progargv) < 0)
-        goto cleanup;
-
-    def = qemuParseCommandLine(caps, progenv, progargv);
-
-cleanup:
-    for (i = 0 ; progargv && progargv[i] ; i++)
-        VIR_FREE(progargv[i]);
-    VIR_FREE(progargv);
-
-    for (i = 0 ; progenv && progenv[i] ; i++)
-        VIR_FREE(progenv[i]);
-    VIR_FREE(progenv);
-
-    return def;
-}
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 86c65a6..eac8603 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -148,13 +148,6 @@ struct _qemuDomainCmdlineDef {
 # define QEMUD_MIGRATION_FIRST_PORT 49152
 # define QEMUD_MIGRATION_NUM_PORTS 64
 
-/* Config type for XML import/export conversions */
-# define QEMU_CONFIG_FORMAT_ARGV "qemu-argv"
-
-# define QEMU_DRIVE_HOST_PREFIX "drive-"
-# define QEMU_VIRTIO_SERIAL_PREFIX "virtio-serial"
-# define QEMU_FSDEV_HOST_PREFIX "fsdev-"
-
 # define qemuReportError(code, ...)                                      \
     virReportErrorHelper(NULL, VIR_FROM_QEMU, code, __FILE__,           \
                          __FUNCTION__, __LINE__, __VA_ARGS__)
@@ -163,131 +156,4 @@ struct _qemuDomainCmdlineDef {
 int qemudLoadDriverConfig(struct qemud_driver *driver,
                           const char *filename);
 
-virCommandPtr qemudBuildCommandLine     (virConnectPtr conn,
-                                         struct qemud_driver *driver,
-                                         virDomainDefPtr def,
-                                         virDomainChrDefPtr monitor_chr,
-                                         bool monitor_json,
-                                         unsigned long long qemuCmdFlags,
-                                         const char *migrateFrom,
-                                         virDomainSnapshotObjPtr current_snapshot,
-                                         enum virVMOperationType vmop)
-    ATTRIBUTE_NONNULL(1);
-
-/* With vlan == -1, use netdev syntax, else old hostnet */
-char * qemuBuildHostNetStr(virDomainNetDefPtr net,
-                           char type_sep,
-                           int vlan,
-                           const char *tapfd,
-                           const char *vhostfd);
-
-/* Legacy, pre device support */
-char * qemuBuildNicStr(virDomainNetDefPtr net,
-                       const char *prefix,
-                       int vlan);
-
-/* Current, best practice */
-char * qemuBuildNicDevStr(virDomainNetDefPtr net,
-                          int vlan);
-
-char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
-                               unsigned long long qemudCmdFlags);
-
-/* Both legacy & current support */
-char *qemuBuildDriveStr(virDomainDiskDefPtr disk,
-                        int bootable,
-                        unsigned long long qemuCmdFlags);
-char *qemuBuildFSStr(virDomainFSDefPtr fs,
-                     unsigned long long qemuCmdFlags);
-
-/* Current, best practice */
-char * qemuBuildDriveDevStr(virDomainDiskDefPtr disk);
-char * qemuBuildFSDevStr(virDomainFSDefPtr fs);
-/* Current, best practice */
-char * qemuBuildControllerDevStr(virDomainControllerDefPtr def);
-
-char * qemuBuildWatchdogDevStr(virDomainWatchdogDefPtr dev);
-
-char * qemuBuildMemballoonDevStr(virDomainMemballoonDefPtr dev);
-
-char * qemuBuildUSBInputDevStr(virDomainInputDefPtr dev);
-
-char * qemuBuildSoundDevStr(virDomainSoundDefPtr sound);
-
-/* Legacy, pre device support */
-char * qemuBuildPCIHostdevPCIDevStr(virDomainHostdevDefPtr dev);
-/* Current, best practice */
-char * qemuBuildPCIHostdevDevStr(virDomainHostdevDefPtr dev,
-                                 const char *configfd);
-
-int qemudOpenPCIConfig(virDomainHostdevDefPtr dev);
-
-/* Current, best practice */
-char * qemuBuildChrChardevStr(virDomainChrDefPtr dev);
-/* Legacy, pre device support */
-char * qemuBuildChrArgStr(virDomainChrDefPtr dev, const char *prefix);
-
-char * qemuBuildVirtioSerialPortDevStr(virDomainChrDefPtr dev);
-
-/* Legacy, pre device support */
-char * qemuBuildUSBHostdevUsbDevStr(virDomainHostdevDefPtr dev);
-/* Current, best practice */
-char * qemuBuildUSBHostdevDevStr(virDomainHostdevDefPtr dev);
-
-
-
-int         qemudNetworkIfaceConnect    (virConnectPtr conn,
-                                         struct qemud_driver *driver,
-                                         virDomainNetDefPtr net,
-                                         unsigned long long qemuCmdFlags)
-    ATTRIBUTE_NONNULL(1);
-
-int
-qemudOpenVhostNet(virDomainNetDefPtr net,
-                  unsigned long long qemuCmdFlags);
-
-int qemudPhysIfaceConnect(virConnectPtr conn,
-                          struct qemud_driver *driver,
-                          virDomainNetDefPtr net,
-                          unsigned long long qemuCmdFlags,
-                          const unsigned char *vmuuid,
-                          enum virVMOperationType vmop);
-
-int         qemudCanonicalizeMachine    (struct qemud_driver *driver,
-                                         virDomainDefPtr def);
-
-virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
-                                     const char **progenv,
-                                     const char **progargv);
-virDomainDefPtr qemuParseCommandLineString(virCapsPtr caps,
-                                           const char *args);
-
-qemuDomainPCIAddressSetPtr qemuDomainPCIAddressSetCreate(virDomainDefPtr def);
-int qemuDomainPCIAddressReserveSlot(qemuDomainPCIAddressSetPtr addrs,
-                                    int slot);
-int qemuDomainPCIAddressReserveAddr(qemuDomainPCIAddressSetPtr addrs,
-                                    virDomainDeviceInfoPtr dev);
-int qemuDomainPCIAddressSetNextAddr(qemuDomainPCIAddressSetPtr addrs,
-                                    virDomainDeviceInfoPtr dev);
-int qemuDomainPCIAddressEnsureAddr(qemuDomainPCIAddressSetPtr addrs,
-                                   virDomainDeviceInfoPtr dev);
-int qemuDomainPCIAddressReleaseAddr(qemuDomainPCIAddressSetPtr addrs,
-                                    virDomainDeviceInfoPtr dev);
-
-void qemuDomainPCIAddressSetFree(qemuDomainPCIAddressSetPtr addrs);
-int  qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs);
-
-int qemuDomainNetVLAN(virDomainNetDefPtr def);
-int qemuAssignDeviceNetAlias(virDomainDefPtr def, virDomainNetDefPtr net, int idx);
-int qemuAssignDeviceDiskAlias(virDomainDiskDefPtr def, unsigned long long qemuCmdFlags);
-int qemuAssignDeviceHostdevAlias(virDomainDefPtr def, virDomainHostdevDefPtr net, int idx);
-int qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller);
-
-int
-qemuParseKeywords(const char *str,
-                  char ***retkeywords,
-                  char ***retvalues,
-                  int allowEmptyValue);
-
-
 #endif /* __QEMUD_CONF_H */
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index f303075..e1a1179 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -55,6 +55,7 @@
 #include "qemu_driver.h"
 #include "qemu_conf.h"
 #include "qemu_capabilities.h"
+#include "qemu_command.h"
 #include "qemu_monitor.h"
 #include "qemu_bridge_filter.h"
 #include "c-ctype.h"
@@ -4134,10 +4135,10 @@ static int qemudStartVMDaemon(virConnectPtr conn,
 
     DEBUG0("Building emulator command line");
     vm->def->id = driver->nextvmid++;
-    if (!(cmd = qemudBuildCommandLine(conn, driver, vm->def, priv->monConfig,
-                                      priv->monJSON != 0, qemuCmdFlags,
-                                      migrateFrom,
-                                      vm->current_snapshot, vmop)))
+    if (!(cmd = qemuBuildCommandLine(conn, driver, vm->def, priv->monConfig,
+                                     priv->monJSON != 0, qemuCmdFlags,
+                                     migrateFrom,
+                                     vm->current_snapshot, vmop)))
         goto cleanup;
 
     if (qemuDomainSnapshotSetInactive(vm, driver->snapshotDir) < 0)
@@ -7474,9 +7475,9 @@ static char *qemuDomainXMLToNative(virConnectPtr conn,
     if (qemuPrepareMonitorChr(driver, &monConfig, def->name) < 0)
         goto cleanup;
 
-    if (!(cmd = qemudBuildCommandLine(conn, driver, def,
-                                      &monConfig, false, qemuCmdFlags,
-                                      NULL, NULL, VIR_VM_OP_NO_OP)))
+    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
+                                     &monConfig, false, qemuCmdFlags,
+                                     NULL, NULL, VIR_VM_OP_NO_OP)))
         goto cleanup;
 
     ret = virCommandToString(cmd);
@@ -8368,7 +8369,7 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
             return -1;
         }
 
-        if ((tapfd = qemudNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
+        if ((tapfd = qemuNetworkIfaceConnect(conn, driver, net, qemuCmdFlags)) < 0)
             return -1;
     } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
         if (priv->monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
@@ -8379,10 +8380,10 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
             return -1;
         }
 
-        if ((tapfd = qemudPhysIfaceConnect(conn, driver, net,
-                                           qemuCmdFlags,
-                                           vm->def->uuid,
-                                           VIR_VM_OP_CREATE)) < 0)
+        if ((tapfd = qemuPhysIfaceConnect(conn, driver, net,
+                                          qemuCmdFlags,
+                                          vm->def->uuid,
+                                          VIR_VM_OP_CREATE)) < 0)
             return -1;
     }
 
@@ -8593,7 +8594,7 @@ static int qemudDomainAttachHostPciDevice(struct qemud_driver *driver,
         if (qemuDomainPCIAddressEnsureAddr(priv->pciaddrs, &hostdev->info) < 0)
             goto error;
         if (qemuCmdFlags & QEMUD_CMD_FLAG_PCI_CONFIGFD) {
-            configfd = qemudOpenPCIConfig(hostdev);
+            configfd = qemuOpenPCIConfig(hostdev);
             if (configfd >= 0) {
                 if (virAsprintf(&configfd_name, "fd-%s",
                                 hostdev->info.alias) < 0) {
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 409f6bd..7877731 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -32,7 +32,7 @@
 #include <sys/time.h>
 
 #include "qemu_monitor_json.h"
-#include "qemu_conf.h"
+#include "qemu_command.h"
 #include "memory.h"
 #include "logging.h"
 #include "driver.h"
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index 29e21ce..11a9391 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -31,7 +31,7 @@
 #include <string.h>
 
 #include "qemu_monitor_text.h"
-#include "qemu_conf.h"
+#include "qemu_command.h"
 #include "c-ctype.h"
 #include "memory.h"
 #include "logging.h"
-- 
1.7.2.3


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