[libvirt] cannot migrate vm back to original machine
by Elaine Cheong
I am running Fedora 8 with Xen 3.1.2 and libvirt 0.4.3 on two machines
(machine #1 and #2). I am using virDomainMigrate() to migrate a VM
from machine #2 (where it originally resides) to machine #1. I am
unable to migrate the VM back to machine #2 using virDomainMigrate(),
even if I first migrate the VM from #2 to #1 by hand, using "xm
migrate -l <vmname> <ipaddress1>".
When I make the call to virDomainMigrate(domain_to_migrate,
connection_to_machine_2, VIR_MIGRATE_LIVE, NULL, NULL, 0), I get the
following message:
libvir: Xen Daemon error : POST operation failed: xend_post: error
from xen daemon: (xend.err "can't connect: Name or service not known")
I have tried running my program on both machine #2 (connecting to
machine #1 with ssh, and machine #2 with local (NULL) or ssh), and on
a separate 3rd machine (connecting to machine #1 and #2 with ssh), but
I get the same error message in both cases. I've tried connecting
with both virConnectOpen() and virConnectOpenReadOnly().
I don't see any obvious error messages when running libvirtd --
verbose, other than the one above, which shows up on machine #1.
There are no obvious error messages in libvirtd --verbose on machine #2.
I checked /var/log/xen/xend.log and xend-debug.log, but didn't see any
error message there either. My /etc/xen/xend-config.sxp is set with
default loglevel of DEBUG.
Any clues as to why I cannot migrate the VM back to the original
machine with libvirt? I am able to migrate it back from #1 to #2 by
hand using "xm migrate -l <vmname> <ipaddress2>".
Thanks,
Elaine
16 years, 6 months
[libvirt] [PATCH] minor Solaris patches
by Ryan Scott
Hi,
Most of the changes in the attached patch are trivial #ifdef
corrections for Solaris compilation.
The biggest part of the change gets 'virsh capabilities' running
correctly under Xen on Solaris.
Signed-off-by: Mark Johnson <Mark.Johnson(a)Sun.COM>
--- a/src/xs_internal.c
+++ b/src/xs_internal.c
@@ -35,7 +35,7 @@
#ifdef __linux__
#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"
-#elif define(__sun__)
+#elif defined(__sun)
#define XEN_HYPERVISOR_SOCKET "/dev/xen/privcmd"
#else
#error "unsupported platform"
--- a/src/xen_internal.c
+++ b/src/xen_internal.c
@@ -75,7 +75,7 @@ typedef struct v1_hypercall_struct
#define XEN_V1_IOCTL_HYPERCALL_CMD \
_IOC(_IOC_NONE, 'P', 0, sizeof(v1_hypercall_t))
typedef v1_hypercall_t hypercall_t;
-#elif define(__sun__)
+#elif defined(__sun)
typedef privcmd_hypercall_t hypercall_t;
#else
#error "unsupported platform"
@@ -340,8 +340,10 @@ lock_pages(void *addr, size_t len)
{
#ifdef __linux__
return (mlock(addr, len));
-#elif define(__sun)
+#elif defined(__sun)
return (0);
+#else
+#error "unsupported platform"
#endif
}
@@ -350,8 +352,10 @@ unlock_pages(void *addr, size_t len)
{
#ifdef __linux__
return (munlock(addr, len));
-#elif define(__sun)
+#elif defined(__sun)
return (0);
+#else
+#error "unsupported platform"
#endif
}
@@ -666,7 +670,7 @@ typedef struct xen_op_v2_dom xen_op_v2_d
#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"
#define HYPERVISOR_CAPABILITIES "/sys/hypervisor/properties/capabilities"
#define CPUINFO "/proc/cpuinfo"
-#elif define(__sun__)
+#elif defined(__sun)
#define XEN_HYPERVISOR_SOCKET "/dev/xen/privcmd"
#define HYPERVISOR_CAPABILITIES ""
#define CPUINFO "/dev/cpu/self/cpuid"
@@ -1948,7 +1952,7 @@ xenHypervisorInit(void)
goto detect_v2;
}
-#ifndef __sun__
+#ifndef __sun
/*
* check if the old hypercall are actually working
*/
@@ -2265,6 +2269,92 @@ xenHypervisorBuildCapabilities(virConnec
return NULL;
}
+#ifdef __linux__
+void
+loadCapabilities(FILE *cpuinfo, FILE *capabilities, char *hvm_type,
+ int *host_pae, char *line, int LINE_SIZE)
+{
+ regmatch_t subs[4];
+
+ /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
+ * It's not clear if this will work on IA64, let alone other
+ * architectures and non-Linux. (XXX)
+ */
+ if (cpuinfo) {
+ while (fgets (line, LINE_SIZE, cpuinfo)) {
+ if (regexec (&flags_hvm_rec, line,
+ sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0
+ && subs[0].rm_so != -1) {
+ strncpy (hvm_type,
+ &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1);
+ hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0';
+ } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0)
+ *host_pae = 1;
+ }
+ }
+
+ /* Expecting one line in this file - ignore any more. */
+ (void) fgets(line, LINE_SIZE, capabilities);
+}
+
+#else
+void
+loadCapabilities(FILE *cpuinfo, FILE *capabilities, char *hvm_type,
+ int *host_pae, char *line, int LINE_SIZE)
+{
+ struct {
+ uint32_t r_eax, r_ebx, r_ecx, r_edx;
+ } _r, *rp = &_r;
+ int d, cmd;
+ char *s;
+ hypercall_t hc;
+
+
+ if ((d = open(CPUINFO, O_RDONLY)) == -1) {
+ goto cpuinfo_open_fail;
+ }
+
+ if (pread(d, rp, sizeof (*rp), 0) != sizeof (*rp)) {
+ goto cpuinfo_pread_fail;
+ }
+
+ s = (char *)&rp->r_ebx;
+ if (strncmp(s, "Auth" "cAMD" "enti", 12) == 0) {
+ if (pread(d, rp, sizeof (*rp), 0x80000001) == sizeof (*rp)) {
+ /* Read secure virtual machine bit (bit 2 of ECX feature ID) */
+ if ((rp->r_ecx >> 2) & 1) {
+ strcpy(hvm_type, "svm");
+ }
+ if ((rp->r_edx >> 6) & 1) {
+ *host_pae = 1;
+ }
+ }
+ } else if (strncmp(s, "Genu" "ntel" "ineI", 12) == 0) {
+ if (pread(d, rp, sizeof (*rp), 0x00000001) == sizeof (*rp)) {
+ /* Read VMXE feature bit (bit 5 of ECX feature ID) */
+ if ((rp->r_ecx >> 5) & 1) {
+ strcpy(hvm_type, "vmx");
+ }
+ if ((rp->r_edx >> 6) & 1) {
+ *host_pae = 1;
+ }
+ }
+ }
+cpuinfo_pread_fail:
+ (void) close(d);
+cpuinfo_open_fail:
+
+ d = open(XEN_HYPERVISOR_SOCKET, O_RDWR);
+ hc.op = __HYPERVISOR_xen_version;
+ hc.arg[0] = (unsigned long) XENVER_capabilities;
+ hc.arg[1] = (unsigned long) line;
+ cmd = IOCTL_PRIVCMD_HYPERCALL;
+ (void) ioctl(d, cmd, (unsigned long) &hc);
+ close(d);
+}
+
+#endif
+
/**
* xenHypervisorGetCapabilities:
* @conn: pointer to the connection block
@@ -2278,7 +2368,8 @@ xenHypervisorMakeCapabilitiesXML(virConn
const char *hostmachine,
FILE *cpuinfo, FILE *capabilities)
{
- char line[1024], *str, *token;
+ const int LINE_SIZE = 1024;
+ char line[LINE_SIZE], *str, *token;
regmatch_t subs[4];
char *saveptr = NULL;
int i;
@@ -2295,24 +2386,12 @@ xenHypervisorMakeCapabilitiesXML(virConn
memset(guest_archs, 0, sizeof(guest_archs));
- /* /proc/cpuinfo: flags: Intel calls HVM "vmx", AMD calls it "svm".
- * It's not clear if this will work on IA64, let alone other
- * architectures and non-Linux. (XXX)
- */
- if (cpuinfo) {
- while (fgets (line, sizeof line, cpuinfo)) {
- if (regexec (&flags_hvm_rec, line, sizeof(subs)/sizeof(regmatch_t), subs, 0) == 0
- && subs[0].rm_so != -1) {
- strncpy (hvm_type,
- &line[subs[1].rm_so], subs[1].rm_eo-subs[1].rm_so+1);
- hvm_type[subs[1].rm_eo-subs[1].rm_so] = '\0';
- } else if (regexec (&flags_pae_rec, line, 0, NULL, 0) == 0)
- host_pae = 1;
- }
- }
+ memset(line, 0, sizeof(line));
+ loadCapabilities(cpuinfo, capabilities, hvm_type, &host_pae, line,
+ LINE_SIZE);
- /* Most of the useful info is in /sys/hypervisor/properties/capabilities
- * which is documented in the code in xen-unstable.hg/xen/arch/.../setup.c.
+ /* The capabilities line is documented in the code in
+ * xen-unstable.hg/xen/arch/.../setup.c.
*
* It is a space-separated list of supported guest architectures.
*
@@ -2335,80 +2414,77 @@ xenHypervisorMakeCapabilitiesXML(virConn
* +--------------- "xen" or "hvm" for para or full virt respectively
*/
- /* Expecting one line in this file - ignore any more. */
- if ((capabilities) && (fgets (line, sizeof line, capabilities))) {
- /* Split the line into tokens. strtok_r is OK here because we "own"
- * this buffer. Parse out the features from each token.
- */
- for (str = line, nr_guest_archs = 0;
- nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0]
- && (token = strtok_r (str, " ", &saveptr)) != NULL;
- str = NULL) {
-
- if (regexec (&xen_cap_rec, token, sizeof subs / sizeof subs[0],
- subs, 0) == 0) {
- int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
- const char *model;
- int bits, pae = 0, nonpae = 0, ia64_be = 0;
-
- if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
- model = "i686";
- bits = 32;
- if (subs[3].rm_so != -1 &&
- STRPREFIX(&token[subs[3].rm_so], "p"))
- pae = 1;
- else
- nonpae = 1;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
- model = "x86_64";
- bits = 64;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
- model = "ia64";
- bits = 64;
- if (subs[3].rm_so != -1 &&
- STRPREFIX(&token[subs[3].rm_so], "be"))
- ia64_be = 1;
- }
- else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
- model = "ppc64";
- bits = 64;
- } else {
- /* XXX surely no other Xen archs exist */
- continue;
- }
+ /* Split the line into tokens. strtok_r is OK here because we "own"
+ * this buffer. Parse out the features from each token.
+ */
+ for (str = line, nr_guest_archs = 0;
+ nr_guest_archs < sizeof guest_archs / sizeof guest_archs[0]
+ && (token = strtok_r (str, " ", &saveptr)) != NULL;
+ str = NULL) {
+
+ if (regexec (&xen_cap_rec, token, sizeof subs / sizeof subs[0],
+ subs, 0) == 0) {
+ int hvm = STRPREFIX(&token[subs[1].rm_so], "hvm");
+ const char *model;
+ int bits, pae = 0, nonpae = 0, ia64_be = 0;
+
+ if (STRPREFIX(&token[subs[2].rm_so], "x86_32")) {
+ model = "i686";
+ bits = 32;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "p"))
+ pae = 1;
+ else
+ nonpae = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "x86_64")) {
+ model = "x86_64";
+ bits = 64;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "ia64")) {
+ model = "ia64";
+ bits = 64;
+ if (subs[3].rm_so != -1 &&
+ STRPREFIX(&token[subs[3].rm_so], "be"))
+ ia64_be = 1;
+ }
+ else if (STRPREFIX(&token[subs[2].rm_so], "powerpc64")) {
+ model = "ppc64";
+ bits = 64;
+ } else {
+ /* XXX surely no other Xen archs exist */
+ continue;
+ }
- /* Search for existing matching (model,hvm) tuple */
- for (i = 0 ; i < nr_guest_archs ; i++) {
- if (STREQ(guest_archs[i].model, model) &&
- guest_archs[i].hvm == hvm) {
- break;
- }
+ /* Search for existing matching (model,hvm) tuple */
+ for (i = 0 ; i < nr_guest_archs ; i++) {
+ if (STREQ(guest_archs[i].model, model) &&
+ guest_archs[i].hvm == hvm) {
+ break;
}
-
- /* Too many arch flavours - highly unlikely ! */
- if (i >= sizeof(guest_archs)/sizeof(guest_archs[0]))
- continue;
- /* Didn't find a match, so create a new one */
- if (i == nr_guest_archs)
- nr_guest_archs++;
-
- guest_archs[i].model = model;
- guest_archs[i].bits = bits;
- guest_archs[i].hvm = hvm;
-
- /* Careful not to overwrite a previous positive
- setting with a negative one here - some archs
- can do both pae & non-pae, but Xen reports
- separately capabilities so we're merging archs */
- if (pae)
- guest_archs[i].pae = pae;
- if (nonpae)
- guest_archs[i].nonpae = nonpae;
- if (ia64_be)
- guest_archs[i].ia64_be = ia64_be;
}
+
+ /* Too many arch flavours - highly unlikely ! */
+ if (i >= sizeof(guest_archs)/sizeof(guest_archs[0]))
+ continue;
+ /* Didn't find a match, so create a new one */
+ if (i == nr_guest_archs)
+ nr_guest_archs++;
+
+ guest_archs[i].model = model;
+ guest_archs[i].bits = bits;
+ guest_archs[i].hvm = hvm;
+
+ /* Careful not to overwrite a previous positive
+ setting with a negative one here - some archs
+ can do both pae & non-pae, but Xen reports
+ separately capabilities so we're merging archs */
+ if (pae)
+ guest_archs[i].pae = pae;
+ if (nonpae)
+ guest_archs[i].nonpae = nonpae;
+ if (ia64_be)
+ guest_archs[i].ia64_be = ia64_be;
}
}
@@ -2447,29 +2523,33 @@ xenHypervisorGetCapabilities (virConnect
/* Really, this never fails - look at the man-page. */
uname (&utsname);
- cpuinfo = fopen ("/proc/cpuinfo", "r");
+#ifdef __linux__
+ cpuinfo = fopen (CPUINFO, "r");
if (cpuinfo == NULL) {
if (errno != ENOENT) {
- virXenPerror (conn, "/proc/cpuinfo");
+ virXenPerror (conn, CPUINFO);
return NULL;
}
}
- capabilities = fopen ("/sys/hypervisor/properties/capabilities", "r");
+ capabilities = fopen (HYPERVISOR_CAPABILITIES, "r");
if (capabilities == NULL) {
if (errno != ENOENT) {
fclose(cpuinfo);
- virXenPerror (conn, "/sys/hypervisor/properties/capabilities");
+ virXenPerror (conn, HYPERVISOR_CAPABILITIES);
return NULL;
}
}
+#endif
xml = xenHypervisorMakeCapabilitiesXML(conn, utsname.machine, cpuinfo, capabilities);
+#ifdef __linux__
if (cpuinfo)
fclose(cpuinfo);
if (capabilities)
fclose(capabilities);
+#endif
return xml;
}
16 years, 6 months
[libvirt] [PATCH] Change virsh list behavior
by Ryan Scott
At the popular request of pretty much everyone in Sun who uses virsh...
Change virsh list to list all domains, and add an "--active" flag to
list only the active domains.
Signed-off-by: Ryan Scott <ryan.scott(a)sun.com>
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -551,6 +551,7 @@ static vshCmdInfo info_list[] = {
static vshCmdOptDef opts_list[] = {
{"inactive", VSH_OT_BOOL, 0, gettext_noop("list inactive domains")},
+ {"active", VSH_OT_BOOL, 0, gettext_noop("list only active domains")},
{"all", VSH_OT_BOOL, 0, gettext_noop("list inactive & active domains")},
{NULL, 0, 0, NULL}
};
@@ -559,13 +560,17 @@ static vshCmdOptDef opts_list[] = {
static int
cmdList(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
{
- int inactive = vshCommandOptBool(cmd, "inactive");
+ int inactiveOpt = vshCommandOptBool(cmd, "inactive");
+ int activeOpt = vshCommandOptBool(cmd, "active");
int all = vshCommandOptBool(cmd, "all");
- int active = !inactive || all ? 1 : 0;
+ int active, inactive;
int *ids = NULL, maxid = 0, i;
char **names = NULL;
int maxname = 0;
- inactive |= all;
+
+ /* If no options are specified, default to both active and inactive */
+ active = activeOpt || all || !inactiveOpt;
+ inactive = inactiveOpt || all || !activeOpt;
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
16 years, 6 months
[libvirt] [PATCH 0 of 4] [LXC] RFC: Network interface support
by Dan Smith
I think I have addressed all of the comments. Changes detailed per patch.
I converted to using a dynamic detection routine for determining NETNS
support, which I think is much better. That is pulled out into a separate
patch for easier distinction.
Thanks!
16 years, 6 months
[libvirt] PATCH: Generic internal API for domain XML parser/formatter
by Daniel P. Berrange
We currently have five drivers which handle the domain XML containing
duplicated parsers and formatters for the XML with varying degrees of
buginess, and often very similar structs. This patch introduces a new
general purpose internal API for parsing and formatting network XML,
and representing it as a series of structs.
This code is derived from the current equivalent code in the QEMU driver
for domains, but with alot of extra config parsing added for stuff needed
by the Xen drivers. I have not yet added the extra bits needed by the
container based drivers, LXC and OpenVZ, but don't anticipate any problems
in this regard.
Again the naming conventions I'm adopting in this patch follow those in
the storage and network drivers:
- virDomainPtr - the public opaque object in libvirt.h
- virDomainObjPtr - the primary internal object for domain state
- virDomainDefPtr - the configuration data for a domain
A virDomainObjPtr contains a reference to one or two virDomainDefPtr
objects - the current live config, and potentially a secondary inactive
config which will become live at the next restart.
The structs are defined in domain_conf.h, along with a bunch of APIs for
dealing with them. These APIs are the same as similarly named ones from
the current qemu driver, but I'll go over them again for a reminder:
virDomainObjPtr virDomainFindByUUID(const virDomainObjPtr doms,
const unsigned char *uuid);
virDomainObjPtr virDomainFindByName(const virDomainObjPtr doms,
const char *name);
virDomainObjPtr virDomainFindByID(const virDomainObjPtr doms,
const char *id);
Allow lookup of a virDomainObjPtr object based on its name, ID or UUID,
as typically obtained from the public virDomainPtr object.
The 'doms' parameter to both of thse is a linked list of domains which
are currently known to the driver using this API. Not all drivers will
use these APIs - the Xen driver will just query XenD - these are only
for drivers which maintain state internally with the libvirt daemon.
void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
void virDomainInputDefFree(virDomainInputDefPtr def);
void virDomainDiskDefFree(virDomainDiskDefPtr def);
void virDomainNetDefFree(virDomainNetDefPtr def);
void virDomainChrDefFree(virDomainChrDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
void virDomainDefFree(virDomainDefPtr def);
void virDomainObjFree(virDomainObjPtr net);
Convenience APIs to totally free the memory associated with these
objects.
virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
virDomainObjPtr *doms,
const virDomainDefPtr def);
Given a virDomainDefPtr object, it'll search for a pre-existing
virDomainObjPtr object with matching config. If one is found, its
config will be updated, otherwise a new object will be allocated.
void virDomainRemoveInactive(virDomainObjPtr *doms,
const virDomainObjPtr dom);
Convenience for removing and free'ing a virDomainObjPtr object in
the current list of active domains.
virDomainDefPtr virDomainDefParse(virConnectPtr conn,
virCapsPtr caps,
const char *xmlStr,
const char *displayName);
Given an XML document describing a network, parses the doc and generates
a virDomainDefPtr to represent it in memory. This is a little more
advanced than the network parser because the various hypervisor drivers
have slightly varying capabilities. So we pass a virCapsPtr object in
so the parser can validate against the actual driver's capabilities.
I'd like to extend the capabilities format to cover things like the
boot parameters supported - eg PXE vs kernel+initrd vs bootloader vs
BIOS, so we can further validate at time of parsing, instead of time
of use.
char *virDomainDefFormat(virConnectPtr conn,
const virDomainDefPtr def,
int secure);
Given a virDomainDefPtr object, generate a XML document describing the
domain. The secure flag controls whether passwords are included in the
XML output.
int virDomainCpuSetParse(virConnectPtr conn,
const char **str,
char sep,
char *cpuset,
int maxcpu);
char *virDomainCpuSetFormat(virConnectPtr conn,
char *cpuset,
int maxcpu);
These are just the APIs for dealing with CPU ranges moved from the xml.c
file so they are in the expected place. A future patch will remove them
from xml.c when the Xen driver is ported to this API.
VIR_ENUM_DECL(virDomainVirt)
VIR_ENUM_DECL(virDomainBoot)
VIR_ENUM_DECL(virDomainFeature)
VIR_ENUM_DECL(virDomainLifecycle)
VIR_ENUM_DECL(virDomainDisk)
VIR_ENUM_DECL(virDomainDiskDevice)
VIR_ENUM_DECL(virDomainDiskBus)
VIR_ENUM_DECL(virDomainNet)
VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainSoundModel)
VIR_ENUM_DECL(virDomainInput)
VIR_ENUM_DECL(virDomainInputBus)
VIR_ENUM_DECL(virDomainGraphics)
This provides prototypes for all the enumerations useful to drivers using
this API and struct definitions.
As a mentioned earlier, the impl of these APIs is just copied from the QEMU
driver, but instead of using pre-declared char[PATH_MAX] fields, we allocate
memory for strings as required. This dramatically reduces the memory needs
of the QEMU driver (when ported to this API). It also switches to use the
xml.c convenience routines instead of the regular libxml2 APIs, and in doing
so I added a couple more convenience routines.
There is no test suite explicitly against these parsers because when the
QEMU and Xen drivers are ported to this API their existing test suites
exercise nearly all the code.
Regards,
Daniel.
diff -r f47fdc49c62f src/Makefile.am
--- a/src/Makefile.am Sun Jun 22 17:58:48 2008 -0400
+++ b/src/Makefile.am Sun Jun 22 18:31:20 2008 -0400
@@ -39,6 +39,7 @@
test.c test.h \
buf.c buf.h \
qparams.c qparams.h \
+ domain_conf.c domain_conf.h \
capabilities.c capabilities.h \
xml.c xml.h \
event.c event.h \
diff -r f47fdc49c62f src/domain_conf.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/domain_conf.c Sun Jun 22 18:31:20 2008 -0400
@@ -0,0 +1,2621 @@
+/*
+ * domain_conf.c: domain XML processing
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2008 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(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include "internal.h"
+
+#include "domain_conf.h"
+#include "memory.h"
+#include "verify.h"
+#include "xml.h"
+#include "uuid.h"
+#include "util.h"
+#include "buf.h"
+#include "c-ctype.h"
+
+VIR_ENUM_IMPL(virDomainVirt, VIR_DOMAIN_VIRT_LAST,
+ "qemu",
+ "kqemu",
+ "kvm",
+ "xen",
+ "lxc",
+ "uml",
+ "openvz",
+ "vserver",
+ "ldom",
+ "test",
+ "vmware",
+ "hyperv")
+
+VIR_ENUM_IMPL(virDomainBoot, VIR_DOMAIN_BOOT_LAST,
+ "fd",
+ "cdrom",
+ "hd",
+ "network")
+
+VIR_ENUM_IMPL(virDomainFeature, VIR_DOMAIN_FEATURE_LAST,
+ "acpi",
+ "apic",
+ "pae")
+
+VIR_ENUM_IMPL(virDomainLifecycle, VIR_DOMAIN_LIFECYCLE_LAST,
+ "destroy",
+ "restart",
+ "rename-restart",
+ "preserve")
+
+VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST,
+ "block",
+ "file")
+
+VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST,
+ "disk",
+ "cdrom",
+ "floppy")
+
+VIR_ENUM_IMPL(virDomainDiskBus, VIR_DOMAIN_DISK_BUS_LAST,
+ "ide",
+ "fdc",
+ "scsi",
+ "virtio",
+ "xen")
+
+VIR_ENUM_IMPL(virDomainNet, VIR_DOMAIN_NET_TYPE_LAST,
+ "user",
+ "ethernet",
+ "server",
+ "client",
+ "mcast",
+ "network",
+ "bridge")
+
+VIR_ENUM_IMPL(virDomainChr, VIR_DOMAIN_CHR_TYPE_LAST,
+ "null",
+ "vc",
+ "pty",
+ "dev",
+ "file",
+ "pipe",
+ "stdio",
+ "udp",
+ "tcp",
+ "unix")
+
+VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
+ "sb16",
+ "es1370",
+ "pcspk");
+
+VIR_ENUM_IMPL(virDomainInput, VIR_DOMAIN_INPUT_TYPE_LAST,
+ "mouse",
+ "tablet")
+
+VIR_ENUM_IMPL(virDomainInputBus, VIR_DOMAIN_INPUT_BUS_LAST,
+ "ps2",
+ "usb",
+ "xen")
+
+VIR_ENUM_IMPL(virDomainGraphics, VIR_DOMAIN_GRAPHICS_TYPE_LAST,
+ "sdl",
+ "vnc")
+
+
+static void virDomainReportError(virConnectPtr conn,
+ int code, const char *fmt, ...)
+{
+ va_list args;
+ char errorMessage[1024];
+ const char *virerr;
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args);
+ va_end(args);
+ } else {
+ errorMessage[0] = '\0';
+ }
+
+ virerr = __virErrorMsg(code, (errorMessage[0] ? errorMessage : NULL));
+ __virRaiseError(conn, NULL, NULL, VIR_FROM_QEMU, code, VIR_ERR_ERROR,
+ virerr, errorMessage, NULL, -1, -1, virerr, errorMessage);
+}
+
+
+virDomainObjPtr virDomainFindByID(const virDomainObjPtr doms,
+ int id)
+{
+ virDomainObjPtr dom = doms;
+ while (dom) {
+ if (virDomainIsActive(dom) && dom->def->id == id)
+ return dom;
+ dom = dom->next;
+ }
+
+ return NULL;
+}
+
+
+virDomainObjPtr virDomainFindByUUID(const virDomainObjPtr doms,
+ const unsigned char *uuid)
+{
+ virDomainObjPtr dom = doms;
+
+ while (dom) {
+ if (!memcmp(dom->def->uuid, uuid, VIR_UUID_BUFLEN))
+ return dom;
+ dom = dom->next;
+ }
+
+ return NULL;
+}
+
+virDomainObjPtr virDomainFindByName(const virDomainObjPtr doms,
+ const char *name)
+{
+ virDomainObjPtr dom = doms;
+
+ while (dom) {
+ if (STREQ(dom->def->name, name))
+ return dom;
+ dom = dom->next;
+ }
+
+ return NULL;
+}
+
+void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def)
+{
+ if (!def)
+ return;
+
+ switch (def->type) {
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ VIR_FREE(def->data.vnc.listenAddr);
+ VIR_FREE(def->data.vnc.keymap);
+ VIR_FREE(def->data.vnc.passwd);
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ VIR_FREE(def->data.sdl.display);
+ VIR_FREE(def->data.sdl.xauth);
+ break;
+ }
+
+ VIR_FREE(def);
+}
+
+void virDomainInputDefFree(virDomainInputDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainInputDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainDiskDefFree(virDomainDiskDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->src);
+ VIR_FREE(def->dst);
+ VIR_FREE(def->driverName);
+ VIR_FREE(def->driverType);
+
+ virDomainDiskDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainNetDefFree(virDomainNetDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->model);
+
+ switch (def->type) {
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ VIR_FREE(def->dst.ethernet.ifname);
+ VIR_FREE(def->dst.ethernet.script);
+ VIR_FREE(def->dst.ethernet.ipaddr);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ VIR_FREE(def->dst.socket.address);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ VIR_FREE(def->dst.network.name);
+ VIR_FREE(def->dst.network.ifname);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ VIR_FREE(def->dst.bridge.brname);
+ VIR_FREE(def->dst.bridge.ifname);
+ break;
+ }
+
+ virDomainNetDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainChrDefFree(virDomainChrDefPtr def)
+{
+ if (!def)
+ return;
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ VIR_FREE(def->data.file.path);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ VIR_FREE(def->data.udp.bindHost);
+ VIR_FREE(def->data.udp.bindService);
+ VIR_FREE(def->data.udp.connectHost);
+ VIR_FREE(def->data.udp.connectService);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ VIR_FREE(def->data.tcp.host);
+ VIR_FREE(def->data.tcp.service);
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ VIR_FREE(def->data.nix.path);
+ break;
+ }
+
+ virDomainChrDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainSoundDefFree(virDomainSoundDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainSoundDefFree(def->next);
+ VIR_FREE(def);
+}
+
+void virDomainDefFree(virDomainDefPtr def)
+{
+ if (!def)
+ return;
+
+ virDomainGraphicsDefFree(def->graphics);
+ virDomainInputDefFree(def->inputs);
+ virDomainDiskDefFree(def->disks);
+ virDomainNetDefFree(def->nets);
+ virDomainChrDefFree(def->serials);
+ virDomainChrDefFree(def->parallels);
+ virDomainChrDefFree(def->console);
+ virDomainSoundDefFree(def->sounds);
+
+
+ VIR_FREE(def->os.type);
+ VIR_FREE(def->os.arch);
+ VIR_FREE(def->os.machine);
+ VIR_FREE(def->os.kernel);
+ VIR_FREE(def->os.initrd);
+ VIR_FREE(def->os.cmdline);
+ VIR_FREE(def->os.root);
+ VIR_FREE(def->os.loader);
+ VIR_FREE(def->os.bootloader);
+ VIR_FREE(def->os.bootloaderArgs);
+
+ VIR_FREE(def->name);
+ VIR_FREE(def->cpumask);
+ VIR_FREE(def->emulator);
+
+ VIR_FREE(def);
+}
+
+void virDomainObjFree(virDomainObjPtr dom)
+{
+ if (!dom)
+ return;
+
+ virDomainDefFree(dom->def);
+ virDomainDefFree(dom->newDef);
+
+ VIR_FREE(dom->vcpupids);
+ VIR_FREE(dom->configFile);
+ VIR_FREE(dom->autostartLink);
+
+ VIR_FREE(dom);
+}
+
+virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
+ virDomainObjPtr *doms,
+ const virDomainDefPtr def)
+{
+ virDomainObjPtr domain;
+
+ if ((domain = virDomainFindByName(*doms, def->name))) {
+ if (!virDomainIsActive(domain)) {
+ virDomainDefFree(domain->def);
+ domain->def = def;
+ } else {
+ if (domain->newDef)
+ virDomainDefFree(domain->newDef);
+ domain->newDef = def;
+ }
+
+ return domain;
+ }
+
+ if (VIR_ALLOC(domain) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ domain->def = def;
+ domain->next = *doms;
+
+ *doms = domain;
+
+ return domain;
+}
+
+void virDomainRemoveInactive(virDomainObjPtr *doms,
+ virDomainObjPtr dom)
+{
+ virDomainObjPtr prev = NULL;
+ virDomainObjPtr curr = *doms;
+
+ while (curr &&
+ curr != dom) {
+ prev = curr;
+ curr = curr->next;
+ }
+
+ if (curr) {
+ if (prev)
+ prev->next = curr->next;
+ else
+ *doms = curr->next;
+ }
+
+ virDomainObjFree(dom);
+}
+
+static int virDomainDiskCompare(virDomainDiskDefPtr a,
+ virDomainDiskDefPtr b) {
+ if (a->bus == b->bus)
+ return virDiskNameToIndex(a->dst) - virDiskNameToIndex(b->dst);
+ else
+ return a->bus - b->bus;
+}
+
+
+/* Parse the XML definition for a disk
+ * @param node XML nodeset to parse for disk definition
+ */
+static virDomainDiskDefPtr
+virDomainDiskDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ virDomainDiskDefPtr def;
+ xmlNodePtr cur;
+ char *type = NULL;
+ char *device = NULL;
+ char *driverName = NULL;
+ char *driverType = NULL;
+ char *source = NULL;
+ char *target = NULL;
+ char *bus = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+ if (type) {
+ if ((def->type = virDomainDiskTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown disk type '%s'"), type);
+ goto error;
+ }
+ } else {
+ def->type = VIR_DOMAIN_DISK_TYPE_FILE;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if ((source == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+
+ if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
+ source = virXMLPropString(cur, "file");
+ else
+ source = virXMLPropString(cur, "dev");
+ } else if ((target == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "target"))) {
+ target = virXMLPropString(cur, "dev");
+ bus = virXMLPropString(cur, "bus");
+ } else if ((driverName == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "driver"))) {
+ driverName = virXMLPropString(cur, "name");
+ driverType = virXMLPropString(cur, "type");
+ } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
+ def->readonly = 1;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
+ def->shared = 1;
+ }
+ }
+ cur = cur->next;
+ }
+
+ device = virXMLPropString(node, "device");
+ if (device) {
+ if ((def->device = virDomainDiskDeviceTypeFromString(device)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown disk device '%s'"), device);
+ goto error;
+ }
+ } else {
+ def->device = VIR_DOMAIN_DISK_DEVICE_DISK;
+ }
+
+ /* Only CDROM and Floppy devices are allowed missing source path
+ * to indicate no media present */
+ if (source == NULL &&
+ def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
+ def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+ virDomainReportError(conn, VIR_ERR_NO_SOURCE,
+ target ? "%s" : NULL, target);
+ goto error;
+ }
+
+ if (target == NULL) {
+ virDomainReportError(conn, VIR_ERR_NO_TARGET,
+ source ? "%s" : NULL, source);
+ goto error;
+ }
+
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
+ !STRPREFIX(target, "fd")) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid floppy device name: %s"), target);
+ goto error;
+ }
+
+ /* Force CDROM to be listed as read only */
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
+ def->readonly = 1;
+
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+ !STRPREFIX((const char *)target, "hd") &&
+ !STRPREFIX((const char *)target, "sd") &&
+ !STRPREFIX((const char *)target, "vd") &&
+ !STRPREFIX((const char *)target, "xvd")) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid harddisk device name: %s"), target);
+ goto error;
+ }
+
+ if (bus) {
+ if ((def->bus = virDomainDiskBusTypeFromString(bus)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown disk bus type '%s'"), bus);
+ goto error;
+ }
+ } else {
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
+ def->bus = VIR_DOMAIN_DISK_BUS_FDC;
+ } else {
+ if (STRPREFIX(target, "hd"))
+ def->bus = VIR_DOMAIN_DISK_BUS_IDE;
+ else if (STRPREFIX(target, "sd"))
+ def->bus = VIR_DOMAIN_DISK_BUS_SCSI;
+ else if (STRPREFIX(target, "vd"))
+ def->bus = VIR_DOMAIN_DISK_BUS_VIRTIO;
+ else if (STRPREFIX(target, "xvd"))
+ def->bus = VIR_DOMAIN_DISK_BUS_XEN;
+ else
+ def->bus = VIR_DOMAIN_DISK_BUS_IDE;
+ }
+ }
+
+ if (def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
+ def->bus != VIR_DOMAIN_DISK_BUS_FDC) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid bus type '%s' for floppy disk"), bus);
+ goto error;
+ }
+ if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY &&
+ def->bus == VIR_DOMAIN_DISK_BUS_FDC) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid bus type '%s' for disk"), bus);
+ goto error;
+ }
+
+ def->src = source;
+ source = NULL;
+ def->dst = target;
+ target = NULL;
+ def->driverName = driverName;
+ driverName = NULL;
+ def->driverType = driverType;
+ driverType = NULL;
+
+cleanup:
+ VIR_FREE(bus);
+ VIR_FREE(type);
+ VIR_FREE(target);
+ VIR_FREE(source);
+ VIR_FREE(device);
+ VIR_FREE(driverType);
+ VIR_FREE(driverName);
+
+ return def;
+
+ error:
+ virDomainDiskDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+static void virDomainNetRandomMAC(virDomainNetDefPtr def) {
+ /* XXX there different vendor prefixes per hypervisor */
+ def->mac[0] = 0x52;
+ def->mac[1] = 0x54;
+ def->mac[2] = 0x00;
+ def->mac[3] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+ def->mac[4] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+ def->mac[5] = 1 + (int)(256*(rand()/(RAND_MAX+1.0)));
+}
+
+
+/* Parse the XML definition for a network interface
+ * @param node XML nodeset to parse for net definition
+ * @return 0 on success, -1 on failure
+ */
+static virDomainNetDefPtr
+virDomainNetDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ virDomainNetDefPtr def;
+ xmlNodePtr cur;
+ char *macaddr = NULL;
+ char *type = NULL;
+ char *network = NULL;
+ char *bridge = NULL;
+ char *ifname = NULL;
+ char *script = NULL;
+ char *address = NULL;
+ char *port = NULL;
+ char *model = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+ if (type != NULL) {
+ if ((def->type = virDomainNetTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown interface type '%s'"), type);
+ goto error;
+ }
+ } else {
+ def->type = VIR_DOMAIN_NET_TYPE_USER;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if ((macaddr == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "mac"))) {
+ macaddr = virXMLPropString(cur, "address");
+ } else if ((network == NULL) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_NETWORK) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ network = virXMLPropString(cur, "network");
+ } else if ((network == NULL) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ bridge = virXMLPropString(cur, "bridge");
+ } else if ((network == NULL) &&
+ ((def->type == VIR_DOMAIN_NET_TYPE_SERVER) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_CLIENT) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_MCAST)) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ address = virXMLPropString(cur, "address");
+ port = virXMLPropString(cur, "port");
+ } else if ((address == NULL) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET) &&
+ (xmlStrEqual(cur->name, BAD_CAST "ip"))) {
+ address = virXMLPropString(cur, "address");
+ } else if ((ifname == NULL) &&
+ ((def->type == VIR_DOMAIN_NET_TYPE_NETWORK) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET) ||
+ (def->type == VIR_DOMAIN_NET_TYPE_BRIDGE)) &&
+ xmlStrEqual(cur->name, BAD_CAST "target")) {
+ ifname = virXMLPropString(cur, "dev");
+ if (STRPREFIX((const char*)ifname, "vnet")) {
+ /* An auto-generated target name, blank it out */
+ VIR_FREE(ifname);
+ ifname = NULL;
+ }
+ } else if ((script == NULL) &&
+ (def->type == VIR_DOMAIN_NET_TYPE_ETHERNET) &&
+ xmlStrEqual(cur->name, BAD_CAST "script")) {
+ script = virXMLPropString(cur, "path");
+ } else if (xmlStrEqual (cur->name, BAD_CAST "model")) {
+ model = virXMLPropString(cur, "type");
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (macaddr) {
+ unsigned int mac[6];
+ sscanf((const char *)macaddr, "%02x:%02x:%02x:%02x:%02x:%02x",
+ (unsigned int*)&mac[0],
+ (unsigned int*)&mac[1],
+ (unsigned int*)&mac[2],
+ (unsigned int*)&mac[3],
+ (unsigned int*)&mac[4],
+ (unsigned int*)&mac[5]);
+ def->mac[0] = mac[0];
+ def->mac[1] = mac[1];
+ def->mac[2] = mac[2];
+ def->mac[3] = mac[3];
+ def->mac[4] = mac[4];
+ def->mac[5] = mac[5];
+ } else {
+ virDomainNetRandomMAC(def);
+ }
+
+ switch (def->type) {
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ if (network == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("No <source> 'network' attribute specified with <interface type='network'/>"));
+ goto error;
+ }
+ def->dst.network.name = network;
+ network = NULL;
+
+ if (ifname != NULL) {
+ def->dst.network.ifname = ifname;
+ ifname = NULL;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+
+ if (script != NULL) {
+ def->dst.ethernet.script = script;
+ script = NULL;
+ }
+ if (ifname != NULL) {
+ def->dst.ethernet.ifname = ifname;
+ ifname = NULL;
+ }
+ if (address != NULL) {
+ def->dst.ethernet.ipaddr = address;
+ address = NULL;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ if (bridge == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("No <source> 'dev' attribute specified with <interface type='bridge'/>"));
+ goto error;
+ }
+ def->dst.bridge.brname = bridge;
+ bridge = NULL;
+
+ if (ifname != NULL) {
+ def->dst.bridge.ifname = ifname;
+ ifname = NULL;
+ }
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ if (port == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("No <source> 'port' attribute specified with socket interface"));
+ goto error;
+ }
+ if (virStrToLong_i(port, NULL, 10, &def->dst.socket.port) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Cannot parse <source> 'port' attribute with socket interface"));
+ goto error;
+ }
+
+ if (address == NULL) {
+ if (def->type == VIR_DOMAIN_NET_TYPE_CLIENT ||
+ def->type == VIR_DOMAIN_NET_TYPE_MCAST) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("No <source> 'address' attribute specified with socket interface"));
+ goto error;
+ }
+ } else {
+ def->dst.socket.address = address;
+ address = NULL;
+ }
+ }
+
+ /* NIC model (see -net nic,model=?). We only check that it looks
+ * reasonable, not that it is a supported NIC type. FWIW kvm
+ * supports these types as of April 2008:
+ * i82551 i82557b i82559er ne2k_pci pcnet rtl8139 e1000 virtio
+ */
+ if (model != NULL) {
+ int i;
+ for (i = 0 ; i < strlen(model) ; i++) {
+ int char_ok = c_isalnum(model[i]) || model[i] == '_';
+ if (!char_ok) {
+ virDomainReportError (conn, VIR_ERR_INVALID_ARG, "%s",
+ _("Model name contains invalid characters"));
+ goto error;
+ }
+ }
+ def->model = model;
+ model = NULL;
+ }
+
+cleanup:
+ VIR_FREE(macaddr);
+ VIR_FREE(network);
+ VIR_FREE(address);
+ VIR_FREE(port);
+ VIR_FREE(ifname);
+ VIR_FREE(script);
+ VIR_FREE(bridge);
+ VIR_FREE(model);
+ VIR_FREE(type);
+
+ return def;
+
+error:
+ virDomainNetDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+/* Parse the XML definition for a character device
+ * @param node XML nodeset to parse for net definition
+ *
+ * The XML we're dealing with looks like
+ *
+ * <serial type="pty">
+ * <source path="/dev/pts/3"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="dev">
+ * <source path="/dev/ttyS0"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="tcp">
+ * <source mode="connect" host="0.0.0.0" service="2445"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="tcp">
+ * <source mode="bind" host="0.0.0.0" service="2445"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="udp">
+ * <source mode="bind" host="0.0.0.0" service="2445"/>
+ * <source mode="connect" host="0.0.0.0" service="2445"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ * <serial type="unix">
+ * <source mode="bind" path="/tmp/foo"/>
+ * <target port="1"/>
+ * </serial>
+ *
+ */
+static virDomainChrDefPtr
+virDomainChrDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ xmlNodePtr cur;
+ char *type = NULL;
+ char *bindHost = NULL;
+ char *bindService = NULL;
+ char *connectHost = NULL;
+ char *connectService = NULL;
+ char *path = NULL;
+ char *mode = NULL;
+ char *protocol = NULL;
+ virDomainChrDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ def->type = VIR_DOMAIN_CHR_TYPE_PTY;
+ type = virXMLPropString(node, "type");
+ if (type != NULL) {
+ if (STREQ(type, "null"))
+ def->type = VIR_DOMAIN_CHR_TYPE_NULL;
+ else if (STREQ(type, "vc"))
+ def->type = VIR_DOMAIN_CHR_TYPE_VC;
+ else if (STREQ(type, "pty"))
+ def->type = VIR_DOMAIN_CHR_TYPE_PTY;
+ else if (STREQ(type, "dev"))
+ def->type = VIR_DOMAIN_CHR_TYPE_DEV;
+ else if (STREQ(type, "file"))
+ def->type = VIR_DOMAIN_CHR_TYPE_FILE;
+ else if (STREQ(type, "pipe"))
+ def->type = VIR_DOMAIN_CHR_TYPE_PIPE;
+ else if (STREQ(type, "stdio"))
+ def->type = VIR_DOMAIN_CHR_TYPE_STDIO;
+ else if (STREQ(type, "udp"))
+ def->type = VIR_DOMAIN_CHR_TYPE_UDP;
+ else if (STREQ(type, "tcp"))
+ def->type = VIR_DOMAIN_CHR_TYPE_TCP;
+ else if (STREQ(type, "unix"))
+ def->type = VIR_DOMAIN_CHR_TYPE_UNIX;
+ else
+ def->type = VIR_DOMAIN_CHR_TYPE_NULL;
+ }
+
+ cur = node->children;
+ while (cur != NULL) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual(cur->name, BAD_CAST "source")) {
+ if (mode == NULL)
+ mode = virXMLPropString(cur, "mode");
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ if (path == NULL)
+ path = virXMLPropString(cur, "path");
+
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ if (mode == NULL ||
+ STREQ((const char *)mode, "connect")) {
+
+ if (connectHost == NULL)
+ connectHost = virXMLPropString(cur, "host");
+ if (connectService == NULL)
+ connectService = virXMLPropString(cur, "service");
+ } else {
+ if (bindHost == NULL)
+ bindHost = virXMLPropString(cur, "host");
+ if (bindService == NULL)
+ bindService = virXMLPropString(cur, "service");
+ }
+
+ if (def->type == VIR_DOMAIN_CHR_TYPE_UDP) {
+ VIR_FREE(mode);
+ mode = NULL;
+ }
+ }
+ } else if (xmlStrEqual(cur->name, BAD_CAST "protocol")) {
+ if (protocol == NULL)
+ protocol = virXMLPropString(cur, "type");
+ }
+ }
+ cur = cur->next;
+ }
+
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_NULL:
+ /* Nada */
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_VC:
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ /* @path attribute is an output only property - pty is auto-allocted */
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ if (path == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source path attribute for char device"));
+ goto error;
+ }
+
+ def->data.file.path = path;
+ path = NULL;
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_STDIO:
+ /* Nada */
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ if (mode == NULL ||
+ STREQ(mode, "connect")) {
+ if (connectHost == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source host attribute for char device"));
+ goto error;
+ }
+ if (connectService == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source service attribute for char device"));
+ goto error;
+ }
+
+ def->data.tcp.host = connectHost;
+ connectHost = NULL;
+ def->data.tcp.service = connectService;
+ connectService = NULL;
+ def->data.tcp.listen = 0;
+ } else {
+ if (bindHost == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source host attribute for char device"));
+ goto error;
+ }
+ if (bindService == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source service attribute for char device"));
+ goto error;
+ }
+
+ def->data.tcp.host = bindHost;
+ bindHost = NULL;
+ def->data.tcp.service = bindService;
+ bindService = NULL;
+ def->data.tcp.listen = 1;
+ }
+ if (protocol != NULL &&
+ STREQ(protocol, "telnet"))
+ def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
+ else
+ def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ if (connectService == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source service attribute for char device"));
+ goto error;
+ }
+
+ def->data.udp.connectHost = connectHost;
+ connectHost = NULL;
+ def->data.udp.connectService = connectService;
+ connectService = NULL;
+
+ def->data.udp.bindHost = bindHost;
+ bindHost = NULL;
+ def->data.udp.bindService = bindService;
+ bindService = NULL;
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ if (path == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Missing source path attribute for char device"));
+ goto error;
+ }
+
+ if (mode != NULL &&
+ STRNEQ(mode, "connect"))
+ def->data.nix.listen = 1;
+ else
+ def->data.nix.listen = 0;
+
+ def->data.nix.path = path;
+ path = NULL;
+ break;
+ }
+
+cleanup:
+ VIR_FREE(mode);
+ VIR_FREE(protocol);
+ VIR_FREE(type);
+ VIR_FREE(bindHost);
+ VIR_FREE(bindService);
+ VIR_FREE(connectHost);
+ VIR_FREE(connectService);
+ VIR_FREE(path);
+
+ return def;
+
+error:
+ virDomainChrDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+/* Parse the XML definition for a network interface */
+static virDomainInputDefPtr
+virDomainInputDefParseXML(virConnectPtr conn,
+ const char *ostype,
+ xmlNodePtr node) {
+ virDomainInputDefPtr def;
+ char *type = NULL;
+ char *bus = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+ bus = virXMLPropString(node, "bus");
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing input device type"));
+ goto error;
+ }
+
+ if ((def->type = virDomainInputTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown input device type '%s'"), type);
+ goto error;
+ }
+
+ if (bus) {
+ if ((def->bus = virDomainInputBusTypeFromString(bus)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown input bus type '%s'"), bus);
+ goto error;
+ }
+
+ if (STREQ(ostype, "hvm")) {
+ if (def->bus == VIR_DOMAIN_INPUT_BUS_PS2 && /* Only allow mouse for ps2 */
+ def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("ps2 bus does not support %s input device"),
+ type);
+ goto error;
+ }
+ if (def->bus == VIR_DOMAIN_INPUT_BUS_XEN) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported input bus %s"),
+ bus);
+ goto error;
+ }
+ } else {
+ if (def->bus != VIR_DOMAIN_INPUT_BUS_XEN) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported input bus %s"),
+ bus);
+ }
+ if (def->type != VIR_DOMAIN_INPUT_TYPE_MOUSE) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("xen bus does not support %s input device"),
+ type);
+ goto error;
+ }
+ }
+ } else {
+ if (STREQ(ostype, "hvm")) {
+ if (def->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)
+ def->bus = VIR_DOMAIN_INPUT_BUS_PS2;
+ else
+ def->bus = VIR_DOMAIN_INPUT_BUS_USB;
+ } else {
+ def->bus = VIR_DOMAIN_INPUT_BUS_XEN;
+ }
+ }
+
+cleanup:
+ VIR_FREE(type);
+ VIR_FREE(bus);
+
+ return def;
+
+error:
+ virDomainInputDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+/* Parse the XML definition for a graphics device */
+static virDomainGraphicsDefPtr
+virDomainGraphicsDefParseXML(virConnectPtr conn,
+ xmlNodePtr node) {
+ virDomainGraphicsDefPtr def;
+ char *type = NULL;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing graphics device type"));
+ goto error;
+ }
+
+ if ((def->type = virDomainGraphicsTypeFromString(type)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown graphics device type '%s'"), type);
+ goto error;
+ }
+
+ if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
+ char *port = virXMLPropString(node, "port");
+ char *autoport;
+
+ if (port) {
+ if (virStrToLong_i(port, NULL, 10, &def->data.vnc.port) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse vnc port %s"), port);
+ VIR_FREE(port);
+ goto error;
+ }
+ VIR_FREE(port);
+ /* Legacy compat syntax, used -1 for auto-port */
+ if (def->data.vnc.port == -1) {
+ def->data.vnc.port = 0;
+ def->data.vnc.autoport = 1;
+ }
+ } else {
+ def->data.vnc.port = 0;
+ def->data.vnc.autoport = 1;
+ }
+
+ if ((autoport = virXMLPropString(node, "autoport")) != NULL) {
+ if (STREQ(autoport, "yes")) {
+ def->data.vnc.port = 0;
+ def->data.vnc.autoport = 1;
+ }
+ VIR_FREE(autoport);
+ }
+
+ def->data.vnc.listenAddr = virXMLPropString(node, "listen");
+ def->data.vnc.passwd = virXMLPropString(node, "passwd");
+ def->data.vnc.keymap = virXMLPropString(node, "keymap");
+ } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
+ def->data.sdl.xauth = virXMLPropString(node, "xauth");
+ def->data.sdl.display = virXMLPropString(node, "display");
+ }
+
+cleanup:
+ VIR_FREE(type);
+
+ return def;
+
+error:
+ virDomainGraphicsDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+static virDomainSoundDefPtr
+virDomainSoundDefParseXML(virConnectPtr conn,
+ const xmlNodePtr node) {
+
+ char *model;
+ virDomainSoundDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ model = virXMLPropString(node, "model");
+ if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown sound model '%s'"), model);
+ goto error;
+ }
+
+cleanup:
+ VIR_FREE(model);
+
+ return def;
+
+error:
+ virDomainSoundDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
+static int virDomainLifecycleParseXML(virConnectPtr conn,
+ xmlXPathContextPtr ctxt,
+ const char *xpath,
+ int *val,
+ int defaultVal)
+{
+ char *tmp = virXPathString(xpath, ctxt);
+ if (tmp == NULL) {
+ *val = defaultVal;
+ } else {
+ *val = virDomainLifecycleTypeFromString(tmp);
+ if (*val < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown lifecycle action %s"), tmp);
+ VIR_FREE(tmp);
+ return -1;
+ }
+ VIR_FREE(tmp);
+ }
+ return 0;
+}
+
+
+virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
+ const virDomainDefPtr def,
+ const char *xmlStr)
+{
+ xmlDocPtr xml;
+ xmlNodePtr node;
+ virDomainDeviceDefPtr dev = NULL;
+
+ if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "device.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR, NULL);
+ goto error;
+ }
+
+ node = xmlDocGetRootElement(xml);
+ if (node == NULL) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("missing root element"));
+ goto error;
+ }
+
+ if (VIR_ALLOC(dev) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+
+ if (xmlStrEqual(node->name, BAD_CAST "disk")) {
+ dev->type = VIR_DOMAIN_DEVICE_DISK;
+ if (!(dev->data.disk = virDomainDiskDefParseXML(conn, node)))
+ goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
+ dev->type = VIR_DOMAIN_DEVICE_NET;
+ if (!(dev->data.net = virDomainNetDefParseXML(conn, node)))
+ goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "input")) {
+ dev->type = VIR_DOMAIN_DEVICE_DISK;
+ if (!(dev->data.input = virDomainInputDefParseXML(conn, def->os.type, node)))
+ goto error;
+ } else if (xmlStrEqual(node->name, BAD_CAST "sound")) {
+ dev->type = VIR_DOMAIN_DEVICE_SOUND;
+ if (!(dev->data.sound = virDomainSoundDefParseXML(conn, node)))
+ goto error;
+ } else {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR,
+ "%s", _("unknown device type"));
+ goto error;
+ }
+
+ xmlFreeDoc(xml);
+
+ return dev;
+
+ error:
+ xmlFreeDoc(xml);
+ VIR_FREE(dev);
+ return NULL;
+}
+
+
+static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
+ virCapsPtr caps,
+ xmlDocPtr xml)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ xmlNodePtr *nodes = NULL, node = NULL;
+ char *tmp = NULL;
+ int i, n;
+ virDomainDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY,
+ "%s", _("failed to allocate space for xmlXPathContext"));
+ return NULL;
+ }
+ def->id = -1;
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY,
+ "%s", _("failed to allocate space for xmlXPathContext"));
+ goto error;
+ }
+
+
+ /* Find out what type of QEMU virtualization to use */
+ if (!(tmp = virXPathString("string(/domain/@type)", ctxt))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing domain type attribute"));
+ goto error;
+ }
+
+ if ((def->virtType = virDomainVirtTypeFromString(tmp)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("invalid domain type %s"), tmp);
+ goto error;
+ }
+ VIR_FREE(tmp);
+
+ /* Extract domain name */
+ if (!(def->name = virXPathString("string(/domain/name[1])", ctxt))) {
+ virDomainReportError(conn, VIR_ERR_NO_NAME, NULL);
+ goto error;
+ }
+
+ /* Extract domain uuid */
+ tmp = virXPathString("string(/domain/uuid[1])", ctxt);
+ if (!tmp) {
+ int err;
+ if ((err = virUUIDGenerate(def->uuid))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("Failed to generate UUID: %s"),
+ strerror(err));
+ goto error;
+ }
+ } else {
+ if (virUUIDParse(tmp, def->uuid) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed uuid element"));
+ goto error;
+ }
+ VIR_FREE(tmp);
+ }
+
+ /* Extract domain memory */
+ if (virXPathULong("string(/domain/memory[1])", ctxt, &def->maxmem) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing memory element"));
+ goto error;
+ }
+
+ if (virXPathULong("string(/domain/currentMemory[1])", ctxt, &def->memory) < 0)
+ def->memory = def->maxmem;
+
+ if (virXPathULong("string(/domain/vcpu[1])", ctxt, &def->vcpus) < 0)
+ def->vcpus = 1;
+
+ tmp = virXPathString("string(/domain/vcpu[1]/@cpuset)", ctxt);
+ if (tmp) {
+ char *set = tmp;
+ def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
+ if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ if (virDomainCpuSetParse(conn, (const char **)&set,
+ 0, def->cpumask,
+ def->cpumasklen) < 0)
+ goto error;
+ VIR_FREE(tmp);
+ }
+
+ if ((n = virXPathNodeSet("/domain/features/*", ctxt, &nodes)) > 0) {
+ for (i = 0 ; i < n ; i++) {
+ int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
+ if (val < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected feature %s"),
+ nodes[i]->name);
+ goto error;
+ }
+ def->features |= (1 << val);
+ }
+ }
+ VIR_FREE(nodes);
+
+ if (virDomainLifecycleParseXML(conn, ctxt, "string(/domain/on_reboot[1])",
+ &def->onReboot, VIR_DOMAIN_LIFECYCLE_RESTART) < 0)
+ goto error;
+
+ if (virDomainLifecycleParseXML(conn, ctxt, "string(/domain/on_poweroff[1])",
+ &def->onPoweroff, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
+ goto error;
+
+ if (virDomainLifecycleParseXML(conn, ctxt, "string(/domain/on_crash[1])",
+ &def->onCrash, VIR_DOMAIN_LIFECYCLE_DESTROY) < 0)
+ goto error;
+
+
+ tmp = virXPathString("string(/domain/clock/@offset)", ctxt);
+ if (tmp && STREQ(tmp, "localtime"))
+ def->localtime = 1;
+ VIR_FREE(tmp);
+
+ def->os.bootloader = virXPathString("string(/domain/bootloader)", ctxt);
+ def->os.bootloaderArgs = virXPathString("string(/domain/bootloader_args)", ctxt);
+
+ def->os.type = virXPathString("string(/domain/os/type[1])", ctxt);
+ if (!def->os.type) {
+ if (def->os.bootloader) {
+ def->os.type = strdup("xen");
+ if (!def->os.type) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ } else {
+ virDomainReportError(conn, VIR_ERR_OS_TYPE,
+ "%s", _("no OS type"));
+ goto error;
+ }
+ }
+ /*
+ * HACK: For xen driver we previously used bogus 'linux' as the
+ * os type for paravirt, whereas capabilities declare it to
+ * be 'xen'. So we accept the former and convert
+ */
+ if (STREQ(def->os.type, "linux") &&
+ def->virtType == VIR_DOMAIN_VIRT_XEN) {
+ VIR_FREE(def->os.type);
+ if (!(def->os.type = strdup("xen"))) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ }
+
+ if (!virCapabilitiesSupportsGuestOSType(caps, def->os.type)) {
+ virDomainReportError(conn, VIR_ERR_OS_TYPE,
+ "%s", def->os.type);
+ goto error;
+ }
+
+ def->os.arch = virXPathString("string(/domain/os/type[1]/@arch)", ctxt);
+ if (!def->os.arch) {
+ const char *defaultArch = virCapabilitiesDefaultGuestArch(caps, def->os.type);
+ if (defaultArch == NULL) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("no supported architecture for os type '%s'"),
+ def->os.type);
+ goto error;
+ }
+ if (!(def->os.arch = strdup(defaultArch))) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ }
+
+ def->os.machine = virXPathString("string(/domain/os/type[1]/@machine)", ctxt);
+ if (!def->os.machine) {
+ const char *defaultMachine = virCapabilitiesDefaultGuestMachine(caps,
+ def->os.type,
+ def->os.arch);
+ if (defaultMachine != NULL) {
+ if (!(def->os.machine = strdup(defaultMachine))) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ }
+ }
+
+ if (!def->os.bootloader) {
+ def->os.kernel = virXPathString("string(/domain/os/kernel[1])", ctxt);
+ def->os.initrd = virXPathString("string(/domain/os/initrd[1])", ctxt);
+ def->os.cmdline = virXPathString("string(/domain/os/cmdline[1])", ctxt);
+ def->os.root = virXPathString("string(/domain/os/root[1])", ctxt);
+ def->os.loader = virXPathString("string(/domain/os/loader[1])", ctxt);
+
+ /* analysis of the boot devices */
+ if ((n = virXPathNodeSet("/domain/os/boot", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract boot device"));
+ goto error;
+ }
+ for (i = 0 ; i < n && i < VIR_DOMAIN_BOOT_LAST ; i++) {
+ int val;
+ char *dev = virXMLPropString(nodes[i], "dev");
+ if (!dev) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing boot device"));
+ goto error;
+ }
+ if ((val = virDomainBootTypeFromString(dev)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown boot device '%s'"),
+ dev);
+ VIR_FREE(dev);
+ goto error;
+ }
+ VIR_FREE(dev);
+ def->os.bootDevs[def->os.nBootDevs++] = val;
+ }
+ if (def->os.nBootDevs == 0) {
+ def->os.nBootDevs = 1;
+ def->os.bootDevs[0] = VIR_DOMAIN_BOOT_DISK;
+ }
+ VIR_FREE(nodes);
+ }
+
+ def->emulator = virXPathString("string(/domain/devices/emulator[1])", ctxt);
+ if (!def->emulator) {
+ const char *type = virDomainVirtTypeToString(def->virtType);
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unknown virt type"));
+ goto error;
+ }
+ const char *emulator = virCapabilitiesDefaultGuestEmulator(caps,
+ def->os.type,
+ def->os.arch,
+ type);
+ if (!emulator) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unsupported guest type"));
+ goto error;
+ }
+ if (!(def->emulator = strdup(emulator))) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ }
+
+ /* analysis of the disk devices */
+ if ((n = virXPathNodeSet("/domain/devices/disk", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract disk devices"));
+ goto error;
+ }
+ for (i = 0 ; i < n ; i++) {
+ virDomainDiskDefPtr disk = virDomainDiskDefParseXML(conn,
+ nodes[i]);
+ if (!disk)
+ goto error;
+
+ /* Maintain list in sorted order according to target device name */
+ if (def->disks == NULL) {
+ disk->next = def->disks;
+ def->disks = disk;
+ } else {
+ virDomainDiskDefPtr ptr = def->disks;
+ while (ptr) {
+ if (!ptr->next || virDomainDiskCompare(disk, ptr->next) < 0) {
+ disk->next = ptr->next;
+ ptr->next = disk;
+ break;
+ }
+ ptr = ptr->next;
+ }
+ }
+ }
+ VIR_FREE(nodes);
+
+ /* analysis of the network devices */
+ if ((n = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract network devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainNetDefPtr net = virDomainNetDefParseXML(conn,
+ nodes[i]);
+ if (!net)
+ goto error;
+
+ net->next = def->nets;
+ def->nets = net;
+ }
+ VIR_FREE(nodes);
+
+
+ /* analysis of the character devices */
+ if ((n = virXPathNodeSet("/domain/devices/parallel", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract parallel devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
+ nodes[i]);
+ if (!chr)
+ goto error;
+
+ chr->dstPort = i;
+ chr->next = def->parallels;
+ def->parallels = chr;
+ }
+ VIR_FREE(nodes);
+
+ if ((n = virXPathNodeSet("/domain/devices/serial", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract serial devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
+ nodes[i]);
+ if (!chr)
+ goto error;
+
+ chr->dstPort = i;
+ chr->next = def->serials;
+ def->serials = chr;
+ }
+ VIR_FREE(nodes);
+
+ /*
+ * If no serial devices were listed, then look for console
+ * devices which is the legacy syntax for the same thing
+ */
+ if (def->serials == NULL) {
+ if ((node = virXPathNode("/domain/devices/console[1]", ctxt)) != NULL) {
+ virDomainChrDefPtr chr = virDomainChrDefParseXML(conn,
+ node);
+ if (!chr)
+ goto error;
+
+ chr->dstPort = 0;
+ /*
+ * For HVM console actually created a serial device
+ * while for non-HVM it was a parvirt console
+ */
+ if (STREQ(def->os.type, "hvm")) {
+ chr->next = def->serials;
+ def->serials = chr;
+ } else {
+ def->console = chr;
+ }
+ }
+ }
+
+
+ /* analysis of the input devices */
+ if ((n = virXPathNodeSet("/domain/devices/input", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract input devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ virDomainInputDefPtr input = virDomainInputDefParseXML(conn,
+ def->os.type,
+ nodes[i]);
+ if (!input)
+ goto error;
+
+
+ /* With QEMU / KVM / Xen graphics, mouse + PS/2 is implicit
+ * with graphics, so don't store it.
+ * XXX will this be true for other virt types ? */
+ if ((STREQ(def->os.type, "hvm") &&
+ input->bus == VIR_DOMAIN_INPUT_BUS_PS2 &&
+ input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE) ||
+ (STRNEQ(def->os.type, "hvm") &&
+ input->bus == VIR_DOMAIN_INPUT_BUS_XEN &&
+ input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE)) {
+ virDomainInputDefFree(input);
+ continue;
+ }
+
+ input->next = def->inputs;
+ def->inputs = input;
+ }
+ VIR_FREE(nodes);
+
+ /* analysis of the input devices */
+ if ((n = virXPathNodeSet("/domain/devices/graphics", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract graphics devices"));
+ goto error;
+ }
+ if (n > 0) {
+ virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(conn,
+ nodes[0]);
+ if (!graphics)
+ goto error;
+
+ def->graphics = graphics;
+ }
+ VIR_FREE(nodes);
+
+ /* If graphics are enabled, there's an implicit PS2 mouse */
+ if (def->graphics != NULL) {
+ virDomainInputDefPtr input;
+
+ if (VIR_ALLOC(input) < 0) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ goto error;
+ }
+ if (STREQ(def->os.type, "hvm")) {
+ input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
+ input->bus = VIR_DOMAIN_INPUT_BUS_PS2;
+ } else {
+ input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
+ input->bus = VIR_DOMAIN_INPUT_BUS_XEN;
+ }
+ input->next = def->inputs;
+ def->inputs = input;
+ }
+
+
+ /* analysis of the sound devices */
+ if ((n = virXPathNodeSet("/domain/devices/sound", ctxt, &nodes)) < 0) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("cannot extract sound devices"));
+ goto error;
+ }
+ for (i = n - 1 ; i >= 0 ; i--) {
+ int collision = 0;
+ virDomainSoundDefPtr check;
+ virDomainSoundDefPtr sound = virDomainSoundDefParseXML(conn,
+ nodes[i]);
+ if (!sound)
+ goto error;
+
+ /* Verify there's no duplicated sound card */
+ check = def->sounds;
+ while (check) {
+ if (check->model == sound->model)
+ collision = 1;
+ check = check->next;
+ }
+ if (collision) {
+ virDomainSoundDefFree(sound);
+ continue;
+ }
+
+ sound->next = def->sounds;
+ def->sounds = sound;
+ }
+ VIR_FREE(nodes);
+
+ xmlXPathFreeContext(ctxt);
+
+ return def;
+
+ error:
+ VIR_FREE(tmp);
+ VIR_FREE(nodes);
+ xmlXPathFreeContext(ctxt);
+ virDomainDefFree(def);
+ return NULL;
+}
+
+
+virDomainDefPtr virDomainDefParse(virConnectPtr conn,
+ virCapsPtr caps,
+ const char *xmlStr,
+ const char *displayName)
+{
+ xmlDocPtr xml;
+ virDomainDefPtr def;
+
+ if (!(xml = xmlReadDoc(BAD_CAST xmlStr,
+ displayName ? displayName : "domain.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ virDomainReportError(conn, VIR_ERR_XML_ERROR, NULL);
+ return NULL;
+ }
+
+ def = virDomainDefParseXML(conn, caps, xml);
+
+ xmlFreeDoc(xml);
+
+ return def;
+}
+
+/************************************************************************
+ * *
+ * Parser and converter for the CPUset strings used in libvirt *
+ * *
+ ************************************************************************/
+/**
+ * virDomainCpuNumberParse
+ * @str: pointer to the char pointer used
+ * @maxcpu: maximum CPU number allowed
+ *
+ * Parse a CPU number
+ *
+ * Returns the CPU number or -1 in case of error. @str will be
+ * updated to skip the number.
+ */
+static int
+virDomainCpuNumberParse(const char **str, int maxcpu)
+{
+ int ret = 0;
+ const char *cur = *str;
+
+ if (!c_isdigit(*cur))
+ return (-1);
+
+ while (c_isdigit(*cur)) {
+ ret = ret * 10 + (*cur - '0');
+ if (ret >= maxcpu)
+ return (-1);
+ cur++;
+ }
+ *str = cur;
+ return (ret);
+}
+
+/**
+ * virDomainCpuSetFormat:
+ * @conn: connection
+ * @cpuset: pointer to a char array for the CPU set
+ * @maxcpu: number of elements available in @cpuset
+ *
+ * Serialize the cpuset to a string
+ *
+ * Returns the new string NULL in case of error. The string need to be
+ * freed by the caller.
+ */
+char *
+virDomainCpuSetFormat(virConnectPtr conn, char *cpuset, int maxcpu)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int start, cur;
+ int first = 1;
+
+ if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu > 100000))
+ return (NULL);
+
+ cur = 0;
+ start = -1;
+ while (cur < maxcpu) {
+ if (cpuset[cur]) {
+ if (start == -1)
+ start = cur;
+ } else if (start != -1) {
+ if (!first)
+ virBufferAddLit(&buf, ",");
+ else
+ first = 0;
+ if (cur == start + 1)
+ virBufferVSprintf(&buf, "%d", start);
+ else
+ virBufferVSprintf(&buf, "%d-%d", start, cur - 1);
+ start = -1;
+ }
+ cur++;
+ }
+ if (start != -1) {
+ if (!first)
+ virBufferAddLit(&buf, ",");
+ if (maxcpu == start + 1)
+ virBufferVSprintf(&buf, "%d", start);
+ else
+ virBufferVSprintf(&buf, "%d-%d", start, maxcpu - 1);
+ }
+
+ if (virBufferError(&buf)) {
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ return virBufferContentAndReset(&buf);
+}
+
+/**
+ * virDomainCpuSetParse:
+ * @conn: connection
+ * @str: pointer to a CPU set string pointer
+ * @sep: potential character used to mark the end of string if not 0
+ * @cpuset: pointer to a char array for the CPU set
+ * @maxcpu: number of elements available in @cpuset
+ *
+ * Parse the cpu set, it will set the value for enabled CPUs in the @cpuset
+ * to 1, and 0 otherwise. The syntax allows coma separated entries each
+ * can be either a CPU number, ^N to unset that CPU or N-M for ranges.
+ *
+ * Returns the number of CPU found in that set, or -1 in case of error.
+ * @cpuset is modified accordingly to the value parsed.
+ * @str is updated to the end of the part parsed
+ */
+int
+virDomainCpuSetParse(virConnectPtr conn, const char **str, char sep,
+ char *cpuset, int maxcpu)
+{
+ const char *cur;
+ int ret = 0;
+ int i, start, last;
+ int neg = 0;
+
+ if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) ||
+ (maxcpu > 100000))
+ return (-1);
+
+ cur = *str;
+ virSkipSpaces(&cur);
+ if (*cur == 0)
+ goto parse_error;
+
+ /* initialize cpumap to all 0s */
+ for (i = 0; i < maxcpu; i++)
+ cpuset[i] = 0;
+ ret = 0;
+
+ while ((*cur != 0) && (*cur != sep)) {
+ /*
+ * 3 constructs are allowed:
+ * - N : a single CPU number
+ * - N-M : a range of CPU numbers with N < M
+ * - ^N : remove a single CPU number from the current set
+ */
+ if (*cur == '^') {
+ cur++;
+ neg = 1;
+ }
+
+ if (!c_isdigit(*cur))
+ goto parse_error;
+ start = virDomainCpuNumberParse(&cur, maxcpu);
+ if (start < 0)
+ goto parse_error;
+ virSkipSpaces(&cur);
+ if ((*cur == ',') || (*cur == 0) || (*cur == sep)) {
+ if (neg) {
+ if (cpuset[start] == 1) {
+ cpuset[start] = 0;
+ ret--;
+ }
+ } else {
+ if (cpuset[start] == 0) {
+ cpuset[start] = 1;
+ ret++;
+ }
+ }
+ } else if (*cur == '-') {
+ if (neg)
+ goto parse_error;
+ cur++;
+ virSkipSpaces(&cur);
+ last = virDomainCpuNumberParse(&cur, maxcpu);
+ if (last < start)
+ goto parse_error;
+ for (i = start; i <= last; i++) {
+ if (cpuset[i] == 0) {
+ cpuset[i] = 1;
+ ret++;
+ }
+ }
+ virSkipSpaces(&cur);
+ }
+ if (*cur == ',') {
+ cur++;
+ virSkipSpaces(&cur);
+ neg = 0;
+ } else if ((*cur == 0) || (*cur == sep)) {
+ break;
+ } else
+ goto parse_error;
+ }
+ *str = cur;
+ return (ret);
+
+ parse_error:
+ virDomainReportError(conn, VIR_ERR_XEN_CALL,
+ "%s", _("topology cpuset syntax error"));
+ return (-1);
+}
+
+
+static int
+virDomainLifecycleDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ int type,
+ const char *name)
+{
+ const char *typeStr = virDomainLifecycleTypeToString(type);
+ if (!typeStr) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected lifecycle type %d"), type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <%s>%s</%s>\n", name, typeStr, name);
+
+ return 0;
+}
+
+
+static int
+virDomainDiskDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainDiskDefPtr def)
+{
+ const char *type = virDomainDiskTypeToString(def->type);
+ const char *device = virDomainDiskDeviceTypeToString(def->device);
+ const char *bus = virDomainDiskBusTypeToString(def->bus);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected disk type %d"), def->type);
+ return -1;
+ }
+ if (!device) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected disk device %d"), def->device);
+ return -1;
+ }
+ if (!bus) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected disk bus %d"), def->bus);
+ return -1;
+ }
+
+ virBufferVSprintf(buf,
+ " <disk type='%s' device='%s'>\n",
+ type, device);
+
+ if (def->driverName) {
+ if (def->driverType)
+ virBufferVSprintf(buf,
+ " <driver name='%s' type='%s'/>\n",
+ def->driverName, def->driverType);
+ else
+ virBufferVSprintf(buf,
+ " <driver name='%s'/>\n",
+ def->driverName);
+ }
+
+ if (def->src) {
+ if (def->type == VIR_DOMAIN_DISK_TYPE_FILE)
+ virBufferVSprintf(buf, " <source file='%s'/>\n",
+ def->src);
+ else
+ virBufferVSprintf(buf, " <source dev='%s'/>\n",
+ def->src);
+ }
+
+ virBufferVSprintf(buf, " <target dev='%s' bus='%s'/>\n",
+ def->dst, bus);
+
+ if (def->readonly)
+ virBufferAddLit(buf, " <readonly/>\n");
+ if (def->shared)
+ virBufferAddLit(buf, " <shareable/>\n");
+
+ virBufferAddLit(buf, " </disk>\n");
+
+ return 0;
+}
+
+static int
+virDomainNetDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainNetDefPtr def)
+{
+ const char *type = virDomainNetTypeToString(def->type);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected net type %d"), def->type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <interface type='%s'>\n", type);
+
+ virBufferVSprintf(buf,
+ " <mac address='%02x:%02x:%02x:%02x:%02x:%02x'/>\n",
+ def->mac[0], def->mac[1], def->mac[2],
+ def->mac[3], def->mac[4], def->mac[5]);
+
+ switch (def->type) {
+ case VIR_DOMAIN_NET_TYPE_NETWORK:
+ virBufferVSprintf(buf, " <source network='%s'/>\n",
+ def->dst.network.name);
+
+ if (def->dst.network.ifname)
+ virBufferVSprintf(buf, " <target dev='%s'/>\n",
+ def->dst.network.ifname);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_ETHERNET:
+ if (def->dst.ethernet.ifname)
+ virBufferVSprintf(buf, " <target dev='%s'/>\n",
+ def->dst.ethernet.ifname);
+ if (def->dst.ethernet.ipaddr)
+ virBufferVSprintf(buf, " <ip address='%s'/>\n",
+ def->dst.ethernet.ipaddr);
+ if (def->dst.ethernet.script)
+ virBufferVSprintf(buf, " <script path='%s'/>\n",
+ def->dst.ethernet.script);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_BRIDGE:
+ virBufferVSprintf(buf, " <source bridge='%s'/>\n",
+ def->dst.bridge.brname);
+ if (def->dst.bridge.ifname)
+ virBufferVSprintf(buf, " <target dev='%s'/>\n",
+ def->dst.bridge.ifname);
+ break;
+
+ case VIR_DOMAIN_NET_TYPE_SERVER:
+ case VIR_DOMAIN_NET_TYPE_CLIENT:
+ case VIR_DOMAIN_NET_TYPE_MCAST:
+ if (def->dst.socket.address)
+ virBufferVSprintf(buf, " <source address='%s' port='%d'/>\n",
+ def->dst.socket.address, def->dst.socket.port);
+ else
+ virBufferVSprintf(buf, " <source port='%d'/>\n",
+ def->dst.socket.port);
+ }
+
+ if (def->model)
+ virBufferVSprintf(buf, " <model type='%s'/>\n",
+ def->model);
+
+ virBufferAddLit(buf, " </interface>\n");
+
+ return 0;
+}
+
+
+static int
+virDomainChrDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainChrDefPtr def,
+ const char *name)
+{
+ const char *type = virDomainChrTypeToString(def->type);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected char type %d"), def->type);
+ return -1;
+ }
+
+ /* Compat with legacy <console tty='/dev/pts/5'/> syntax */
+ if (STREQ(name, "console") &&
+ def->type == VIR_DOMAIN_CHR_TYPE_PTY &&
+ def->data.file.path) {
+ virBufferVSprintf(buf, " <%s type='%s' tty='%s'>\n",
+ name, type,
+ def->data.file.path);
+ } else {
+ virBufferVSprintf(buf, " <%s type='%s'>\n",
+ name, type);
+ }
+
+ switch (def->type) {
+ case VIR_DOMAIN_CHR_TYPE_NULL:
+ case VIR_DOMAIN_CHR_TYPE_VC:
+ case VIR_DOMAIN_CHR_TYPE_STDIO:
+ /* nada */
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_PTY:
+ case VIR_DOMAIN_CHR_TYPE_DEV:
+ case VIR_DOMAIN_CHR_TYPE_FILE:
+ case VIR_DOMAIN_CHR_TYPE_PIPE:
+ if (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
+ def->data.file.path) {
+ virBufferVSprintf(buf, " <source path='%s'/>\n",
+ def->data.file.path);
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UDP:
+ if (def->data.udp.bindService &&
+ def->data.udp.bindHost) {
+ virBufferVSprintf(buf, " <source mode='bind' host='%s' service='%s'/>\n",
+ def->data.udp.bindHost,
+ def->data.udp.bindService);
+ } else if (def->data.udp.bindHost) {
+ virBufferVSprintf(buf, " <source mode='bind' host='%s'/>\n",
+ def->data.udp.bindHost);
+ } else if (def->data.udp.bindService) {
+ virBufferVSprintf(buf, " <source mode='bind' service='%s'/>\n",
+ def->data.udp.bindService);
+ }
+
+ if (def->data.udp.connectService &&
+ def->data.udp.connectHost) {
+ virBufferVSprintf(buf, " <source mode='connect' host='%s' service='%s'/>\n",
+ def->data.udp.connectHost,
+ def->data.udp.connectService);
+ } else if (def->data.udp.connectHost) {
+ virBufferVSprintf(buf, " <source mode='connect' host='%s'/>\n",
+ def->data.udp.connectHost);
+ } else if (def->data.udp.connectService) {
+ virBufferVSprintf(buf, " <source mode='connect' service='%s'/>\n",
+ def->data.udp.connectService);
+ }
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_TCP:
+ virBufferVSprintf(buf, " <source mode='%s' host='%s' service='%s'/>\n",
+ def->data.tcp.listen ? "bind" : "connect",
+ def->data.tcp.host,
+ def->data.tcp.service);
+ virBufferVSprintf(buf, " <protocol type='%s'/>\n",
+ def->data.tcp.protocol ==
+ VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET
+ ? "telnet" : "raw");
+ break;
+
+ case VIR_DOMAIN_CHR_TYPE_UNIX:
+ virBufferVSprintf(buf, " <source mode='%s' path='%s'/>\n",
+ def->data.nix.listen ? "bind" : "connect",
+ def->data.nix.path);
+ break;
+ }
+
+ virBufferVSprintf(buf, " <target port='%d'/>\n",
+ def->dstPort);
+
+ virBufferVSprintf(buf, " </%s>\n",
+ name);
+
+ return 0;
+}
+
+static int
+virDomainSoundDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainSoundDefPtr def)
+{
+ const char *model = virDomainSoundModelTypeToString(def->model);
+
+ if (!model) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected sound model %d"), def->model);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <sound model='%s'/>\n",
+ model);
+
+ return 0;
+}
+
+static int
+virDomainInputDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainInputDefPtr def)
+{
+ const char *type = virDomainInputTypeToString(def->type);
+ const char *bus = virDomainInputBusTypeToString(def->bus);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected input type %d"), def->type);
+ return -1;
+ }
+ if (!bus) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected input bus type %d"), def->bus);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <input type='%s' bus='%s'/>\n",
+ type, bus);
+
+ return 0;
+}
+
+
+static int
+virDomainGraphicsDefFormat(virConnectPtr conn,
+ virBufferPtr buf,
+ virDomainGraphicsDefPtr def,
+ int secure)
+{
+ const char *type = virDomainGraphicsTypeToString(def->type);
+
+ if (!type) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected net type %d"), def->type);
+ return -1;
+ }
+
+ virBufferVSprintf(buf, " <graphics type='%s'", type);
+
+ switch (def->type) {
+ case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
+ if (def->data.vnc.autoport)
+ virBufferAddLit(buf, " port='-1'");
+ else if (def->data.vnc.port)
+ virBufferVSprintf(buf, " port='%d'",
+ def->data.vnc.port);
+
+ virBufferVSprintf(buf, " autoport='%s'",
+ def->data.vnc.autoport ? "yes" : "no");
+
+ if (def->data.vnc.listenAddr)
+ virBufferVSprintf(buf, " listen='%s'",
+ def->data.vnc.listenAddr);
+
+ if (def->data.vnc.keymap)
+ virBufferVSprintf(buf, " keymap='%s'",
+ def->data.vnc.keymap);
+
+ if (def->data.vnc.passwd && secure)
+ virBufferVSprintf(buf, " passwd='%s'",
+ def->data.vnc.passwd);
+
+ break;
+
+ case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
+ if (def->data.sdl.display)
+ virBufferVSprintf(buf, " display='%s'",
+ def->data.sdl.display);
+
+ if (def->data.sdl.xauth)
+ virBufferVSprintf(buf, " xauth='%s'",
+ def->data.sdl.xauth);
+ break;
+ }
+
+ virBufferAddLit(buf, "/>\n");
+
+ return 0;
+}
+
+char *virDomainDefFormat(virConnectPtr conn,
+ virDomainDefPtr def,
+ int secure)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ unsigned char *uuid;
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virDomainDiskDefPtr disk;
+ virDomainNetDefPtr net;
+ virDomainSoundDefPtr sound;
+ virDomainInputDefPtr input;
+ virDomainChrDefPtr chr;
+ const char *type = NULL, *tmp;
+ int n, allones = 1;
+
+ if (!(type = virDomainVirtTypeToString(def->virtType))) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected domain type %d"), def->virtType);
+ goto cleanup;
+ }
+
+ if (def->id >= 0)
+ virBufferVSprintf(&buf, "<domain type='%s' id='%d'>\n", type, def->id);
+ else
+ virBufferVSprintf(&buf, "<domain type='%s'>\n", type);
+
+ virBufferVSprintf(&buf, " <name>%s</name>\n", def->name);
+
+ uuid = def->uuid;
+ virUUIDFormat(uuid, uuidstr);
+ virBufferVSprintf(&buf, " <uuid>%s</uuid>\n", uuidstr);
+
+ virBufferVSprintf(&buf, " <memory>%lu</memory>\n", def->maxmem);
+ virBufferVSprintf(&buf, " <currentMemory>%lu</currentMemory>\n",
+ def->memory);
+
+ for (n = 0 ; n < def->cpumasklen ; n++)
+ if (def->cpumask[n] != 1)
+ allones = 0;
+
+ if (allones) {
+ virBufferVSprintf(&buf, " <vcpu>%lu</vcpu>\n", def->vcpus);
+ } else {
+ char *cpumask = NULL;
+ if ((cpumask =
+ virDomainCpuSetFormat(conn, def->cpumask, def->cpumasklen)) == NULL)
+ goto cleanup;
+ virBufferVSprintf(&buf, " <vcpu cpuset='%s'>%lu</vcpu>\n",
+ cpumask, def->vcpus);
+ VIR_FREE(cpumask);
+ }
+
+ if (def->os.bootloader) {
+ virBufferVSprintf(&buf, " <bootloader>%s</bootloader>\n",
+ def->os.bootloader);
+ if (def->os.bootloaderArgs)
+ virBufferVSprintf(&buf, " <bootloader_args>%s</bootloader_args>\n",
+ def->os.bootloaderArgs);
+ }
+ virBufferAddLit(&buf, " <os>\n");
+
+ virBufferAddLit(&buf, " <type");
+ if (def->os.arch)
+ virBufferVSprintf(&buf, " arch='%s'", def->os.arch);
+ if (def->os.machine)
+ virBufferVSprintf(&buf, " machine='%s'", def->os.machine);
+ /*
+ * HACK: For xen driver we previously used bogus 'linux' as the
+ * os type for paravirt, whereas capabilities declare it to
+ * be 'xen'. So we convert to the former for backcompat
+ */
+ if (def->virtType == VIR_DOMAIN_VIRT_XEN &&
+ STREQ(def->os.type, "xen"))
+ virBufferVSprintf(&buf, ">%s</type>\n", "linux");
+ else
+ virBufferVSprintf(&buf, ">%s</type>\n", def->os.type);
+
+ if (def->os.loader)
+ virBufferVSprintf(&buf, " <loader>%s</loader>\n",
+ def->os.loader);
+ if (def->os.kernel)
+ virBufferVSprintf(&buf, " <kernel>%s</kernel>\n",
+ def->os.kernel);
+ if (def->os.initrd)
+ virBufferVSprintf(&buf, " <initrd>%s</initrd>\n",
+ def->os.initrd);
+ if (def->os.cmdline)
+ virBufferVSprintf(&buf, " <cmdline>%s</cmdline>\n",
+ def->os.cmdline);
+ if (def->os.root)
+ virBufferVSprintf(&buf, " <root>%s</root>\n",
+ def->os.root);
+
+ if (!def->os.bootloader) {
+ for (n = 0 ; n < def->os.nBootDevs ; n++) {
+ const char *boottype =
+ virDomainBootTypeToString(def->os.bootDevs[n]);
+ if (!boottype) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected boot device type %d"),
+ def->os.bootDevs[n]);
+ goto cleanup;
+ }
+ virBufferVSprintf(&buf, " <boot dev='%s'/>\n", boottype);
+ }
+ }
+
+ virBufferAddLit(&buf, " </os>\n");
+
+ if (def->features) {
+ int i;
+ virBufferAddLit(&buf, " <features>\n");
+ for (i = 0 ; i < VIR_DOMAIN_FEATURE_LAST ; i++) {
+ if (def->features & (1 << i)) {
+ const char *name = virDomainFeatureTypeToString(i);
+ if (!name) {
+ virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected feature %d"), i);
+ goto cleanup;
+ }
+ virBufferVSprintf(&buf, " <%s/>\n", name);
+ }
+ }
+ virBufferAddLit(&buf, " </features>\n");
+ }
+
+ virBufferVSprintf(&buf, " <clock offset='%s'/>\n",
+ def->localtime ? "localtime" : "utc");
+
+ if (virDomainLifecycleDefFormat(conn, &buf, def->onPoweroff,
+ "on_poweroff") < 0)
+ goto cleanup;
+ if (virDomainLifecycleDefFormat(conn, &buf, def->onReboot,
+ "on_reboot") < 0)
+ goto cleanup;
+ if (virDomainLifecycleDefFormat(conn, &buf, def->onCrash,
+ "on_crash") < 0)
+ goto cleanup;
+
+ virBufferAddLit(&buf, " <devices>\n");
+
+ if (def->emulator)
+ virBufferVSprintf(&buf, " <emulator>%s</emulator>\n",
+ def->emulator);
+
+ disk = def->disks;
+ while (disk) {
+ if (virDomainDiskDefFormat(conn, &buf, disk) < 0)
+ goto cleanup;
+ disk = disk->next;
+ }
+
+ net = def->nets;
+ while (net) {
+ if (virDomainNetDefFormat(conn, &buf, net) < 0)
+ goto cleanup;
+ net = net->next;
+ }
+
+
+ chr = def->serials;
+ while (chr) {
+ if (virDomainChrDefFormat(conn, &buf, chr, "serial") < 0)
+ goto cleanup;
+ chr = chr->next;
+ }
+
+ chr = def->parallels;
+ while (chr) {
+ if (virDomainChrDefFormat(conn, &buf, chr, "parallel") < 0)
+ goto cleanup;
+ chr = chr->next;
+ }
+
+ /* If there's a PV console that's preferred.. */
+ if (def->console) {
+ if (virDomainChrDefFormat(conn, &buf, def->console, "console") < 0)
+ goto cleanup;
+ } else if (def->serials != NULL) {
+ /* ..else for legacy compat duplicate the serial device as a console */
+ if (virDomainChrDefFormat(conn, &buf, def->serials, "console") < 0)
+ goto cleanup;
+ }
+
+ input = def->inputs;
+ while (input) {
+ if (input->bus == VIR_DOMAIN_INPUT_BUS_USB &&
+ virDomainInputDefFormat(conn, &buf, input) < 0)
+ goto cleanup;
+ input = input->next;
+ }
+
+ if (def->graphics) {
+ /* If graphics is enabled, add the implicit mouse */
+ virDomainInputDef autoInput = {
+ VIR_DOMAIN_INPUT_TYPE_MOUSE,
+ STREQ(def->os.type, "hvm") ?
+ VIR_DOMAIN_INPUT_BUS_PS2 : VIR_DOMAIN_INPUT_BUS_XEN,
+ NULL };
+
+ if (virDomainInputDefFormat(conn, &buf, &autoInput) < 0)
+ goto cleanup;
+
+ if (virDomainGraphicsDefFormat(conn, &buf, def->graphics, secure) < 0)
+ goto cleanup;
+ }
+
+ sound = def->sounds;
+ while(sound) {
+ if (virDomainSoundDefFormat(conn, &buf, sound) < 0)
+ goto cleanup;
+ sound = sound->next;
+ }
+
+ virBufferAddLit(&buf, " </devices>\n");
+ virBufferAddLit(&buf, "</domain>\n");
+
+ if (virBufferError(&buf))
+ goto no_memory;
+
+ return virBufferContentAndReset(&buf);
+
+ no_memory:
+ virDomainReportError(conn, VIR_ERR_NO_MEMORY, NULL);
+ cleanup:
+ tmp = virBufferContentAndReset(&buf);
+ VIR_FREE(tmp);
+ return NULL;
+}
+
diff -r f47fdc49c62f src/domain_conf.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/domain_conf.h Sun Jun 22 18:31:20 2008 -0400
@@ -0,0 +1,461 @@
+/*
+ * domain_conf.h: domain XML processing
+ *
+ * Copyright (C) 2006-2008 Red Hat, Inc.
+ * Copyright (C) 2006-2008 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(a)redhat.com>
+ */
+
+#ifndef __DOMAIN_CONF_H
+#define __DOMAIN_CONF_H
+
+#include <config.h>
+
+#include "internal.h"
+#include "capabilities.h"
+#include "util.h"
+
+/* Different types of hypervisor */
+/* NB: Keep in sync with virDomainVirtTypeToString impl */
+enum virDomainVirtType {
+ VIR_DOMAIN_VIRT_QEMU,
+ VIR_DOMAIN_VIRT_KQEMU,
+ VIR_DOMAIN_VIRT_KVM,
+ VIR_DOMAIN_VIRT_XEN,
+ VIR_DOMAIN_VIRT_LXC,
+ VIR_DOMAIN_VIRT_UML,
+ VIR_DOMAIN_VIRT_OPENVZ,
+ VIR_DOMAIN_VIRT_VSERVER,
+ VIR_DOMAIN_VIRT_LDOM,
+ VIR_DOMAIN_VIRT_TEST,
+ VIR_DOMAIN_VIRT_VMWARE,
+ VIR_DOMAIN_VIRT_HYPERV,
+
+ VIR_DOMAIN_VIRT_LAST,
+};
+
+/* Two types of disk backends */
+enum virDomainDiskType {
+ VIR_DOMAIN_DISK_TYPE_BLOCK,
+ VIR_DOMAIN_DISK_TYPE_FILE,
+
+ VIR_DOMAIN_DISK_TYPE_LAST
+};
+
+/* Three types of disk frontend */
+enum virDomainDiskDevice {
+ VIR_DOMAIN_DISK_DEVICE_DISK,
+ VIR_DOMAIN_DISK_DEVICE_CDROM,
+ VIR_DOMAIN_DISK_DEVICE_FLOPPY,
+
+ VIR_DOMAIN_DISK_DEVICE_LAST
+};
+
+enum virDomainDiskBus {
+ VIR_DOMAIN_DISK_BUS_IDE,
+ VIR_DOMAIN_DISK_BUS_FDC,
+ VIR_DOMAIN_DISK_BUS_SCSI,
+ VIR_DOMAIN_DISK_BUS_VIRTIO,
+ VIR_DOMAIN_DISK_BUS_XEN,
+
+ VIR_DOMAIN_DISK_BUS_LAST
+};
+
+/* Stores the virtual disk configuration */
+typedef struct _virDomainDiskDef virDomainDiskDef;
+typedef virDomainDiskDef *virDomainDiskDefPtr;
+struct _virDomainDiskDef {
+ int type;
+ int device;
+ int bus;
+ char *src;
+ char *dst;
+ char *driverName;
+ char *driverType;
+ unsigned int readonly : 1;
+ unsigned int shared : 1;
+
+ virDomainDiskDefPtr next;
+};
+
+
+/* 5 different types of networking config */
+enum virDomainNetType {
+ VIR_DOMAIN_NET_TYPE_USER,
+ VIR_DOMAIN_NET_TYPE_ETHERNET,
+ VIR_DOMAIN_NET_TYPE_SERVER,
+ VIR_DOMAIN_NET_TYPE_CLIENT,
+ VIR_DOMAIN_NET_TYPE_MCAST,
+ VIR_DOMAIN_NET_TYPE_NETWORK,
+ VIR_DOMAIN_NET_TYPE_BRIDGE,
+
+ VIR_DOMAIN_NET_TYPE_LAST,
+};
+
+
+#define VIR_DOMAIN_NET_MAC_SIZE 6
+
+/* Stores the virtual network interface configuration */
+typedef struct _virDomainNetDef virDomainNetDef;
+typedef virDomainNetDef *virDomainNetDefPtr;
+struct _virDomainNetDef {
+ int type;
+ unsigned char mac[VIR_DOMAIN_NET_MAC_SIZE];
+ char *model;
+ union {
+ struct {
+ char *ifname;
+ char *script;
+ char *ipaddr;
+ } ethernet;
+ struct {
+ char *address;
+ int port;
+ } socket; /* any of NET_CLIENT or NET_SERVER or NET_MCAST */
+ struct {
+ char *name;
+ char *ifname;
+ } network;
+ struct {
+ char *brname;
+ char *ifname;
+ } bridge;
+ } dst;
+
+ virDomainNetDefPtr next;
+};
+
+enum virDomainChrSrcType {
+ VIR_DOMAIN_CHR_TYPE_NULL,
+ VIR_DOMAIN_CHR_TYPE_VC,
+ VIR_DOMAIN_CHR_TYPE_PTY,
+ VIR_DOMAIN_CHR_TYPE_DEV,
+ VIR_DOMAIN_CHR_TYPE_FILE,
+ VIR_DOMAIN_CHR_TYPE_PIPE,
+ VIR_DOMAIN_CHR_TYPE_STDIO,
+ VIR_DOMAIN_CHR_TYPE_UDP,
+ VIR_DOMAIN_CHR_TYPE_TCP,
+ VIR_DOMAIN_CHR_TYPE_UNIX,
+
+ VIR_DOMAIN_CHR_TYPE_LAST,
+};
+
+enum virDomainChrTcpProtocol {
+ VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW,
+ VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET,
+
+ VIR_DOMAIN_CHR_TCP_PROTOCOL_LAST,
+};
+
+typedef struct _virDomainChrDef virDomainChrDef;
+typedef virDomainChrDef *virDomainChrDefPtr;
+struct _virDomainChrDef {
+ int dstPort;
+
+ int type;
+ union {
+ struct {
+ char *path;
+ } file; /* pty, file, pipe, or device */
+ struct {
+ char *host;
+ char *service;
+ int listen;
+ int protocol;
+ } tcp;
+ struct {
+ char *bindHost;
+ char *bindService;
+ char *connectHost;
+ char *connectService;
+ } udp;
+ struct {
+ char *path;
+ int listen;
+ } nix;
+ } data;
+
+ virDomainChrDefPtr next;
+};
+
+enum virDomainInputType {
+ VIR_DOMAIN_INPUT_TYPE_MOUSE,
+ VIR_DOMAIN_INPUT_TYPE_TABLET,
+
+ VIR_DOMAIN_INPUT_TYPE_LAST,
+};
+
+enum virDomainInputBus {
+ VIR_DOMAIN_INPUT_BUS_PS2,
+ VIR_DOMAIN_INPUT_BUS_USB,
+ VIR_DOMAIN_INPUT_BUS_XEN,
+
+ VIR_DOMAIN_INPUT_BUS_LAST
+};
+
+typedef struct _virDomainInputDef virDomainInputDef;
+typedef virDomainInputDef *virDomainInputDefPtr;
+struct _virDomainInputDef {
+ int type;
+ int bus;
+ virDomainInputDefPtr next;
+};
+
+enum virDomainSoundModel {
+ VIR_DOMAIN_SOUND_MODEL_SB16,
+ VIR_DOMAIN_SOUND_MODEL_ES1370,
+ VIR_DOMAIN_SOUND_MODEL_PCSPK,
+
+ VIR_DOMAIN_SOUND_MODEL_LAST
+};
+
+typedef struct _virDomainSoundDef virDomainSoundDef;
+typedef virDomainSoundDef *virDomainSoundDefPtr;
+struct _virDomainSoundDef {
+ int model;
+ virDomainSoundDefPtr next;
+};
+
+/* 3 possible graphics console modes */
+enum virDomainGraphicsType {
+ VIR_DOMAIN_GRAPHICS_TYPE_SDL,
+ VIR_DOMAIN_GRAPHICS_TYPE_VNC,
+
+ VIR_DOMAIN_GRAPHICS_TYPE_LAST,
+};
+
+typedef struct _virDomainGraphicsDef virDomainGraphicsDef;
+typedef virDomainGraphicsDef *virDomainGraphicsDefPtr;
+struct _virDomainGraphicsDef {
+ int type;
+ union {
+ struct {
+ int port;
+ int autoport : 1;
+ char *listenAddr;
+ char *keymap;
+ char *passwd;
+ } vnc;
+ struct {
+ char *display;
+ char *xauth;
+ } sdl;
+ } data;
+};
+
+
+
+/* Flags for the 'type' field in next struct */
+enum virDomainDeviceType {
+ VIR_DOMAIN_DEVICE_DISK,
+ VIR_DOMAIN_DEVICE_NET,
+ VIR_DOMAIN_DEVICE_INPUT,
+ VIR_DOMAIN_DEVICE_SOUND,
+};
+
+typedef struct _virDomainDeviceDef virDomainDeviceDef;
+typedef virDomainDeviceDef *virDomainDeviceDefPtr;
+struct _virDomainDeviceDef {
+ int type;
+ union {
+ virDomainDiskDefPtr disk;
+ virDomainNetDefPtr net;
+ virDomainInputDefPtr input;
+ virDomainSoundDefPtr sound;
+ } data;
+};
+
+
+#define VIR_DOMAIN_MAX_BOOT_DEVS 4
+
+/* 3 possible boot devices */
+enum virDomainBootOrder {
+ VIR_DOMAIN_BOOT_FLOPPY,
+ VIR_DOMAIN_BOOT_CDROM,
+ VIR_DOMAIN_BOOT_DISK,
+ VIR_DOMAIN_BOOT_NET,
+
+ VIR_DOMAIN_BOOT_LAST,
+};
+
+enum virDomainFeature {
+ VIR_DOMAIN_FEATURE_ACPI,
+ VIR_DOMAIN_FEATURE_APIC,
+ VIR_DOMAIN_FEATURE_PAE,
+
+ VIR_DOMAIN_FEATURE_LAST
+};
+
+enum virDomainLifecycleAction {
+ VIR_DOMAIN_LIFECYCLE_DESTROY,
+ VIR_DOMAIN_LIFECYCLE_RESTART,
+ VIR_DOMAIN_LIFECYCLE_RESTART_RENAME,
+ VIR_DOMAIN_LIFECYCLE_PRESERVE,
+
+ VIR_DOMAIN_LIFECYCLE_LAST
+};
+
+/* Operating system configuration data & machine / arch */
+typedef struct _virDomainOSDef virDomainOSDef;
+typedef virDomainOSDef *virDomainOSDefPtr;
+struct _virDomainOSDef {
+ char *type;
+ char *arch;
+ char *machine;
+ int nBootDevs;
+ int bootDevs[VIR_DOMAIN_BOOT_LAST];
+ char *kernel;
+ char *initrd;
+ char *cmdline;
+ char *root;
+ char *loader;
+ char *bootloader;
+ char *bootloaderArgs;
+};
+
+#define VIR_DOMAIN_CPUMASK_LEN 1024
+
+/* Guest VM main configuration */
+typedef struct _virDomainDef virDomainDef;
+typedef virDomainDef *virDomainDefPtr;
+struct _virDomainDef {
+ int virtType;
+ int id;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ char *name;
+
+ unsigned long memory;
+ unsigned long maxmem;
+ unsigned long vcpus;
+ int cpumasklen;
+ char *cpumask;
+
+ /* These 3 are based on virDomainLifeCycleAction enum flags */
+ int onReboot;
+ int onPoweroff;
+ int onCrash;
+
+ virDomainOSDef os;
+ char *emulator;
+ int features;
+
+ int localtime;
+
+ virDomainGraphicsDefPtr graphics;
+ virDomainDiskDefPtr disks;
+ virDomainNetDefPtr nets;
+ virDomainInputDefPtr inputs;
+ virDomainSoundDefPtr sounds;
+ virDomainChrDefPtr serials;
+ virDomainChrDefPtr parallels;
+ virDomainChrDefPtr console;
+};
+
+/* Guest VM runtime state */
+typedef struct _virDomainObj virDomainObj;
+typedef virDomainObj *virDomainObjPtr;
+struct _virDomainObj {
+ int stdin;
+ int stdout;
+ int stderr;
+ int monitor;
+ int logfile;
+ int pid;
+ int state;
+
+ int nvcpupids;
+ int *vcpupids;
+
+ unsigned int autostart : 1;
+ unsigned int persistent : 1;
+
+ char *configFile;
+ char *autostartLink;
+
+ virDomainDefPtr def; /* The current definition */
+ virDomainDefPtr newDef; /* New definition to activate at shutdown */
+
+ virDomainObjPtr next;
+};
+
+
+static inline int
+virDomainIsActive(virDomainObjPtr dom)
+{
+ return dom->def->id != -1;
+}
+
+
+virDomainObjPtr virDomainFindByID(const virDomainObjPtr doms,
+ int id);
+virDomainObjPtr virDomainFindByUUID(const virDomainObjPtr doms,
+ const unsigned char *uuid);
+virDomainObjPtr virDomainFindByName(const virDomainObjPtr doms,
+ const char *name);
+
+
+void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
+void virDomainInputDefFree(virDomainInputDefPtr def);
+void virDomainDiskDefFree(virDomainDiskDefPtr def);
+void virDomainNetDefFree(virDomainNetDefPtr def);
+void virDomainChrDefFree(virDomainChrDefPtr def);
+void virDomainSoundDefFree(virDomainSoundDefPtr def);
+void virDomainDefFree(virDomainDefPtr vm);
+void virDomainObjFree(virDomainObjPtr vm);
+
+virDomainObjPtr virDomainAssignDef(virConnectPtr conn,
+ virDomainObjPtr *doms,
+ const virDomainDefPtr def);
+void virDomainRemoveInactive(virDomainObjPtr *doms,
+ virDomainObjPtr dom);
+
+virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
+ const virDomainDefPtr def,
+ const char *xmlStr);
+virDomainDefPtr virDomainDefParse(virConnectPtr conn,
+ virCapsPtr caps,
+ const char *xmlStr,
+ const char *displayName);
+char *virDomainDefFormat(virConnectPtr conn,
+ virDomainDefPtr def,
+ int secure);
+
+int virDomainCpuSetParse(virConnectPtr conn,
+ const char **str,
+ char sep,
+ char *cpuset,
+ int maxcpu);
+char *virDomainCpuSetFormat(virConnectPtr conn,
+ char *cpuset,
+ int maxcpu);
+
+VIR_ENUM_DECL(virDomainVirt)
+VIR_ENUM_DECL(virDomainBoot)
+VIR_ENUM_DECL(virDomainFeature)
+VIR_ENUM_DECL(virDomainLifecycle)
+VIR_ENUM_DECL(virDomainDisk)
+VIR_ENUM_DECL(virDomainDiskDevice)
+VIR_ENUM_DECL(virDomainDiskBus)
+VIR_ENUM_DECL(virDomainNet)
+VIR_ENUM_DECL(virDomainChr)
+VIR_ENUM_DECL(virDomainSoundModel)
+VIR_ENUM_DECL(virDomainInput)
+VIR_ENUM_DECL(virDomainInputBus)
+VIR_ENUM_DECL(virDomainGraphics)
+
+#endif /* __DOMAIN_CONF_H */
diff -r f47fdc49c62f src/util.h
--- a/src/util.h Sun Jun 22 17:58:48 2008 -0400
+++ b/src/util.h Sun Jun 22 18:31:20 2008 -0400
@@ -100,7 +100,7 @@
#define VIR_ENUM_IMPL(name, lastVal, ...) \
static const char const *name ## TypeList[] = { __VA_ARGS__ }; \
- verify(ARRAY_CARDINALITY(name ## TypeList) == lastVal); \
+ extern int (* name ## Verify (void)) [verify_true (ARRAY_CARDINALITY(name ## TypeList) == lastVal)]; \
const char *name ## TypeToString(int type) { \
return virEnumToString(name ## TypeList, \
ARRAY_CARDINALITY(name ## TypeList), \
diff -r f47fdc49c62f src/xml.c
--- a/src/xml.c Sun Jun 22 17:58:48 2008 -0400
+++ b/src/xml.c Sun Jun 22 18:31:20 2008 -0400
@@ -490,6 +490,59 @@
}
/**
+ * virXPathULong:
+ * @xpath: the XPath string to evaluate
+ * @ctxt: an XPath context
+ * @value: the returned long value
+ *
+ * Convenience function to evaluate an XPath number
+ *
+ * Returns 0 in case of success in which case @value is set,
+ * or -1 if the XPath evaluation failed or -2 if the
+ * value doesn't have a long format.
+ */
+int
+virXPathULong(const char *xpath, xmlXPathContextPtr ctxt, unsigned long *value)
+{
+ xmlXPathObjectPtr obj;
+ int ret = 0;
+
+ if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
+ virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("Invalid parameter to virXPathNumber()"), 0);
+ return (-1);
+ }
+ obj = xmlXPathEval(BAD_CAST xpath, ctxt);
+ if ((obj != NULL) && (obj->type == XPATH_STRING) &&
+ (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
+ char *conv = NULL;
+ long val;
+
+ val = strtoul((const char *) obj->stringval, &conv, 10);
+ if (conv == (const char *) obj->stringval) {
+ ret = -2;
+ } else {
+ *value = val;
+ }
+ } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
+ (!(isnan(obj->floatval)))) {
+ if (obj->floatval < 0) {
+ ret = -2;
+ } else {
+ *value = (unsigned long) obj->floatval;
+ if (*value != obj->floatval) {
+ ret = -2;
+ }
+ }
+ } else {
+ ret = -1;
+ }
+
+ xmlXPathFreeObject(obj);
+ return (ret);
+}
+
+/**
* virXPathBoolean:
* @xpath: the XPath string to evaluate
* @ctxt: an XPath context
@@ -578,18 +631,18 @@
_("Invalid parameter to virXPathNodeSet()"), 0);
return (-1);
}
+ if (list != NULL)
+ *list = NULL;
+
obj = xmlXPathEval(BAD_CAST xpath, ctxt);
if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
- (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
- (obj->nodesetval->nodeTab == NULL)) {
+ (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr < 0)) {
xmlXPathFreeObject(obj);
- if (list != NULL)
- *list = NULL;
return (-1);
}
ret = obj->nodesetval->nodeNr;
- if (list != NULL) {
+ if (list != NULL && ret) {
if (VIR_ALLOC_N(*list, ret) < 0) {
virXMLError(NULL, VIR_ERR_NO_MEMORY,
_("allocate string array"),
@@ -602,6 +655,13 @@
}
xmlXPathFreeObject(obj);
return (ret);
+}
+
+char *
+virXMLPropString(xmlNodePtr node,
+ const char *name)
+{
+ return (char *)xmlGetProp(node, BAD_CAST name);
}
/************************************************************************
diff -r f47fdc49c62f src/xml.h
--- a/src/xml.h Sun Jun 22 17:58:48 2008 -0400
+++ b/src/xml.h Sun Jun 22 18:31:20 2008 -0400
@@ -23,14 +23,27 @@
int virXPathNumber (const char *xpath,
xmlXPathContextPtr ctxt,
double *value);
+int virXPathInt (const char *xpath,
+ xmlXPathContextPtr ctxt,
+ int *value);
+int virXPathUInt (const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned int *value);
int virXPathLong (const char *xpath,
xmlXPathContextPtr ctxt,
long *value);
+int virXPathULong (const char *xpath,
+ xmlXPathContextPtr ctxt,
+ unsigned long *value);
xmlNodePtr virXPathNode (const char *xpath,
xmlXPathContextPtr ctxt);
int virXPathNodeSet (const char *xpath,
xmlXPathContextPtr ctxt,
xmlNodePtr **list);
+
+char * virXMLPropString(xmlNodePtr node,
+ const char *name);
+
#if WITH_XEN || WITH_QEMU
int virParseCpuSet (virConnectPtr conn,
--
|: 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 :|
16 years, 6 months
[libvirt] [PATCH] fix_syntax_check
by Atsushi SAKAI
Hi, Daniel
I accidentally met the following error.
Just changes tabs to spaces.
xm_internal.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Thanks
Atsushi SAKAI
16 years, 6 months
[libvirt] Using Xen config files
by Thomas Moyer
Is it possible to directly utilize the Xen config files when using the
python bindings for libvirt? If not, is there any automated method of
converting the Xen config to a libvirt XML config?
--
Thomas Moyer
Graduate Student
CSE Department
Penn State University
tmmoyer(a)cse.psu.edu
http://www.cse.psu.edu/~tmmoyer
16 years, 6 months
[libvirt] MinGW environment for libvirt (at this moment))
by Atsushi SAKAI
Hi,
This is a current memo for building MinGW environment for libvirt.
(up to run src/.libs/virsh.exe)
Of course this Windows path is opened by Rich.
this is another way to build this.
Ref.
http://www.redhat.com/archives/libvir-list/2008-January/msg00017.html
Compares to Rich one, 2 different point exists
1)GCC version is keeps 3.x not 4.x.
2)libxml2 is using GTK one.
Any suggestions are welcome.
Since I want to simplify this complicated procedure.
1.Install MinGW-5.1.4.exe
2.Install MSYS-1.0.11-2004.04.30-1.exe
3.Install msysDTK-1.0.1.exe
Above files are taken from following
http://sourceforge.net/project/showfiles.php?group_id=2435
4.Install gtk-dev-2.12.9-win32-2.exe
(This is for using pkg-config/gettext/libxml2)
Taken from
http://gladewin32.sourceforge.net/
5.expand m4-1.4.7-MSYS.tar.bz2 from root directory
(we need 1.4.5 or later but msysDTK installs 1.4)
Taken from
http://sourceforge.net/project/showfiles.php?group_id=2435
6.Install autoconf-2.62.tar.gz
./configure --prefix=/usr
make
make install
Taken from
http://www.gnu.org/software/autoconf/
7.Install automake-1.10.1.tar.gz
./configure --prefix=/usr
make
make install
(create /usr/share/aclocal-1.10)
Taken from
http://www.gnu.org/software/automake/
8.Install libtool-1.5.18.tar.gz
./configure --prefix=/usr
make
make install
Taken from
http://www.gnu.org/software/libtool/
9.Add m4 script for aclocal
cp /mingw/lib/GTK/share/aclocal/* /usr/share/aclocal
(This is for running autogen.sh)
10..Install GNUTLS
expand gnutls-2.3.13.exe to c:\msys\1.0
(it goes to /usr)(This is for /usr/share/aclocal)
cp -r /usr/include/gnutls /mingw/include
cp /usr/lib/libgnutls* /mingw/lib
cp /usr/lib/libgpg-error* /mingw/lib
cp /usr/lib/libgcrypt* /mingw/lib
cp /usr/lib/tasn1.* /mingw/lib
rewrite dependency_libs on /mingw/lib/libgnutls.la
from /home/jas/gnutls4win/inst to /mingw
Taken from
http://josefsson.org/gnutls4win/
11.expand xdr
Install xdr-4.0-mingw5.tar.gz(see Rich Page)
rpc => /mingw/include
lib*.a => /mingw/lib
http://www.annexia.org/tmp/xdr-4.0-mingw5.tar.gz
12.get libvirt code from CVS repository
comment out siginfo_t
(currently this problem is assigned to me)
ftp://libvirt.org/libvirt/
13.create virsh
./autogen.sh (tgz file lacks this. you should get CVS repository)
./configure --without-xen --without-qemu --without-sasl --without-libvirtd
make
(Ignore compile stops at testutils.c)
(this problem is also assigned to me.)
14.execute src/.libs/virsh.exe
Thanks
Atsushi SAKAI
16 years, 6 months
[libvirt] ULLONG_MAX undeclared
by a.hocquel@free.fr
Hi,
I subscribed today on the list because I have a compilation problem of libvirt 0.4.2 and 0.4.3 (didn't try the other versions).
I'm trying to compile libvirt on a Debian Etch with Xen 3.2.0 (also tried with a 3.2.1)
Every time I have this mistake:
storage_conf.c: In function 'virStorageSize':
storage_conf.c:659: error: 'ULLONG_MAX' undeclared (first use in this function)
storage_conf.c:659: error: (Each undeclared identifier is reported only once
storage_conf.c:659: error: for each function it appears in.)
make[2]: *** [libvirt_la-storage_conf.lo] Error 1
make[2]: Leaving directory `/usr/src/libvirt-0.4.2/src'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/usr/src/libvirt-0.4.2'
make: *** [all] Error 2
I looked for ULLONG_MAX and find it in /usr/include/limits.h and /usr/include/linux/kernel.h
So first I decided to add
#include <limits.h>
inside storage_conf.c
but it didn't change anything.
Surely the definition of ULLONG_MAX is surrounded by an "unwelcome" condition.
So actually to succeed the compilation I directly added:
# define ULLONG_MAX 18446744073709551615ULL
inside the files (storage_backend_fs.c need it too).
I know that's dirty, so is there anybody who can help me to make it in a clean way?
Thank you by advance.
Best Regards,
Alex
16 years, 6 months
[libvirt] Question about compilation on MinGW(StorageAPI)
by Atsushi SAKAI
Hi, Rich and Dan
I have a question about libvirt on MinGW.
As you know, MinGW supports remote management only.
In this situation, Storage API(dir) should be off.
Can I configure it? or other way exists?
One more question on MinGW with Ruby,
Does someone already test the Ruby bindings on MinGW?
I am stacked this on configuration of "rake" on MinGW.
Thanks
Atsushi SAKAI
16 years, 6 months