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 :|