diff --git a/fs-storage-driver.patch b/fs-storage-driver.patch
index 2429882..9e6fef6 100644
--- a/fs-storage-driver.patch
+++ b/fs-storage-driver.patch
@@ -1,8 +1,8 @@
-Index: libvirt-0.4.4/src/storage_backend_fs.c
+Index: libvirt-0.4.5/src/storage_backend_fs.c
===================================================================
---- libvirt-0.4.4.orig/src/storage_backend_fs.c
-+++ libvirt-0.4.4/src/storage_backend_fs.c
-@@ -455,7 +455,9 @@ virStorageBackendFileSystemIsMounted(vir
+--- libvirt-0.4.5.orig/src/storage_backend_fs.c
++++ libvirt-0.4.5/src/storage_backend_fs.c
+@@ -583,7 +583,9 @@ virStorageBackendFileSystemIsMounted(vir
virStoragePoolObjPtr pool) {
FILE *mtab;
struct mntent *ent;
@@ -13,7 +13,7 @@ Index: libvirt-0.4.4/src/storage_backend_fs.c
if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) {
virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
_("cannot read %s: %s"),
-@@ -463,14 +465,27 @@ virStorageBackendFileSystemIsMounted(vir
+@@ -591,14 +593,27 @@ virStorageBackendFileSystemIsMounted(vir
return -1;
}
@@ -42,7 +42,7 @@ Index: libvirt-0.4.4/src/storage_backend_fs.c
return 0;
}
-@@ -797,12 +812,16 @@ virStorageBackendFileSystemDelete(virCon
+@@ -951,12 +966,16 @@ virStorageBackendFileSystemDelete(virCon
{
/* XXX delete all vols first ? */
diff --git a/libvirt-0.4.4.tar.bz2 b/libvirt-0.4.4.tar.bz2
deleted file mode 100644
index d791bfb..0000000
--- a/libvirt-0.4.4.tar.bz2
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:2f04d72f036b077c29f8af811e0e3ede9d44fe61a7e7ac4bdc35f14d297d6941
-size 2944387
diff --git a/libvirt-0.4.6.tar.bz2 b/libvirt-0.4.6.tar.bz2
new file mode 100644
index 0000000..c42f407
--- /dev/null
+++ b/libvirt-0.4.6.tar.bz2
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:135ab72ebfba0359972e0fa0b4e643c4b744a0ebc9d60b3fb5e5518b5e575355
+size 3136828
diff --git a/libvirt.changes b/libvirt.changes
index 466ba88..61b5ba8 100644
--- a/libvirt.changes
+++ b/libvirt.changes
@@ -1,3 +1,58 @@
+-------------------------------------------------------------------
+Mon Oct 6 15:36:17 MDT 2008 - jfehlig@novell.com
+
+- Use xend vs hypercall interface to change max mem setting
+ bnc#431766
+
+-------------------------------------------------------------------
+Wed Oct 1 16:04:21 MDT 2008 - jfehlig@novell.com
+
+- Enabled libvirtd listen mode in libvirtd init script.
+
+-------------------------------------------------------------------
+Tue Sep 30 19:07:45 MDT 2008 - jfehlig@novell.com
+
+- Updated to version 0.4.6
+ - avoid a segfault if missing qemu emulator
+ - reading vncdisplay from xend domain
+ - segfault in OpenVZ
+ - fix parsing of pool without a source
+- Fixed bug in network interface parsing
+ - vif-parsing.patch submitted upstream
+
+-------------------------------------------------------------------
+Tue Sep 16 13:02:40 MDT 2008 - jfehlig@novell.com
+
+- open-iscsi package required for iscsi storage backend
+
+-------------------------------------------------------------------
+Mon Sep 15 15:59:28 MDT 2008 - jfehlig@novell.com
+
+- Updated to version 0.4.5
+ - NETNS support for Linux containers
+ - unified XML domain and network parsing for all drivers
+ - OpenVZ features improvements
+ - OpenVZ and Linux containers support now default
+ - USB device passthrough for QEmu/KVM
+ - storage pool source discovery
+ - other bug fixes and improvements
+
+-------------------------------------------------------------------
+Thu Sep 4 15:49:55 CEST 2008 - kwolf@suse.de
+
+- Added Python bindings for the snapshot functions
+
+-------------------------------------------------------------------
+Wed Sep 3 21:09:27 CEST 2008 - kwolf@suse.de
+
+- Implemented listing of snapshots for Xen and in virsh
+
+-------------------------------------------------------------------
+Tue Sep 2 13:23:22 CEST 2008 - kwolf@suse.de
+
+- Added snapshot support. Implemented snapshot_create/apply/delete
+ for Xen.
+
-------------------------------------------------------------------
Fri Aug 29 17:37:53 MDT 2008 - jfehlig@novell.com
diff --git a/libvirt.spec b/libvirt.spec
index cf2b347..4b21c53 100644
--- a/libvirt.spec
+++ b/libvirt.spec
@@ -1,5 +1,5 @@
#
-# spec file for package libvirt (Version 0.4.4)
+# spec file for package libvirt (Version 0.4.6)
#
# Copyright (c) 2008 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
@@ -48,8 +48,8 @@ Url: http://libvirt.org/
License: LGPL v2.1 or later
Group: Development/Libraries/C and C++
AutoReqProv: yes
-Version: 0.4.4
-Release: 28
+Version: 0.4.6
+Release: 1
Summary: A C toolkit to interract with the virtualization capabilities of Linux
Requires: readline
Requires: ncurses
@@ -58,17 +58,20 @@ Requires: iptables
Requires: cyrus-sasl
Requires: lvm2
Requires: parted
+#Requires: /usr/bin/qemu-img
Recommends: cyrus-sasl-digestmd5
Requires: dnsmasq
Requires: PolicyKit >= 0.6
Requires: socat
+Requires: open-iscsi
Source0: %{name}-%{version}.tar.bz2
Source1: libvirtd.init
-Patch0: libvirtd-polkit.patch
-Patch1: socat.patch
-Patch2: libvirtd-defaults.patch
-Patch3: logical-storage-driver.patch
-Patch4: fs-storage-driver.patch
+Patch0: socat.patch
+Patch1: libvirtd-defaults.patch
+Patch2: fs-storage-driver.patch
+Patch3: snapshots.patch
+Patch4: vif-parsing.patch
+Patch5: xen-maxmem.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-build
%description
@@ -164,14 +167,15 @@ Authors:
%patch2 -p1
%patch3 -p1
%patch4 -p1
+%patch5 -p1
rm po/no.*
%build
%if ! %{with_xen}
%define _without_xen --without-xen
%endif
-%if %{with_lxc}
-%define _with_lxc --with-lxc
+%if ! %{with_lxc}
+%define _without_lxc --without-lxc
%endif
%if %{with_selinux}
%define _with_selinux --with-selinux
@@ -179,14 +183,14 @@ rm po/no.*
autoreconf -f -i
export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing"
%configure %{?_without_xen} \
- %{?_with_lxc} \
+ %{?_without_lxc} \
%{?_with_selinux} \
--libexecdir=%{_libdir}/%{name} \
--with-init-script=none \
--with-remote-pid-file=%{_localstatedir}/run/libvirtd.pid \
--with-xen-proxy=no \
ac_cv_path_DNSMASQ=/usr/sbin/dnsmasq \
- ac_cv_path_QEMU_IMG=/usr/bin/qemu-img \
+ ac_cv_path_QEMU_IMG=/usr/bin/qemu-img-xen \
ac_cv_path_ISCSIADM=/sbin/iscsiadm
make DOCS_DIR=%{_docdir}/%{name}-python EXAMPLE_DIR=%{_docdir}/%{name}-python/examples HTML_DIR=%{_docdir}/%{name}
cd docs/examples ; make index.html ; cd ../..
@@ -199,6 +203,11 @@ rm -rf $RPM_BUILD_ROOT/usr/share/locale/sr@latin
# for now, do not install the default network definition
rm -f $RPM_BUILD_ROOT%{_sysconfdir}/libvirt/qemu/networks/default.xml
rm -f $RPM_BUILD_ROOT%{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml
+# do not package augeas config files for now
+rm -f $RPM_BUILD_ROOT%{_datadir}/augeas/lenses/libvirtd.aug
+rm -f $RPM_BUILD_ROOT%{_datadir}/augeas/lenses/libvirtd_qemu.aug
+rm -f $RPM_BUILD_ROOT%{_datadir}/augeas/lenses/tests/test_libvirtd.aug
+rm -f $RPM_BUILD_ROOT%{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
mkdir -p $RPM_BUILD_ROOT/%{_localstatedir}/run/libvirt
mkdir -p $RPM_BUILD_ROOT/%{_localstatedir}/lib/libvirt
rm $RPM_BUILD_ROOT%{_docdir}/%{name}/{*.c,examples.x*}
@@ -253,6 +262,9 @@ rm -rf $RPM_BUILD_ROOT
%if 0%{?suse_version} > 1030
%{_libdir}/%{name}/libvirt_parthelper
%endif
+%if %{with_lxc}
+%attr(0755, root, root) %{_libdir}/%{name}/libvirt_lxc
+%endif
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/
@@ -265,7 +277,7 @@ rm -rf $RPM_BUILD_ROOT
%config %{_sysconfdir}/libvirt/qemu.conf
%config %{_sysconfdir}/sasl2/libvirt.conf
%if 0%{?suse_version} > 1030
-%{_datadir}/PolicyKit/policy/libvirtd.policy
+%{_datadir}/PolicyKit/policy/org.libvirt.unix.policy
%endif
%files devel
@@ -288,6 +300,37 @@ rm -rf $RPM_BUILD_ROOT
%{py_sitedir}/libvirtmod*
%changelog
+* Mon Oct 06 2008 jfehlig@novell.com
+- Use xend vs hypercall interface to change max mem setting
+ bnc#431766
+* Wed Oct 01 2008 jfehlig@novell.com
+- Enabled libvirtd listen mode in libvirtd init script.
+* Tue Sep 30 2008 jfehlig@novell.com
+- Updated to version 0.4.6
+ - avoid a segfault if missing qemu emulator
+ - reading vncdisplay from xend domain
+ - segfault in OpenVZ
+ - fix parsing of pool without a source
+- Fixed bug in network interface parsing
+ - vif-parsing.patch submitted upstream
+* Tue Sep 16 2008 jfehlig@novell.com
+- open-iscsi package required for iscsi storage backend
+* Mon Sep 15 2008 jfehlig@novell.com
+- Updated to version 0.4.5
+ - NETNS support for Linux containers
+ - unified XML domain and network parsing for all drivers
+ - OpenVZ features improvements
+ - OpenVZ and Linux containers support now default
+ - USB device passthrough for QEmu/KVM
+ - storage pool source discovery
+ - other bug fixes and improvements
+* Thu Sep 04 2008 kwolf@suse.de
+- Added Python bindings for the snapshot functions
+* Wed Sep 03 2008 kwolf@suse.de
+- Implemented listing of snapshots for Xen and in virsh
+* Tue Sep 02 2008 kwolf@suse.de
+- Added snapshot support. Implemented snapshot_create/apply/delete
+ for Xen.
* Fri Aug 29 2008 jfehlig@novell.com
- Fixed bugs in nfs storage pool creation/deletion
* Thu Aug 28 2008 jfehlig@novell.com
diff --git a/libvirtd-polkit.patch b/libvirtd-polkit.patch
deleted file mode 100644
index 1baf0c3..0000000
--- a/libvirtd-polkit.patch
+++ /dev/null
@@ -1,14 +0,0 @@
-diff -ru a/qemud/libvirtd.policy b/qemud/libvirtd.policy
---- a/qemud/libvirtd.policy 2007-12-05 11:21:27.000000000 -0700
-+++ b/qemud/libvirtd.policy 2008-05-09 09:28:26.000000000 -0600
-@@ -36,7 +36,7 @@
- read-write mode for management, and we require user password -->
- no
- no
-- auth_self_keep_session
-+ auth_admin_keep_session
-
-
-
-\ No newline at end of file
-Only in b/qemud: libvirtd.policy~
diff --git a/libvirtd.init b/libvirtd.init
index 76b98c2..5af6963 100644
--- a/libvirtd.init
+++ b/libvirtd.init
@@ -31,7 +31,7 @@ rc_reset
case "$1" in
start)
echo -n "Starting libvirtd "
- startproc $LIBVIRTD_BIN -d
+ startproc $LIBVIRTD_BIN -d -l
rc_status -v
;;
stop)
diff --git a/logical-storage-driver.patch b/logical-storage-driver.patch
deleted file mode 100644
index 625d05e..0000000
--- a/logical-storage-driver.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-Index: libvirt-0.4.4/src/storage_backend_logical.c
-===================================================================
---- libvirt-0.4.4.orig/src/storage_backend_logical.c
-+++ libvirt-0.4.4/src/storage_backend_logical.c
-@@ -280,7 +280,7 @@ virStorageBackendLogicalBuildPool(virCon
- memset(zeros, 0, sizeof(zeros));
-
- /* XXX multiple pvs */
-- if (VIR_ALLOC_N(vgargv, 1) < 0) {
-+ if (VIR_ALLOC_N(vgargv, 3 + pool->def->source.ndevice) < 0) {
- virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("command line"));
- return -1;
- }
-@@ -531,6 +531,7 @@ virStorageBackend virStorageBackendLogic
- .deleteVol = virStorageBackendLogicalDeleteVol,
-
- .poolOptions = {
-+ .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE),
- .formatFromString = virStorageBackendLogicalPoolFormatFromString,
- .formatToString = virStorageBackendLogicalPoolFormatToString,
- },
diff --git a/snapshots.patch b/snapshots.patch
new file mode 100644
index 0000000..291e80e
--- /dev/null
+++ b/snapshots.patch
@@ -0,0 +1,1215 @@
+Index: libvirt-0.4.6/include/libvirt/libvirt.h.in
+===================================================================
+--- libvirt-0.4.6.orig/include/libvirt/libvirt.h.in
++++ libvirt-0.4.6/include/libvirt/libvirt.h.in
+@@ -470,6 +470,21 @@ int virDomainRestore
+ const char *from);
+
+ /*
++ * Snapshots
++ */
++int virDomainSnapshotCreate (virDomainPtr domain,
++ const char* name);
++int virDomainSnapshotApply (virDomainPtr domain,
++ const char* name);
++int virDomainSnapshotDelete (virDomainPtr domain,
++ const char* name);
++int virDomainNumOfSnapshots (virDomainPtr domain);
++int virDomainListSnapshots (virDomainPtr domain,
++ char **const names,
++ int maxnames);
++
++
++/*
+ * Domain core dump
+ */
+ int virDomainCoreDump (virDomainPtr domain,
+Index: libvirt-0.4.6/src/libvirt.c
+===================================================================
+--- libvirt-0.4.6.orig/src/libvirt.c
++++ libvirt-0.4.6/src/libvirt.c
+@@ -1659,6 +1659,168 @@ virDomainRestore(virConnectPtr conn, con
+ return -1;
+ }
+
++
++/**
++ * virDomainSnapshotCreate:
++ * @domain: a domain object
++ * @name: name for the new snapshot
++ *
++ * Creates a snapshot from a running domain
++ *
++ * Returns 0 in case of success and -1 in case of failure.
++ */
++int
++virDomainSnapshotCreate(virDomainPtr domain, const char* name)
++{
++ virConnectPtr conn;
++
++ DEBUG("domain=%p", domain);
++
++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
++ return (-1);
++ }
++
++ conn = domain->conn;
++ if (conn->flags & VIR_CONNECT_RO) {
++ virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
++ return (-1);
++ }
++
++ if (conn->driver->domainSnapshotCreate)
++ return conn->driver->domainSnapshotCreate(domain, name);
++
++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
++ return -1;
++}
++
++/**
++ * virDomainSnapshotApply:
++ * @domain: a domain object
++ * @name: name of the snapshot to apply
++ *
++ * Starts a domain using a given snapshot. The domain needs to be shut down
++ * before calling thsi function.
++ *
++ * Returns 0 in case of success and -1 in case of failure.
++ */
++int
++virDomainSnapshotApply(virDomainPtr domain, const char* name)
++{
++ virConnectPtr conn;
++
++ DEBUG("domain=%p", domain);
++
++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
++ return (-1);
++ }
++
++ conn = domain->conn;
++ if (conn->flags & VIR_CONNECT_RO) {
++ virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
++ return (-1);
++ }
++
++ if (conn->driver->domainSnapshotApply)
++ return conn->driver->domainSnapshotApply(domain, name);
++
++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
++ return -1;
++}
++
++/**
++ * virDomainSnapshotDelete:
++ * @domain: a domain object
++ * @name: name of the snapshot to delete
++ *
++ * Deletes a snapshot from the given domain
++ *
++ * Returns 0 in case of success and -1 in case of failure.
++ */
++int
++virDomainSnapshotDelete(virDomainPtr domain, const char* name)
++{
++ virConnectPtr conn;
++
++ DEBUG("domain=%p", domain);
++
++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
++ return (-1);
++ }
++
++ conn = domain->conn;
++ if (conn->flags & VIR_CONNECT_RO) {
++ virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
++ return (-1);
++ }
++
++ if (conn->driver->domainSnapshotDelete)
++ return conn->driver->domainSnapshotDelete(domain, name);
++
++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
++ return -1;
++}
++
++/**
++ * virDomainNumOfSnapshots:
++ * @domain: a domain object
++ *
++ * Returns the number of snapshots of the given domain or -1 in case of failure
++ */
++int
++virDomainNumOfSnapshots(virDomainPtr domain)
++{
++ virConnectPtr conn;
++
++ DEBUG("domain=%p", domain);
++
++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
++ return (-1);
++ }
++
++ conn = domain->conn;
++ if (conn->driver->domainNumOfSnapshots)
++ return conn->driver->domainNumOfSnapshots(domain);
++
++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
++ return -1;
++}
++
++/**
++ * virDomainListSnapshots:
++ * @domain: a domain object
++ * @names: pointer to an array to store the snapshot names
++ * @maxnames: size of the array
++ *
++ * List the names of all snapshots of the given domain. The names are
++ * stored in the @names array. Unused array entries are set to NULL.
++ *
++ * Returns 0 in case of success and -1 in case of failure.
++ */
++int
++virDomainListSnapshots(virDomainPtr domain, char **const names, int maxnames)
++{
++ virConnectPtr conn;
++
++ DEBUG("domain=%p", domain);
++
++ if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
++ virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
++ return (-1);
++ }
++
++ conn = domain->conn;
++ if (conn->driver->domainListSnapshots)
++ return conn->driver->domainListSnapshots(domain, names, maxnames);
++
++ virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
++ return -1;
++}
++
++
+ /**
+ * virDomainCoreDump:
+ * @domain: a domain object
+Index: libvirt-0.4.6/src/driver.h
+===================================================================
+--- libvirt-0.4.6.orig/src/driver.h
++++ libvirt-0.4.6/src/driver.h
+@@ -146,6 +146,21 @@ typedef int
+ (*virDrvDomainRestore) (virConnectPtr conn,
+ const char *from);
+ typedef int
++ (*virDrvDomainSnapshotCreate) (virDomainPtr domain,
++ const char* name);
++typedef int
++ (*virDrvDomainSnapshotApply) (virDomainPtr domain,
++ const char* name);
++typedef int
++ (*virDrvDomainSnapshotDelete) (virDomainPtr domain,
++ const char* name);
++typedef int
++ (*virDrvDomainNumOfSnapshots) (virDomainPtr domain);
++typedef int
++ (*virDrvDomainListSnapshots) (virDomainPtr domain,
++ char **const names,
++ int maxnames);
++typedef int
+ (*virDrvDomainCoreDump) (virDomainPtr domain,
+ const char *to,
+ int flags);
+@@ -352,6 +367,12 @@ struct _virDriver {
+ virDrvDomainMemoryPeek domainMemoryPeek;
+ virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory;
+ virDrvNodeGetFreeMemory getFreeMemory;
++
++ virDrvDomainSnapshotCreate domainSnapshotCreate;
++ virDrvDomainSnapshotApply domainSnapshotApply;
++ virDrvDomainSnapshotDelete domainSnapshotDelete;
++ virDrvDomainNumOfSnapshots domainNumOfSnapshots;
++ virDrvDomainListSnapshots domainListSnapshots;
+ };
+
+ typedef int
+Index: libvirt-0.4.6/src/xen_unified.c
+===================================================================
+--- libvirt-0.4.6.orig/src/xen_unified.c
++++ libvirt-0.4.6/src/xen_unified.c
+@@ -869,6 +869,81 @@ xenUnifiedDomainRestore (virConnectPtr c
+ }
+
+ static int
++xenUnifiedDomainSnapshotCreate(virDomainPtr domain, const char* name)
++{
++ GET_PRIVATE(domain->conn);
++ int i;
++
++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
++ if (priv->opened[i] &&
++ drivers[i]->domainSnapshotCreate &&
++ drivers[i]->domainSnapshotCreate(domain, name) == 0)
++ return 0;
++
++ return -1;
++}
++
++static int
++xenUnifiedDomainSnapshotApply(virDomainPtr domain, const char* name)
++{
++ GET_PRIVATE(domain->conn);
++ int i;
++
++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
++ if (priv->opened[i] &&
++ drivers[i]->domainSnapshotApply &&
++ drivers[i]->domainSnapshotApply(domain, name) == 0)
++ return 0;
++
++ return -1;
++}
++
++static int
++xenUnifiedDomainSnapshotDelete(virDomainPtr domain, const char* name)
++{
++ GET_PRIVATE(domain->conn);
++ int i;
++
++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
++ if (priv->opened[i] &&
++ drivers[i]->domainSnapshotDelete &&
++ drivers[i]->domainSnapshotDelete(domain, name) == 0)
++ return 0;
++
++ return -1;
++}
++
++static int
++xenUnifiedDomainNumOfSnapshots(virDomainPtr domain)
++{
++ GET_PRIVATE(domain->conn);
++ int i;
++
++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
++ if (priv->opened[i] &&
++ drivers[i]->domainNumOfSnapshots)
++ return drivers[i]->domainNumOfSnapshots(domain);
++
++ return -1;
++}
++
++static int
++xenUnifiedDomainListSnapshots(virDomainPtr domain, char **const names,
++ int maxnames)
++{
++ GET_PRIVATE(domain->conn);
++ int i;
++
++ for (i = 0; i < XEN_UNIFIED_NR_DRIVERS; ++i)
++ if (priv->opened[i] &&
++ drivers[i]->domainListSnapshots &&
++ drivers[i]->domainListSnapshots(domain, names, maxnames) == 0)
++ return 0;
++
++ return -1;
++}
++
++static int
+ xenUnifiedDomainCoreDump (virDomainPtr dom, const char *to, int flags)
+ {
+ GET_PRIVATE(dom->conn);
+@@ -1336,6 +1411,11 @@ static virDriver xenUnifiedDriver = {
+ .domainGetInfo = xenUnifiedDomainGetInfo,
+ .domainSave = xenUnifiedDomainSave,
+ .domainRestore = xenUnifiedDomainRestore,
++ .domainSnapshotCreate = xenUnifiedDomainSnapshotCreate,
++ .domainSnapshotApply = xenUnifiedDomainSnapshotApply,
++ .domainSnapshotDelete = xenUnifiedDomainSnapshotDelete,
++ .domainNumOfSnapshots = xenUnifiedDomainNumOfSnapshots,
++ .domainListSnapshots = xenUnifiedDomainListSnapshots,
+ .domainCoreDump = xenUnifiedDomainCoreDump,
+ .domainSetVcpus = xenUnifiedDomainSetVcpus,
+ .domainPinVcpu = xenUnifiedDomainPinVcpu,
+Index: libvirt-0.4.6/src/xen_unified.h
+===================================================================
+--- libvirt-0.4.6.orig/src/xen_unified.h
++++ libvirt-0.4.6/src/xen_unified.h
+@@ -63,6 +63,11 @@ struct xenUnifiedDriver {
+ virDrvDomainGetInfo domainGetInfo;
+ virDrvDomainSave domainSave;
+ virDrvDomainRestore domainRestore;
++ virDrvDomainSnapshotCreate domainSnapshotCreate;
++ virDrvDomainSnapshotApply domainSnapshotApply;
++ virDrvDomainSnapshotDelete domainSnapshotDelete;
++ virDrvDomainNumOfSnapshots domainNumOfSnapshots;
++ virDrvDomainListSnapshots domainListSnapshots;
+ virDrvDomainCoreDump domainCoreDump;
+ virDrvDomainSetVcpus domainSetVcpus;
+ virDrvDomainPinVcpu domainPinVcpu;
+Index: libvirt-0.4.6/src/xend_internal.c
+===================================================================
+--- libvirt-0.4.6.orig/src/xend_internal.c
++++ libvirt-0.4.6/src/xend_internal.c
+@@ -51,6 +51,12 @@
+
+ #ifndef PROXY
+
++static int xenDaemonDomainSnapshotCreate(virDomainPtr domain, const char* name);
++static int xenDaemonDomainSnapshotApply(virDomainPtr domain, const char* name);
++static int xenDaemonDomainSnapshotDelete(virDomainPtr domain, const char* name);
++static int xenDaemonDomainNumOfSnapshots(virDomainPtr domain);
++static int xenDaemonDomainListSnapshots(virDomainPtr domain, char **const names, int maxnames);
++
+ /*
+ * The number of Xen scheduler parameters
+ */
+@@ -3070,6 +3076,87 @@ xenDaemonDomainRestore(virConnectPtr con
+ }
+ return xend_op(conn, "", "op", "restore", "file", filename, NULL);
+ }
++
++static int
++xenDaemonDomainSnapshotCreate(virDomainPtr domain, const char* name)
++{
++ if ((domain == NULL) || (name == NULL)) {
++ virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
++ return (-1);
++ }
++ return xend_op(domain->conn, domain->name, "op",
++ "snapshot_create", "name", name, NULL);
++}
++
++static int
++xenDaemonDomainSnapshotApply(virDomainPtr domain, const char* name)
++{
++ if ((domain == NULL) || (name == NULL)) {
++ virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
++ return (-1);
++ }
++ return xend_op(domain->conn, domain->name, "op",
++ "snapshot_apply", "name", name, NULL);
++}
++
++static int
++xenDaemonDomainSnapshotDelete(virDomainPtr domain, const char* name)
++{
++ if ((domain == NULL) || (name == NULL)) {
++ virXendError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
++ return (-1);
++ }
++ return xend_op(domain->conn, domain->name, "op",
++ "snapshot_delete", "name", name, NULL);
++}
++
++static int
++xenDaemonDomainNumOfSnapshots(virDomainPtr domain)
++{
++ struct sexpr *root, *node, *value;
++ int i;
++
++ root = sexpr_get(domain->conn,
++ "/xend/domain/%s?op=snapshot_list", domain->name);
++ if (root == NULL)
++ return -1;
++
++ for (node = root, i = 0; node->kind == SEXPR_CONS; node = node->u.s.cdr) {
++ value = node->u.s.car;
++
++ if (value->kind == SEXPR_VALUE)
++ i++;
++ }
++
++ return i;
++}
++
++static int
++xenDaemonDomainListSnapshots(virDomainPtr domain, char **const names,
++ int maxnames)
++{
++ struct sexpr *root, *node, *value;
++ int i;
++ root = sexpr_get(domain->conn,
++ "/xend/domain/%s?op=snapshot_list", domain->name);
++ if (root == NULL)
++ return -1;
++
++ for (node = root, i = 0; node->kind == SEXPR_CONS; node = node->u.s.cdr) {
++ value = node->u.s.car;
++
++ if (value->kind == SEXPR_VALUE) {
++ names[i] = strdup(value->u.value);
++ if (++i > maxnames)
++ return 0;
++ }
++ }
++
++ for (; i < maxnames; i++)
++ names[i] = NULL;
++
++ return 0;
++}
+ #endif /* !PROXY */
+
+ /**
+@@ -4824,6 +4911,11 @@ struct xenUnifiedDriver xenDaemonDriver
+ xenDaemonDomainGetInfo, /* domainGetInfo */
+ xenDaemonDomainSave, /* domainSave */
+ xenDaemonDomainRestore, /* domainRestore */
++ xenDaemonDomainSnapshotCreate, /* domainSnapshotCreate */
++ xenDaemonDomainSnapshotApply, /* domainSnapshotApply */
++ xenDaemonDomainSnapshotDelete, /* domainSnapshotDelete */
++ xenDaemonDomainNumOfSnapshots, /* domainNumOfSnapshots */
++ xenDaemonDomainListSnapshots, /* domainListSnapshots */
+ xenDaemonDomainCoreDump, /* domainCoreDump */
+ xenDaemonDomainSetVcpus, /* domainSetVcpus */
+ xenDaemonDomainPinVcpu, /* domainPinVcpu */
+Index: libvirt-0.4.6/src/proxy_internal.c
+===================================================================
+--- libvirt-0.4.6.orig/src/proxy_internal.c
++++ libvirt-0.4.6/src/proxy_internal.c
+@@ -66,6 +66,11 @@ struct xenUnifiedDriver xenProxyDriver =
+ xenProxyDomainGetInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
++ NULL, /* domainSnapshotCreate */
++ NULL, /* domainSnapshotApply */
++ NULL, /* domainSnapshotDelete */
++ NULL, /* domainNumOfSnapshots */
++ NULL, /* domainListSnapshots */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+Index: libvirt-0.4.6/src/xen_internal.c
+===================================================================
+--- libvirt-0.4.6.orig/src/xen_internal.c
++++ libvirt-0.4.6/src/xen_internal.c
+@@ -700,6 +700,11 @@ struct xenUnifiedDriver xenHypervisorDri
+ xenHypervisorGetDomainInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
++ NULL, /* domainSnapshotCreate */
++ NULL, /* domainSnapshotApply */
++ NULL, /* domainSnapshotDelete */
++ NULL, /* domainNumOfSnapshots */
++ NULL, /* domainListSnapshots */
+ NULL, /* domainCoreDump */
+ xenHypervisorSetVcpus, /* domainSetVcpus */
+ xenHypervisorPinVcpu, /* domainPinVcpu */
+Index: libvirt-0.4.6/src/xm_internal.c
+===================================================================
+--- libvirt-0.4.6.orig/src/xm_internal.c
++++ libvirt-0.4.6/src/xm_internal.c
+@@ -105,6 +105,11 @@ struct xenUnifiedDriver xenXMDriver = {
+ xenXMDomainGetInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
++ NULL, /* domainSnapshotCreate */
++ NULL, /* domainSnapshotApply */
++ NULL, /* domainSnapshotDelete */
++ NULL, /* domainNumOfSnapshots */
++ NULL, /* domainListSnapshots */
+ NULL, /* domainCoreDump */
+ xenXMDomainSetVcpus, /* domainSetVcpus */
+ xenXMDomainPinVcpu, /* domainPinVcpu */
+Index: libvirt-0.4.6/src/xs_internal.c
+===================================================================
+--- libvirt-0.4.6.orig/src/xs_internal.c
++++ libvirt-0.4.6/src/xs_internal.c
+@@ -66,6 +66,11 @@ struct xenUnifiedDriver xenStoreDriver =
+ xenStoreGetDomainInfo, /* domainGetInfo */
+ NULL, /* domainSave */
+ NULL, /* domainRestore */
++ NULL, /* domainSnapshotCreate */
++ NULL, /* domainSnapshotApply */
++ NULL, /* domainSnapshotDelete */
++ NULL, /* domainNumOfSnapshots */
++ NULL, /* domainListSnapshots */
+ NULL, /* domainCoreDump */
+ NULL, /* domainSetVcpus */
+ NULL, /* domainPinVcpu */
+Index: libvirt-0.4.6/src/virsh.c
+===================================================================
+--- libvirt-0.4.6.orig/src/virsh.c
++++ libvirt-0.4.6/src/virsh.c
+@@ -1100,6 +1100,189 @@ cmdSave(vshControl *ctl, const vshCmd *c
+ return ret;
+ }
+
++
++/*
++ * "snapshot-create" command
++ */
++static vshCmdInfo info_snapshot_create[] = {
++ {"syntax", "snapshot-create "},
++ {"help", gettext_noop("Create a snapshot of the domain")},
++ {"desc", gettext_noop("Create a snapshot of the domain")},
++ {NULL, NULL}
++};
++
++static vshCmdOptDef opts_snapshot_create[] = {
++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")},
++ {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")},
++ {NULL, 0, 0, NULL}
++};
++
++static int
++cmdSnapshotCreate(vshControl * ctl, vshCmd * cmd)
++{
++ virDomainPtr dom;
++ char *name;
++ char *domain;
++ int ret = TRUE;
++
++ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
++ return FALSE;
++
++ if (!(name = vshCommandOptString(cmd, "name", NULL)))
++ return FALSE;
++
++ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &domain)))
++ return FALSE;
++
++ if (virDomainSnapshotCreate(dom, name) == 0) {
++ vshPrint(ctl, _("Snapshot %s created for domain %s\n"), name, domain);
++ } else {
++ vshError(ctl, FALSE, _("Failed to create snapshot %s for domain %s"),
++ name, domain);
++ ret = FALSE;
++ }
++
++ virDomainFree(dom);
++ return ret;
++}
++
++/*
++ * "snapshot-apply" command
++ */
++static vshCmdInfo info_snapshot_apply[] = {
++ {"syntax", "snapshot-apply "},
++ {"help", gettext_noop("Start the domain using a snapshot")},
++ {"desc", gettext_noop("Start the domain using a snapshot")},
++ {NULL, NULL}
++};
++
++static vshCmdOptDef opts_snapshot_apply[] = {
++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")},
++ {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")},
++ {NULL, 0, 0, NULL}
++};
++
++static int
++cmdSnapshotApply(vshControl * ctl, vshCmd * cmd)
++{
++ virDomainPtr dom;
++ char *name;
++ char *domain;
++ int ret = TRUE;
++
++ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
++ return FALSE;
++
++ if (!(name = vshCommandOptString(cmd, "name", NULL)))
++ return FALSE;
++
++ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &domain)))
++ return FALSE;
++
++ if (virDomainSnapshotApply(dom, name) == 0) {
++ vshPrint(ctl, _("Domain %s started using snapshot %s\n"),
++ domain, name);
++ } else {
++ vshError(ctl, FALSE, _("Failed to start domain %s using snapshot %s"),
++ domain, name);
++ ret = FALSE;
++ }
++
++ virDomainFree(dom);
++ return ret;
++}
++
++/*
++ * "snapshot-delete" command
++ */
++static vshCmdInfo info_snapshot_delete[] = {
++ {"syntax", "snapshot-delete "},
++ {"help", gettext_noop("Delete a snapshot from a domain")},
++ {"desc", gettext_noop("Delete a snapshot from a domain")},
++ {NULL, NULL}
++};
++
++static vshCmdOptDef opts_snapshot_delete[] = {
++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")},
++ {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Name of the snapshot")},
++ {NULL, 0, 0, NULL}
++};
++
++static int
++cmdSnapshotDelete(vshControl * ctl, vshCmd * cmd)
++{
++ virDomainPtr dom;
++ char *name;
++ char *domain;
++ int ret = TRUE;
++
++ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
++ return FALSE;
++
++ if (!(name = vshCommandOptString(cmd, "name", NULL)))
++ return FALSE;
++
++ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &domain)))
++ return FALSE;
++
++ if (virDomainSnapshotDelete(dom, name) == 0) {
++ vshPrint(ctl, _("Snapshot %s deleted from domain %s\n"), name, domain);
++ } else {
++ vshError(ctl, FALSE, _("Failed to delete snapshot %s from domain %s"),
++ name, domain);
++ ret = FALSE;
++ }
++
++ virDomainFree(dom);
++ return ret;
++}
++
++/*
++ * "snapshot-list" command
++ */
++static vshCmdInfo info_snapshot_list[] = {
++ {"syntax", "snapshot-list "},
++ {"help", gettext_noop("List all snapshots of a domain")},
++ {"desc", gettext_noop("List all snapshots of a domain")},
++ {NULL, NULL}
++};
++
++static vshCmdOptDef opts_snapshot_list[] = {
++ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("Domain name, id or uuid")},
++ {NULL, 0, 0, NULL}
++};
++
++static int
++cmdSnapshotList(vshControl * ctl, vshCmd * cmd)
++{
++ virDomainPtr dom;
++ char *domain;
++ char** names;
++ int num;
++ int i;
++ int ret = TRUE;
++
++ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
++ return FALSE;
++
++ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &domain)))
++ return FALSE;
++
++ // TODO Display snapshot details
++ num = virDomainNumOfSnapshots(dom);
++ names = malloc(num * sizeof(*names));
++ virDomainListSnapshots(dom, names, num);
++
++ for (i = 0; i < num; i++) {
++ printf("%s\n", names[i]);
++ free(names[i]);
++ }
++
++ free(names);
++ virDomainFree(dom);
++ return ret;
++}
++
+ /*
+ * "schedinfo" command
+ */
+@@ -5568,6 +5751,12 @@ static const vshCmdDef commands[] = {
+ {"undefine", cmdUndefine, opts_undefine, info_undefine},
+ {"uri", cmdURI, NULL, info_uri},
+
++ {"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create},
++ {"snapshot-apply", cmdSnapshotApply, opts_snapshot_apply, info_snapshot_apply},
++ {"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, info_snapshot_delete},
++ {"snapshot-list", cmdSnapshotList, opts_snapshot_list, info_snapshot_list},
++
++
+ {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create},
+ {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as},
+ {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete},
+Index: libvirt-0.4.6/src/lxc_driver.c
+===================================================================
+--- libvirt-0.4.6.orig/src/lxc_driver.c
++++ libvirt-0.4.6/src/lxc_driver.c
+@@ -1203,6 +1203,11 @@ static virDriver lxcDriver = {
+ NULL, /* domainMemoryPeek */
+ NULL, /* nodeGetCellsFreeMemory */
+ NULL, /* getFreeMemory */
++ NULL, /* domainSnapshotCreate */
++ NULL, /* domainSnapshotApply */
++ NULL, /* domainSnapshotDelete */
++ NULL, /* domainNumOfSnapshots */
++ NULL, /* domainListSnapshots */
+ };
+
+
+Index: libvirt-0.4.6/src/openvz_driver.c
+===================================================================
+--- libvirt-0.4.6.orig/src/openvz_driver.c
++++ libvirt-0.4.6/src/openvz_driver.c
+@@ -1014,6 +1014,11 @@ static virDriver openvzDriver = {
+ NULL, /* domainMemoryPeek */
+ NULL, /* nodeGetCellsFreeMemory */
+ NULL, /* nodeGetFreeMemory */
++ NULL, /* domainSnapshotCreate */
++ NULL, /* domainSnapshotApply */
++ NULL, /* domainSnapshotDelete */
++ NULL, /* domainNumOfSnapshots */
++ NULL, /* domainListSnapshots */
+ };
+
+ int openvzRegister(void) {
+Index: libvirt-0.4.6/src/qemu_driver.c
+===================================================================
+--- libvirt-0.4.6.orig/src/qemu_driver.c
++++ libvirt-0.4.6/src/qemu_driver.c
+@@ -4079,6 +4079,11 @@ static virDriver qemuDriver = {
+ NULL, /* nodeGetCellsFreeMemory */
+ NULL, /* getFreeMemory */
+ #endif
++ NULL, /* domainSnapshotCreate */
++ NULL, /* domainSnapshotApply */
++ NULL, /* domainSnapshotDelete */
++ NULL, /* domainNumOfSnapshots */
++ NULL, /* domainListSnapshots */
+ };
+
+ static virNetworkDriver qemuNetworkDriver = {
+Index: libvirt-0.4.6/src/remote_internal.c
+===================================================================
+--- libvirt-0.4.6.orig/src/remote_internal.c
++++ libvirt-0.4.6/src/remote_internal.c
+@@ -4888,6 +4888,11 @@ static virDriver driver = {
+ .domainMemoryPeek = remoteDomainMemoryPeek,
+ .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory,
+ .getFreeMemory = remoteNodeGetFreeMemory,
++ .domainSnapshotCreate = NULL,
++ .domainSnapshotApply = NULL,
++ .domainSnapshotDelete = NULL,
++ .domainNumOfSnapshots = NULL,
++ .domainListSnapshots = NULL,
+ };
+
+ static virNetworkDriver network_driver = {
+Index: libvirt-0.4.6/src/test.c
+===================================================================
+--- libvirt-0.4.6.orig/src/test.c
++++ libvirt-0.4.6/src/test.c
+@@ -1595,6 +1595,11 @@ static virDriver testDriver = {
+ NULL, /* domainMemoryPeek */
+ testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
+ NULL, /* getFreeMemory */
++ NULL, /* domainSnapshotCreate */
++ NULL, /* domainSnapshotApply */
++ NULL, /* domainSnapshotDelete */
++ NULL, /* domainNumOfSnapshots */
++ NULL, /* domainListSnapshots */
+ };
+
+ static virNetworkDriver testNetworkDriver = {
+Index: libvirt-0.4.6/src/libvirt_sym.version
+===================================================================
+--- libvirt-0.4.6.orig/src/libvirt_sym.version
++++ libvirt-0.4.6/src/libvirt_sym.version
+@@ -35,6 +35,11 @@
+ virDomainRestore;
+ virDomainResume;
+ virDomainSave;
++ virDomainSnapshotCreate;
++ virDomainSnapshotApply;
++ virDomainSnapshotDelete;
++ virDomainNumOfSnapshots;
++ virDomainListSnapshots;
+ virDomainCoreDump;
+ virDomainSetMemory;
+ virDomainSetMaxMemory;
+Index: libvirt-0.4.6/docs/libvirt-api.xml
+===================================================================
+--- libvirt-0.4.6.orig/docs/libvirt-api.xml
++++ libvirt-0.4.6/docs/libvirt-api.xml
+@@ -143,6 +143,11 @@
+
+
+
++
++
++
++
++
+
+
+
+@@ -1096,6 +1101,36 @@ see note above'/>
+
+
+
++
++ Start a shut off domain based on a previously taken snapshot
++
++
++
++
++
++ Create a snapshot from a running domain
++
++
++
++
++
++ Delete a snapshot from a domain
++
++
++
++
++
++ Returns the number of snapshot a given domain has
++
++
++
++
++ Returns the names of the snapshots of a domain
++
++
++
++
++
+
+ Undefine a domain but does not stop it if it is running
+
+Index: libvirt-0.4.6/python/libvirt-py.c
+===================================================================
+--- libvirt-0.4.6.orig/python/libvirt-py.c
++++ libvirt-0.4.6/python/libvirt-py.c
+@@ -25,6 +25,25 @@ LIBVIRT_END_ALLOW_THREADS;
+ }
+
+ PyObject *
++libvirt_virDomainSnapshotDelete(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
++ PyObject *py_retval;
++ int c_retval;
++ virDomainPtr domain;
++ PyObject *pyobj_domain;
++ char * name;
++
++ if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotDelete", &pyobj_domain, &name))
++ return(NULL);
++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
++LIBVIRT_BEGIN_ALLOW_THREADS;
++
++ c_retval = virDomainSnapshotDelete(domain, name);
++LIBVIRT_END_ALLOW_THREADS;
++ py_retval = libvirt_intWrap((int) c_retval);
++ return(py_retval);
++}
++
++PyObject *
+ libvirt_virStorageVolGetKey(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ const char * c_retval;
+@@ -520,24 +539,6 @@ LIBVIRT_END_ALLOW_THREADS;
+ }
+
+ PyObject *
+-libvirt_virNetworkGetName(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+- PyObject *py_retval;
+- const char * c_retval;
+- virNetworkPtr network;
+- PyObject *pyobj_network;
+-
+- if (!PyArg_ParseTuple(args, (char *)"O:virNetworkGetName", &pyobj_network))
+- return(NULL);
+- network = (virNetworkPtr) PyvirNetwork_Get(pyobj_network);
+-LIBVIRT_BEGIN_ALLOW_THREADS;
+-
+- c_retval = virNetworkGetName(network);
+-LIBVIRT_END_ALLOW_THREADS;
+- py_retval = libvirt_charPtrConstWrap((const char *) c_retval);
+- return(py_retval);
+-}
+-
+-PyObject *
+ libvirt_virNetworkDestroy(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ int c_retval;
+@@ -771,6 +772,25 @@ LIBVIRT_END_ALLOW_THREADS;
+ }
+
+ PyObject *
++libvirt_virDomainSnapshotCreate(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
++ PyObject *py_retval;
++ int c_retval;
++ virDomainPtr domain;
++ PyObject *pyobj_domain;
++ char * name;
++
++ if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotCreate", &pyobj_domain, &name))
++ return(NULL);
++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
++LIBVIRT_BEGIN_ALLOW_THREADS;
++
++ c_retval = virDomainSnapshotCreate(domain, name);
++LIBVIRT_END_ALLOW_THREADS;
++ py_retval = libvirt_intWrap((int) c_retval);
++ return(py_retval);
++}
++
++PyObject *
+ libvirt_virNetworkDefineXML(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ virNetworkPtr c_retval;
+@@ -806,6 +826,24 @@ LIBVIRT_END_ALLOW_THREADS;
+ }
+
+ PyObject *
++libvirt_virDomainNumOfSnapshots(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
++ PyObject *py_retval;
++ int c_retval;
++ virDomainPtr domain;
++ PyObject *pyobj_domain;
++
++ if (!PyArg_ParseTuple(args, (char *)"O:virDomainNumOfSnapshots", &pyobj_domain))
++ return(NULL);
++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
++LIBVIRT_BEGIN_ALLOW_THREADS;
++
++ c_retval = virDomainNumOfSnapshots(domain);
++LIBVIRT_END_ALLOW_THREADS;
++ py_retval = libvirt_intWrap((int) c_retval);
++ return(py_retval);
++}
++
++PyObject *
+ libvirt_virDomainResume(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ int c_retval;
+@@ -824,6 +862,25 @@ LIBVIRT_END_ALLOW_THREADS;
+ }
+
+ PyObject *
++libvirt_virDomainSnapshotApply(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
++ PyObject *py_retval;
++ int c_retval;
++ virDomainPtr domain;
++ PyObject *pyobj_domain;
++ char * name;
++
++ if (!PyArg_ParseTuple(args, (char *)"Oz:virDomainSnapshotApply", &pyobj_domain, &name))
++ return(NULL);
++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
++LIBVIRT_BEGIN_ALLOW_THREADS;
++
++ c_retval = virDomainSnapshotApply(domain, name);
++LIBVIRT_END_ALLOW_THREADS;
++ py_retval = libvirt_intWrap((int) c_retval);
++ return(py_retval);
++}
++
++PyObject *
+ libvirt_virConnectGetHostname(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ char * c_retval;
+@@ -897,6 +954,24 @@ LIBVIRT_END_ALLOW_THREADS;
+ }
+
+ PyObject *
++libvirt_virNetworkGetName(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
++ PyObject *py_retval;
++ const char * c_retval;
++ virNetworkPtr network;
++ PyObject *pyobj_network;
++
++ if (!PyArg_ParseTuple(args, (char *)"O:virNetworkGetName", &pyobj_network))
++ return(NULL);
++ network = (virNetworkPtr) PyvirNetwork_Get(pyobj_network);
++LIBVIRT_BEGIN_ALLOW_THREADS;
++
++ c_retval = virNetworkGetName(network);
++LIBVIRT_END_ALLOW_THREADS;
++ py_retval = libvirt_charPtrConstWrap((const char *) c_retval);
++ return(py_retval);
++}
++
++PyObject *
+ libvirt_virConnectGetCapabilities(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
+ PyObject *py_retval;
+ char * c_retval;
+Index: libvirt-0.4.6/python/libvirt-py.h
+===================================================================
+--- libvirt-0.4.6.orig/python/libvirt-py.h
++++ libvirt-0.4.6/python/libvirt-py.h
+@@ -1,6 +1,7 @@
+ /* Generated */
+
+ PyObject * libvirt_virStoragePoolGetXMLDesc(PyObject *self, PyObject *args);
++PyObject * libvirt_virDomainSnapshotDelete(PyObject *self, PyObject *args);
+ PyObject * libvirt_virStorageVolGetKey(PyObject *self, PyObject *args);
+ PyObject * libvirt_virConnectClose(PyObject *self, PyObject *args);
+ PyObject * libvirt_virDomainDefineXML(PyObject *self, PyObject *args);
+@@ -28,7 +29,6 @@ PyObject * libvirt_virConnectNumOfNetwor
+ PyObject * libvirt_virStorageVolGetName(PyObject *self, PyObject *args);
+ PyObject * libvirt_virStoragePoolLookupByUUIDString(PyObject *self, PyObject *args);
+ PyObject * libvirt_virDomainGetXMLDesc(PyObject *self, PyObject *args);
+-PyObject * libvirt_virNetworkGetName(PyObject *self, PyObject *args);
+ PyObject * libvirt_virNetworkDestroy(PyObject *self, PyObject *args);
+ PyObject * libvirt_virStoragePoolLookupByName(PyObject *self, PyObject *args);
+ PyObject * libvirt_virNetworkGetBridgeName(PyObject *self, PyObject *args);
+@@ -42,13 +42,17 @@ PyObject * libvirt_virNetworkSetAutostar
+ PyObject * libvirt_virDomainGetMaxMemory(PyObject *self, PyObject *args);
+ PyObject * libvirt_virResetLastError(PyObject *self, PyObject *args);
+ PyObject * libvirt_virStoragePoolFree(PyObject *self, PyObject *args);
++PyObject * libvirt_virDomainSnapshotCreate(PyObject *self, PyObject *args);
+ PyObject * libvirt_virNetworkDefineXML(PyObject *self, PyObject *args);
+ PyObject * libvirt_virConnResetLastError(PyObject *self, PyObject *args);
++PyObject * libvirt_virDomainNumOfSnapshots(PyObject *self, PyObject *args);
+ PyObject * libvirt_virDomainResume(PyObject *self, PyObject *args);
++PyObject * libvirt_virDomainSnapshotApply(PyObject *self, PyObject *args);
+ PyObject * libvirt_virConnectGetHostname(PyObject *self, PyObject *args);
+ PyObject * libvirt_virDomainGetName(PyObject *self, PyObject *args);
+ PyObject * libvirt_virNetworkGetXMLDesc(PyObject *self, PyObject *args);
+ PyObject * libvirt_virConnectNumOfStoragePools(PyObject *self, PyObject *args);
++PyObject * libvirt_virNetworkGetName(PyObject *self, PyObject *args);
+ PyObject * libvirt_virConnectGetCapabilities(PyObject *self, PyObject *args);
+ PyObject * libvirt_virDomainLookupByName(PyObject *self, PyObject *args);
+ PyObject * libvirt_virConnectFindStoragePoolSources(PyObject *self, PyObject *args);
+Index: libvirt-0.4.6/python/libvirt.py
+===================================================================
+--- libvirt-0.4.6.orig/python/libvirt.py
++++ libvirt-0.4.6/python/libvirt.py
+@@ -359,6 +359,12 @@ class virDomain:
+ ret = libvirtmod.virDomainGetName(self._o)
+ return ret
+
++ def numOfSnapshots(self):
++ """Returns the number of snapshot a given domain has """
++ ret = libvirtmod.virDomainNumOfSnapshots(self._o)
++ if ret == -1: raise libvirtError ('virDomainNumOfSnapshots() failed', dom=self)
++ return ret
++
+ def reboot(self, flags):
+ """Reboot a domain, the domain object is still usable there
+ after but the domain OS is being stopped for a restart.
+@@ -433,6 +439,24 @@ class virDomain:
+ if ret == -1: raise libvirtError ('virDomainShutdown() failed', dom=self)
+ return ret
+
++ def snapshotApply(self, name):
++ """Start a shut off domain based on a previously taken snapshot """
++ ret = libvirtmod.virDomainSnapshotApply(self._o, name)
++ if ret == -1: raise libvirtError ('virDomainSnapshotApply() failed', dom=self)
++ return ret
++
++ def snapshotCreate(self, name):
++ """Create a snapshot from a running domain """
++ ret = libvirtmod.virDomainSnapshotCreate(self._o, name)
++ if ret == -1: raise libvirtError ('virDomainSnapshotCreate() failed', dom=self)
++ return ret
++
++ def snapshotDelete(self, name):
++ """Delete a snapshot from a domain """
++ ret = libvirtmod.virDomainSnapshotDelete(self._o, name)
++ if ret == -1: raise libvirtError ('virDomainSnapshotDelete() failed', dom=self)
++ return ret
++
+ def suspend(self):
+ """Suspends an active domain, the process is frozen without
+ further access to CPU resources and I/O but the memory used
+@@ -489,6 +513,12 @@ class virDomain:
+ ret = libvirtmod.virDomainInterfaceStats(self._o, path)
+ return ret
+
++ def listSnapshots(self):
++ """Returns the names of the snapshots of a domain """
++ ret = libvirtmod.virDomainListSnapshots(self._o)
++ if ret is None: raise libvirtError ('virDomainListSnapshots() failed', dom=self)
++ return ret
++
+ def pinVcpu(self, vcpu, cpumap):
+ """Dynamically change the real CPUs which can be allocated to
+ a virtual CPU. This function requires privileged access to
+Index: libvirt-0.4.6/python/libvir.c
+===================================================================
+--- libvirt-0.4.6.orig/python/libvir.c
++++ libvirt-0.4.6/python/libvir.c
+@@ -1466,6 +1466,35 @@ libvirt_virStoragePoolLookupByUUID(PyObj
+ return(py_retval);
+ }
+
++static PyObject *
++libvirt_virDomainListSnapshots(PyObject *self ATTRIBUTE_UNUSED, PyObject *args) {
++ PyObject *py_retval;
++ int i, num;
++ char** names;
++ virDomainPtr domain;
++ PyObject *pyobj_domain;
++
++ if (!PyArg_ParseTuple(args, (char *)"O:virDomainListSnapshots",
++ &pyobj_domain))
++ return(NULL);
++ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
++
++LIBVIRT_BEGIN_ALLOW_THREADS;
++ num = virDomainNumOfSnapshots(domain);
++ names = malloc(num * sizeof(*names));
++ virDomainListSnapshots(domain, names, num);
++LIBVIRT_END_ALLOW_THREADS;
++
++ py_retval = PyList_New(num);
++ for (i = 0; i < num; i++) {
++ PyList_SetItem(py_retval, i, Py_BuildValue("s", names[i]));
++ free(names[i]);
++ }
++ free(names);
++
++ return(py_retval);
++}
++
+
+
+ /************************************************************************
+@@ -1502,6 +1531,7 @@ static PyMethodDef libvirtMethods[] = {
+ {(char *) "virDomainSetSchedulerParameters", libvirt_virDomainSetSchedulerParameters, METH_VARARGS, NULL},
+ {(char *) "virDomainGetVcpus", libvirt_virDomainGetVcpus, METH_VARARGS, NULL},
+ {(char *) "virDomainPinVcpu", libvirt_virDomainPinVcpu, METH_VARARGS, NULL},
++ {(char *) "virDomainListSnapshots", libvirt_virDomainListSnapshots, METH_VARARGS, NULL},
+ {(char *) "virConnectListStoragePools", libvirt_virConnectListStoragePools, METH_VARARGS, NULL},
+ {(char *) "virConnectListDefinedStoragePools", libvirt_virConnectListDefinedStoragePools, METH_VARARGS, NULL},
+ {(char *) "virStoragePoolGetAutostart", libvirt_virStoragePoolGetAutostart, METH_VARARGS, NULL},
+Index: libvirt-0.4.6/python/libvirt-python-api.xml
+===================================================================
+--- libvirt-0.4.6.orig/python/libvirt-python-api.xml
++++ libvirt-0.4.6/python/libvirt-python-api.xml
+@@ -135,6 +135,11 @@
+
+
+
++
++ Returns the names of the snapshots of a domain
++
++
++
+
+ list the storage pools, stores the pointers to the names in @names
+
+Index: libvirt-0.4.6/python/generator.py
+===================================================================
+--- libvirt-0.4.6.orig/python/generator.py
++++ libvirt-0.4.6/python/generator.py
+@@ -306,6 +306,7 @@ skip_impl = (
+ 'virDomainSetSchedulerParameters',
+ 'virDomainGetVcpus',
+ 'virDomainPinVcpu',
++ 'virDomainListSnapshots',
+ 'virStoragePoolGetUUID',
+ 'virStoragePoolGetUUIDString',
+ 'virStoragePoolLookupByUUID',
diff --git a/socat.patch b/socat.patch
index 6c01965..0d19d61 100644
--- a/socat.patch
+++ b/socat.patch
@@ -1,8 +1,8 @@
-Index: libvirt-0.4.4/src/remote_internal.c
+Index: libvirt-0.4.5/src/remote_internal.c
===================================================================
---- libvirt-0.4.4.orig/src/remote_internal.c
-+++ libvirt-0.4.4/src/remote_internal.c
-@@ -660,9 +660,22 @@ doRemoteOpen (virConnectPtr conn,
+--- libvirt-0.4.5.orig/src/remote_internal.c
++++ libvirt-0.4.5/src/remote_internal.c
+@@ -623,9 +623,22 @@ doRemoteOpen (virConnectPtr conn,
cmd_argv[j++] = strdup ("none");
}
cmd_argv[j++] = strdup (priv->hostname);
@@ -27,4 +27,4 @@ Index: libvirt-0.4.4/src/remote_internal.c
+ }
cmd_argv[j++] = 0;
assert (j == nr_args);
- for (j = 0; j < (nr_args-1); j++) {
+ for (j = 0; j < (nr_args-1); j++)
diff --git a/vif-parsing.patch b/vif-parsing.patch
new file mode 100644
index 0000000..a392340
--- /dev/null
+++ b/vif-parsing.patch
@@ -0,0 +1,13 @@
+Index: libvirt-0.4.6/src/xend_internal.c
+===================================================================
+--- libvirt-0.4.6.orig/src/xend_internal.c
++++ libvirt-0.4.6/src/xend_internal.c
+@@ -1890,6 +1890,8 @@ xenDaemonParseSxprNets(virConnectPtr con
+ prev->next = net;
+ else
+ def->nets = net;
++
++ prev = net;
+ vif_index++;
+ }
+ }
diff --git a/xen-maxmem.patch b/xen-maxmem.patch
new file mode 100644
index 0000000..cb9244e
--- /dev/null
+++ b/xen-maxmem.patch
@@ -0,0 +1,13 @@
+Index: libvirt-0.4.6/src/xen_internal.c
+===================================================================
+--- libvirt-0.4.6.orig/src/xen_internal.c
++++ libvirt-0.4.6/src/xen_internal.c
+@@ -695,7 +695,7 @@ struct xenUnifiedDriver xenHypervisorDri
+ xenHypervisorDestroyDomain, /* domainDestroy */
+ xenHypervisorDomainGetOSType, /* domainGetOSType */
+ xenHypervisorGetMaxMemory, /* domainGetMaxMemory */
+- xenHypervisorSetMaxMemory, /* domainSetMaxMemory */
++ NULL, /* domainSetMaxMemory */
+ NULL, /* domainSetMemory */
+ xenHypervisorGetDomainInfo, /* domainGetInfo */
+ NULL, /* domainSave */