[libvirt] PATCH: 4/5: The hard QEMU implementation

Daniel P. Berrange berrange at redhat.com
Tue May 19 17:44:13 UTC 2009


On Wed, May 13, 2009 at 06:53:44PM +0200, Daniel Veillard wrote:
> On Wed, May 13, 2009 at 03:40:54PM +0100, Daniel P. Berrange wrote:
> > This provides the QEMU driver implementation which is able to convert
> > from QEMU argv into domain XML. This is alot of hard code, because we
> > have to parse and interpret arbitrary QEMU args and had no existing
> > code doing this. This is also actually the single most useful feature
> > of this patchset, and the original motivation. With this available, it
> > makes it very easy for people using QEMU to switch over to using libvirt

Here's an update with the VIR_REALLOCs in the loop changed to alloc in
chunks of 10. Also fixes a few misc bugs in the conversions, and the
style items pointed out last time.

Daniel

diff -r 832729f8dd03 src/domain_conf.h
--- a/src/domain_conf.h	Tue May 19 18:43:30 2009 +0100
+++ b/src/domain_conf.h	Tue May 19 18:43:59 2009 +0100
@@ -253,7 +253,7 @@ enum virDomainSoundModel {
     VIR_DOMAIN_SOUND_MODEL_SB16,
     VIR_DOMAIN_SOUND_MODEL_ES1370,
     VIR_DOMAIN_SOUND_MODEL_PCSPK,
-    VIR_DOMAIN_SOUND_MODEL_ES97,
+    VIR_DOMAIN_SOUND_MODEL_AC97,
 
     VIR_DOMAIN_SOUND_MODEL_LAST
 };
diff -r 832729f8dd03 src/qemu_conf.c
--- a/src/qemu_conf.c	Tue May 19 18:43:30 2009 +0100
+++ b/src/qemu_conf.c	Tue May 19 18:43:59 2009 +0100
@@ -1,5 +1,5 @@
 /*
- * config.c: VM configuration management
+ * qemu_conf.c: QEMU configuration management
  *
  * Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
@@ -36,6 +36,7 @@
 #include <arpa/inet.h>
 #include <sys/utsname.h>
 
+#include "c-ctype.h"
 #include "virterror_internal.h"
 #include "qemu_conf.h"
 #include "uuid.h"
@@ -1542,6 +1543,1229 @@ int qemudBuildCommandLine(virConnectPtr 
 }
 
 
+/*
+ * This method takes a string representing a QEMU command line ARGV set
+ * optionall 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 **progenv = NULL;
+    const char **progargv = NULL;
+
+    /* Iterate over string, splitting on sequences of ' ' */
+    while (curr && *curr != '\0') {
+        char *arg;
+        const char *next = strchr(curr, ' ');
+        if (!next)
+            next = strchr(curr, '\n');
+
+        if (next)
+            arg = strndup(curr, next-curr);
+        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 containining
+     * 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];
+        }
+        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);
+    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[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
+ */
+static int
+qemuParseCommandLineKeywords(virConnectPtr conn,
+                             const char *str,
+                             char ***retkeywords,
+                             char ***retvalues)
+{
+    int keywordCount = 0;
+    int keywordAlloc = 0;
+    char **keywords = NULL;
+    char **values = NULL;
+    const char *start = str;
+    int i;
+
+    *retkeywords = NULL;
+    *retvalues = NULL;
+
+    while (start) {
+        const char *separator;
+        const char *endmark;
+        char *keyword;
+        char *value;
+
+        if (!(separator = strchr(start, '='))) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("malformed keyword arguments in '%s'"), str);
+            goto error;
+        }
+        if (!(keyword = strndup(start, separator - start)))
+            goto no_memory;
+
+        separator++;
+        endmark = strchr(separator, ',');
+
+        value = endmark ?
+            strndup(separator, endmark - separator) :
+            strdup(separator);
+        if (!value) {
+            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 ? endmark + 1 : NULL;
+    }
+
+    *retkeywords = keywords;
+    *retvalues = values;
+
+    return keywordCount;
+
+no_memory:
+    virReportOOMError(conn);
+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(virConnectPtr conn,
+                         const char *val)
+{
+    virDomainDiskDefPtr def = NULL;
+    char **keywords;
+    char **values;
+    int nkeywords;
+    int i;
+    int idx = -1;
+
+    if ((nkeywords = qemuParseCommandLineKeywords(conn, val,
+                                                  &keywords,
+                                                  &values)) < 0)
+        return NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError(conn);
+        goto cleanup;
+    }
+
+    def->bus = VIR_DOMAIN_DISK_BUS_IDE;
+    def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+
+    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
+                    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(conn);
+                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], "index")) {
+            if (virStrToLong_i(values[i], NULL, 10, &idx) < 0) {
+                virDomainDiskDefFree(def);
+                def = NULL;
+                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                                 _("cannot parse drive index '%s'"), val);
+                goto cleanup;
+            }
+        }
+    }
+
+    if (!def->src &&
+        def->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("missing file parameter in drive '%s'"), val);
+        virDomainDiskDefFree(def);
+        def = NULL;
+        goto cleanup;
+    }
+    if (idx == -1) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("missing index parameter in drive '%s'"), val);
+        virDomainDiskDefFree(def);
+        def = NULL;
+        goto cleanup;
+    }
+
+    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(conn);
+        goto cleanup;
+    }
+    if (STREQ(def->dst, "xvda"))
+        def->dst[3] = 'a' + idx;
+    else
+        def->dst[2] = 'a' + idx;
+
+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(virConnectPtr conn,
+                   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)
+            tmp += strlen("vlan=");
+
+        if (virStrToLong_i(tmp, &end, 10, &gotvlan) < 0) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot parse NIC vlan in '%s'"), nics[i]);
+            return NULL;
+        }
+
+        if (gotvlan == wantvlan)
+            return nics[i];
+    }
+
+    qemudReportError(conn, NULL, NULL, 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(virConnectPtr conn,
+                        const char *val,
+                        int nnics,
+                        const char **nics)
+{
+    virDomainNetDefPtr def = NULL;
+    char **keywords;
+    char **values;
+    int nkeywords;
+    const char *nic;
+    int wantvlan = 0;
+    const char *tmp;
+    int i;
+
+    tmp = strchr(val, ',');
+    if (!tmp) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("cannot extract NIC type from '%s'"), val);
+        return NULL;
+    }
+
+    if ((nkeywords = qemuParseCommandLineKeywords(conn,
+                                                  tmp+1,
+                                                  &keywords,
+                                                  &values)) < 0)
+        return NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError(conn);
+        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) {
+                qemudReportError(conn, NULL, NULL, 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(conn, nnics, nics, wantvlan);
+    if (!nic) {
+        virDomainNetDefFree(def);
+        def = NULL;
+        goto cleanup;
+    }
+
+    if (!STRPREFIX(nic, "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 ((nkeywords = qemuParseCommandLineKeywords(conn,
+                                                  nic + strlen("nic,"),
+                                                  &keywords,
+                                                  &values)) < 0) {
+        virDomainNetDefFree(def);
+        def = NULL;
+        goto cleanup;
+    }
+
+    for (i = 0 ; i < nkeywords ; i++) {
+        if (STREQ(keywords[i], "macaddr")) {
+            virParseMacAddr(values[i], def->mac);
+        } else if (STREQ(keywords[i], "model")) {
+            def->model = values[i];
+            values[i] = NULL;
+        }
+    }
+
+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(virConnectPtr conn,
+                        const char *val)
+{
+    virDomainHostdevDefPtr def = NULL;
+    int bus = 0, slot = 0, func = 0;
+    const char *start;
+    char *end;
+
+    if (!STRPREFIX(val, "host=")) {
+        qemudReportError(conn, NULL, NULL, 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 || *end != ':') {
+        qemudReportError(conn, NULL, NULL, 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 || *end != '.') {
+        qemudReportError(conn, NULL, NULL, 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) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("cannot extract PCI device function '%s'"), val);
+        VIR_FREE(def);
+        goto cleanup;
+    }
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError(conn);
+        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(virConnectPtr conn,
+                        const char *val)
+{
+    virDomainHostdevDefPtr def = NULL;
+    int first = 0, second = 0;
+    const char *start;
+    char *end;
+
+    if (!STRPREFIX(val, "host:")) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("unknown PCI 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 || *end != ':') {
+            qemudReportError(conn, NULL, NULL, 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) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot extract PCI device product '%s'"), val);
+            VIR_FREE(def);
+            goto cleanup;
+        }
+    } else {
+        if (virStrToLong_i(start, &end, 10, &first) < 0 || !end || *end != '.') {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot extract PCI device bus '%s'"), val);
+            VIR_FREE(def);
+            goto cleanup;
+        }
+        start = end + 1;
+        if (virStrToLong_i(start, NULL, 10, &second) < 0) {
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("cannot extract PCI device address '%s'"), val);
+            VIR_FREE(def);
+            goto cleanup;
+        }
+    }
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError(conn);
+        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(virConnectPtr conn,
+                        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 (svc1) {
+            svc1++;
+            if (host2)
+                def->data.udp.connectService = strndup(svc1, host2-svc1);
+            else
+                def->data.udp.connectService = strdup(svc1);
+        }
+
+        if (host2) {
+            host2++;
+            if (svc2)
+                def->data.udp.bindHost = strndup(host2, svc2-host2);
+            else
+                def->data.udp.bindHost = strdup(host2);
+        }
+        if (svc2) {
+            svc2++;
+            def->data.udp.bindService = strdup(svc2);
+        }
+    } 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) {
+            qemudReportError(conn, NULL, NULL, 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);
+        svc++;
+        if (opt) {
+            def->data.tcp.service = strndup(svc, opt-svc);
+        } else {
+            def->data.tcp.service = strdup(svc);
+        }
+    } 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 {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         _("unknown character device syntax %s"), val);
+        goto error;
+    }
+
+    return def;
+
+no_memory:
+    virReportOOMError(conn);
+error:
+    virDomainChrDefFree(def);
+    return NULL;
+}
+
+/*
+ * 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(virConnectPtr conn,
+                                     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;
+
+    if (!progargv[0]) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                         "%s", _("no emulator path found"));
+        return NULL;
+    }
+
+    if (VIR_ALLOC(def) < 0)
+        goto no_memory;
+
+    def->id = -1;
+    def->memory = def->maxmem = 64 * 1024;
+    def->vcpus = 1;
+    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) {                                                        \
+        qemudReportError(conn, NULL, NULL, 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);
+                    qemudReportError(conn, NULL, NULL, 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) {
+                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, \
+                                 _("cannot parse memory level '%s'"), val);
+                goto error;
+            }
+            def->memory = def->maxmem = mem * 1024;
+        } else if (STREQ(arg, "-smp")) {
+            int vcpus;
+            WANT_VALUE();
+            if (virStrToLong_i(val, NULL, 10, &vcpus) < 0) {
+                qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, \
+                                 _("cannot parse CPU count '%s'"), val);
+                goto error;
+            }
+            def->vcpus = vcpus;
+        } else if (STREQ(arg, "-uuid")) {
+            WANT_VALUE();
+            if (virUUIDParse(val, def->uuid) < 0) {
+                qemudReportError(conn, NULL, NULL, 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
+                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->src ||
+                !disk->dst) {
+                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 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->localtime = 1;
+        } 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;
+            }
+            def->os.nBootDevs = b;
+        } else if (STREQ(arg, "-name")) {
+            WANT_VALUE();
+            if (!(def->name = strdup(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(conn, val)))
+                    goto error;
+                if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) {
+                    virDomainChrDefFree(chr);
+                    goto no_memory;
+                }
+                chr->dstPort = def->nserials;
+                def->serials[def->nserials++] = chr;
+            }
+        } else if (STREQ(arg, "-parallel")) {
+            WANT_VALUE();
+            if (STRNEQ(val, "none")) {
+                virDomainChrDefPtr chr;
+                if (!(chr = qemuParseCommandLineChr(conn, val)))
+                    goto error;
+                if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) {
+                    virDomainChrDefFree(chr);
+                    goto no_memory;
+                }
+                chr->dstPort = 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(conn, 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(conn, 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(conn, val)))
+                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, "-pcidevice")) {
+            virDomainHostdevDefPtr hostdev;
+            WANT_VALUE();
+            if (!(hostdev = qemuParseCommandLinePCI(conn, 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, "-bootloader")) {
+            WANT_VALUE();
+            def->os.bootloader = strdup(val);
+            if (!def->os.bootloader)
+                goto no_memory;
+        } 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 {
+            VIR_WARN(_("unknown QEMU argument '%s' during conversion"), arg);
+#if 0
+            qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                             _("unknown argument '%s'"), arg);
+            goto error;
+#endif
+        }
+    }
+
+#undef WANT_VALUE
+
+    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;
+    }
+
+    VIR_FREE(nics);
+
+    if (!def->name) {
+        if (!(def->name = strdup("unnamed")))
+            goto no_memory;
+    }
+
+    return def;
+
+no_memory:
+    virReportOOMError(conn);
+error:
+    virDomainDefFree(def);
+    VIR_FREE(nics);
+    return NULL;
+}
+
+
+virDomainDefPtr qemuParseCommandLineString(virConnectPtr conn,
+                                           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(conn, 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;
+}
+
+
 /* Called from SAX on parsing errors in the XML. */
 static void
 catchXMLError (void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
diff -r 832729f8dd03 src/qemu_conf.h
--- a/src/qemu_conf.h	Tue May 19 18:43:30 2009 +0100
+++ b/src/qemu_conf.h	Tue May 19 18:43:59 2009 +0100
@@ -1,5 +1,5 @@
 /*
- * config.h: VM configuration management
+ * qemu_conf.h: QEMU configuration management
  *
  * Copyright (C) 2006, 2007, 2009 Red Hat, Inc.
  * Copyright (C) 2006 Daniel P. Berrange
@@ -135,6 +135,12 @@ int         qemudBuildCommandLine       
                                          int *ntapfds,
                                          const char *migrateFrom);
 
+virDomainDefPtr qemuParseCommandLine(virConnectPtr conn,
+                                     const char **progenv,
+                                     const char **progargv);
+virDomainDefPtr qemuParseCommandLineString(virConnectPtr conn,
+                                           const char *args);
+
 const char *qemudVirtTypeToString       (int type);
 qemudDomainStatusPtr qemudDomainStatusParseFile(virConnectPtr conn,
                                                 virCapsPtr caps,
diff -r 832729f8dd03 src/qemu_driver.c
--- a/src/qemu_driver.c	Tue May 19 18:43:30 2009 +0100
+++ b/src/qemu_driver.c	Tue May 19 18:43:59 2009 +0100
@@ -3422,6 +3422,30 @@ cleanup:
 }
 
 
+static char *qemuDomainXMLFromNative(virConnectPtr conn,
+                                     const char *format,
+                                     const char *config,
+                                     unsigned int flags ATTRIBUTE_UNUSED) {
+    virDomainDefPtr def = NULL;
+    char *xml = NULL;
+
+    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
+        qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
+                         _("unsupported config type %s"), format);
+        goto cleanup;
+    }
+
+    def = qemuParseCommandLineString(conn, config);
+    if (!def)
+        goto cleanup;
+
+    xml = virDomainDefFormat(conn, def, VIR_DOMAIN_XML_INACTIVE);
+
+cleanup:
+    virDomainDefFree(def);
+    return xml;
+}
+
 static char *qemuDomainXMLToNative(virConnectPtr conn,
                                    const char *format,
                                    const char *xmlData,
@@ -3438,6 +3462,8 @@ static char *qemuDomainXMLToNative(virCo
     char *ret = NULL;
     int i;
 
+    qemuDriverLock(driver);
+
     if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
         qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
                          _("unsupported config type %s"), format);
@@ -3536,6 +3562,7 @@ static char *qemuDomainXMLToNative(virCo
     ret = virBufferContentAndReset(&buf);
 
 cleanup:
+    qemuDriverUnlock(driver);
     for (tmp = retargv ; tmp && *tmp ; tmp++)
         VIR_FREE(*tmp);
     VIR_FREE(retargv);
@@ -5351,7 +5378,7 @@ static virDriver qemuDriver = {
     qemudDomainGetSecurityLabel, /* domainGetSecurityLabel */
     qemudNodeGetSecurityModel, /* nodeGetSecurityModel */
     qemudDomainDumpXML, /* domainDumpXML */
-    NULL, /* domainXmlFromNative */
+    qemuDomainXMLFromNative, /* domainXmlFromNative */
     qemuDomainXMLToNative, /* domainXMLToNative */
     qemudListDefinedDomains, /* listDefinedDomains */
     qemudNumDefinedDomains, /* numOfDefinedDomains */
diff -r 832729f8dd03 src/vbox/vbox_tmpl.c
--- a/src/vbox/vbox_tmpl.c	Tue May 19 18:43:30 2009 +0100
+++ b/src/vbox/vbox_tmpl.c	Tue May 19 18:43:59 2009 +0100
@@ -1878,7 +1878,7 @@ static char *vboxDomainDumpXML(virDomain
                                 if (audioController == AudioControllerType_SB16) {
                                     def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_SB16;
                                 } else if (audioController == AudioControllerType_AC97) {
-                                    def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_ES97;
+                                    def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_AC97;
                                 }
                             } else {
                                 VIR_FREE(def->sounds);
@@ -2934,7 +2934,7 @@ static virDomainPtr vboxDomainDefineXML(
                     if (NS_SUCCEEDED(rc)) {
                         if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_SB16) {
                             audioAdapter->vtbl->SetAudioController(audioAdapter, AudioControllerType_SB16);
-                        } else if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_ES97) {
+                        } else if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_AC97) {
                             audioAdapter->vtbl->SetAudioController(audioAdapter, AudioControllerType_AC97);
                         }
                     }


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list