[libvirt] QEMU/KVM snapshots, and rudimentary API extension

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

 



I was starting to use libvirt on a project, and realized that there was nothing in the API for snapshots. As I need to be able to take snapshots without taking down the machine (that and KVM's restore function didn't seem to be working terribly well), I added a few functions so that I could take snapshots, and I also added a screenshot function so I could give users a view of their snapshots in my application. At this point, as I only really use KVM/QEMU, that is the only hypervisor I implemented it for, and I'm sure there will be some problems with my structure in the other drivers. However, I figured I should at least submit the patch, even if it turns out to be of no use to anyone :)

At this point for the QEMU driver, it only does snapshots for qcow2 drives, and will report an error if qemu says that no valid drives were found, or if for restoring/deleting the specified snapshot wasn't found.

Philip Jameson

diff --git a/build-aux/.gitignore b/build-aux/.gitignore
index a1b5d3b..2a6c414 100644
--- a/build-aux/.gitignore
+++ b/build-aux/.gitignore
@@ -1,3 +1,8 @@
 *
 /link-warning.h
 /mktempd
+/arg-nonnull.h
+/config.rpath
+/gitlog-to-changelog
+/useless-if-before-free
+/vc-list-files
diff --git a/daemon/remote.c b/daemon/remote.c
index 0b30131..3ade7ab 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -5304,6 +5304,129 @@ remoteDispatchCpuCompare(struct qemud_server *server ATTRIBUTE_UNUSED,
 }
 
 
+static int
+remoteDispatchDomainTakeSnapshot (struct qemud_server *server ATTRIBUTE_UNUSED,
+                          struct qemud_client *client ATTRIBUTE_UNUSED,
+                          virConnectPtr conn,
+                          remote_message_header *hdr ATTRIBUTE_UNUSED,
+                          remote_error *rerr,
+                          remote_domain_take_snapshot_args *args,
+			  void *ret ATTRIBUTE_UNUSED)
+{
+    virDomainPtr dom;
+    dom = get_nonnull_domain (conn, args->dom);
+    if (dom == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    if (virDomainTakeSnapshot (dom, args->name) == -1) {
+        virDomainFree(dom);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    virDomainFree(dom);
+    return 0;
+}
+
+static int
+remoteDispatchDomainRestoreSnapshot (struct qemud_server *server ATTRIBUTE_UNUSED,
+                          struct qemud_client *client ATTRIBUTE_UNUSED,
+                          virConnectPtr conn,
+                          remote_message_header *hdr ATTRIBUTE_UNUSED,
+                          remote_error *rerr,
+                          remote_domain_restore_snapshot_args *args,
+			  void *ret ATTRIBUTE_UNUSED)
+{
+    virDomainPtr dom;
+    dom = get_nonnull_domain (conn, args->dom);
+    if (dom == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    if (virDomainRestoreSnapshot (dom, args->name) == -1) {
+        virDomainFree(dom);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    virDomainFree(dom);
+    return 0;
+}
+
+static int
+remoteDispatchDomainDeleteSnapshot (struct qemud_server *server ATTRIBUTE_UNUSED,
+                          struct qemud_client *client ATTRIBUTE_UNUSED,
+                          virConnectPtr conn,
+                          remote_message_header *hdr ATTRIBUTE_UNUSED,
+                          remote_error *rerr,
+                          remote_domain_delete_snapshot_args *args,
+			  void *ret ATTRIBUTE_UNUSED)
+{
+    virDomainPtr dom;
+    dom = get_nonnull_domain (conn, args->dom);
+    if (dom == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    if (virDomainDeleteSnapshot (dom, args->name) == -1) {
+        virDomainFree(dom);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    virDomainFree(dom);
+    return 0;
+}
+
+static int
+remoteDispatchDomainListSnapshots (struct qemud_server *server ATTRIBUTE_UNUSED,
+                          struct qemud_client *client ATTRIBUTE_UNUSED,
+                          virConnectPtr conn,
+                          remote_message_header *hdr ATTRIBUTE_UNUSED,
+                          remote_error *rerr,
+                          remote_domain_list_snapshots_args *args,
+                          remote_domain_list_snapshots_ret *ret)
+{
+    virDomainPtr dom;
+    dom = get_nonnull_domain (conn, args->dom);
+    if (dom == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+
+    //Need to reallocate the new array before putting it to use, and passing it back
+    ret->sslist = calloc(args->listsize,sizeof(char*));
+    if ((ret->numsnapshots = virDomainListSnapshots (dom, ret->sslist,args->listsize)) == -1) {
+        virDomainFree(dom);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    virDomainFree(dom);
+    return 0;
+}
+
+static int
+remoteDispatchDomainTakeScreenshot (struct qemud_server *server ATTRIBUTE_UNUSED,
+                          struct qemud_client *client ATTRIBUTE_UNUSED,
+                          virConnectPtr conn,
+                          remote_message_header *hdr ATTRIBUTE_UNUSED,
+                          remote_error *rerr,
+                          remote_domain_take_screenshot_args *args,
+			  void *ret ATTRIBUTE_UNUSED)
+{
+    virDomainPtr dom;
+    dom = get_nonnull_domain (conn, args->dom);
+    if (dom == NULL) {
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    if (virDomainTakeScreenshot (dom, args->path) == -1) {
+        virDomainFree(dom);
+        remoteDispatchConnError(rerr, conn);
+        return -1;
+    }
+    virDomainFree(dom);
+    return 0;
+}
+
 /*----- Helpers. -----*/
 
 /* get_nonnull_domain and get_nonnull_network turn an on-wire
diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h
index c1801d0..2ca54cf 100644
--- a/daemon/remote_dispatch_args.h
+++ b/daemon/remote_dispatch_args.h
@@ -135,3 +135,8 @@
     remote_interface_is_active_args val_remote_interface_is_active_args;
     remote_cpu_compare_args val_remote_cpu_compare_args;
     remote_domain_memory_stats_args val_remote_domain_memory_stats_args;
+    remote_domain_take_snapshot_args val_remote_domain_take_snapshot_args;
+    remote_domain_restore_snapshot_args val_remote_domain_restore_snapshot_args;
+    remote_domain_delete_snapshot_args val_remote_domain_delete_snapshot_args;
+    remote_domain_list_snapshots_args val_remote_domain_list_snapshots_args;
+    remote_domain_take_screenshot_args val_remote_domain_take_screenshot_args;
diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h
index 1a0f8d8..4ae23dc 100644
--- a/daemon/remote_dispatch_prototypes.h
+++ b/daemon/remote_dispatch_prototypes.h
@@ -434,6 +434,46 @@ static int remoteDispatchDomainSuspend(
     remote_error *err,
     remote_domain_suspend_args *args,
     void *ret);
+static int remoteDispatchDomainTakeSnapshot(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_take_snapshot_args *args,
+    void *ret); 
+static int remoteDispatchDomainRestoreSnapshot(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_restore_snapshot_args *args,
+    void *ret); 
+static int remoteDispatchDomainDeleteSnapshot(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_delete_snapshot_args *args,
+    void *ret); 
+static int remoteDispatchDomainListSnapshots(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_list_snapshots_args *args,
+    remote_domain_list_snapshots_ret *ret); 
+static int remoteDispatchDomainTakeScreenshot(
+    struct qemud_server *server,
+    struct qemud_client *client,
+    virConnectPtr conn,
+    remote_message_header *hdr,
+    remote_error *err,
+    remote_domain_take_screenshot_args *args,
+    void *ret); 
 static int remoteDispatchDomainUndefine(
     struct qemud_server *server,
     struct qemud_client *client,
diff --git a/daemon/remote_dispatch_ret.h b/daemon/remote_dispatch_ret.h
index d7811de..f12f7b4 100644
--- a/daemon/remote_dispatch_ret.h
+++ b/daemon/remote_dispatch_ret.h
@@ -117,3 +117,4 @@
     remote_get_lib_version_ret val_remote_get_lib_version_ret;
     remote_cpu_compare_ret val_remote_cpu_compare_ret;
     remote_domain_memory_stats_ret val_remote_domain_memory_stats_ret;
+    remote_domain_list_snapshots_ret val_remote_domain_list_snapshots_ret;
diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h
index 09ebeee..a535120 100644
--- a/daemon/remote_dispatch_table.h
+++ b/daemon/remote_dispatch_table.h
@@ -802,3 +802,28 @@
     .args_filter = (xdrproc_t) xdr_remote_domain_memory_stats_args,
     .ret_filter = (xdrproc_t) xdr_remote_domain_memory_stats_ret,
 },
+{   /* DomainTakeSnapshot => 160 */
+    .fn = (dispatch_fn) remoteDispatchDomainTakeSnapshot,
+    .args_filter = (xdrproc_t) xdr_remote_domain_take_snapshot_args,
+    .ret_filter = (xdrproc_t) xdr_void,
+},
+{   /* DomainRestoreSnapshot => 161 */
+    .fn = (dispatch_fn) remoteDispatchDomainRestoreSnapshot,
+    .args_filter = (xdrproc_t) xdr_remote_domain_restore_snapshot_args,
+    .ret_filter = (xdrproc_t) xdr_void,
+},
+{   /* DomainDeleteSnapshot => 162 */
+    .fn = (dispatch_fn) remoteDispatchDomainDeleteSnapshot,
+    .args_filter = (xdrproc_t) xdr_remote_domain_delete_snapshot_args,
+    .ret_filter = (xdrproc_t) xdr_void,
+},
+{   /* DomainListSnapshots => 163 */
+    .fn = (dispatch_fn) remoteDispatchDomainListSnapshots,
+    .args_filter = (xdrproc_t) xdr_remote_domain_list_snapshots_args,
+    .ret_filter = (xdrproc_t) xdr_remote_domain_list_snapshots_ret,
+},
+{   /* DomainTakeScreenshot => 164 */
+    .fn = (dispatch_fn) remoteDispatchDomainTakeScreenshot,
+    .args_filter = (xdrproc_t) xdr_remote_domain_take_screenshot_args,
+    .ret_filter = (xdrproc_t) xdr_void,
+},
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index f192fb1..7f9423f 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -620,6 +620,17 @@ int                     virDomainSave           (virDomainPtr domain,
 int                     virDomainRestore        (virConnectPtr conn,
                                                  const char *from);
 
+int			virDomainTakeSnapshot	(virDomainPtr domain,
+						 const char *name);
+int			virDomainRestoreSnapshot(virDomainPtr domain,
+						 const char *name);
+int			virDomainDeleteSnapshot	(virDomainPtr domain,
+						 const char *name);
+int			virDomainListSnapshots	(virDomainPtr domain,
+						 char** sslist, int listsize);
+int			virDomainTakeScreenshot	(virDomainPtr domain,
+						 const char *path);
+
 /*
  * Domain core dump
  */
diff --git a/src/driver.h b/src/driver.h
index c7e4fbf..bab1f2c 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -360,6 +360,22 @@ typedef int
                         const char *cpu,
                         unsigned int flags);
 
+typedef int
+        (*virDrvDomainTakeSnapshot)(virDomainPtr domain,
+					 const char *name);
+typedef int
+        (*virDrvDomainRestoreSnapshot)(virDomainPtr domain,
+					 const char *name);
+typedef int
+        (*virDrvDomainDeleteSnapshot)(virDomainPtr domain,
+					 const char *name);
+typedef int
+        (*virDrvDomainListSnapshots)(virDomainPtr domain,
+					 char **sslist,int listsize);
+typedef int
+        (*virDrvDomainTakeScreenshot)(virDomainPtr domain,
+					 const char *path);
+
 /**
  * _virDriver:
  *
@@ -448,6 +464,11 @@ struct _virDriver {
     virDrvDomainIsActive       domainIsActive;
     virDrvDomainIsPersistent   domainIsPersistent;
     virDrvCPUCompare            cpuCompare;
+    virDrvDomainTakeSnapshot            domainTakeSnapshot;
+    virDrvDomainRestoreSnapshot            domainRestoreSnapshot;
+    virDrvDomainDeleteSnapshot            domainDeleteSnapshot;
+    virDrvDomainListSnapshots            domainListSnapshots;
+    virDrvDomainTakeScreenshot            domainTakeScreenshot;
 };
 
 typedef int
diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c
index 5cdadfd..ecb313c 100644
--- a/src/esx/esx_driver.c
+++ b/src/esx/esx_driver.c
@@ -3455,6 +3455,11 @@ static virDriver esxDriver = {
     esxDomainIsActive,               /* domainIsActive */
     esxDomainIsPersistent,           /* domainIsPersistent */
     NULL,                            /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 
diff --git a/src/libvirt.c b/src/libvirt.c
index 1ae2932..aaec403 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -2197,6 +2197,231 @@ error:
 }
 
 /**
+ * virDomainTakeSnapshot:
+ * @domain: a domain object
+ * @name: name of the snapshot
+ *
+ * This method will attempt to create a snapshot of the domain while running.
+ * At present, this is only implemented for QEMU/KVM domains.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainTakeSnapshot(virDomainPtr domain, const char *name){
+	DEBUG("domain=%p, name=%s",domain,name);
+	virResetLastError();
+	virConnectPtr conn;
+
+	if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+		virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+		return (-1);
+	}
+	if (domain->conn->flags & VIR_CONNECT_RO) {
+		virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+		goto error;
+	}
+	conn = domain->conn;
+	if (name == NULL) {
+		virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+		goto error;
+	}
+	if (conn->driver->domainTakeSnapshot) {
+		int ret;
+		ret = conn->driver->domainTakeSnapshot (domain, name);
+		if (ret < 0)
+			goto error;
+		return ret;
+	}
+
+	virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+	error:
+		/* Copy to connection error object for back compatability */
+		virSetConnError(domain->conn);
+		return -1;
+}
+
+/**
+ * virDomainRestoreSnapshot:
+ * @domain: a domain object
+ * @name: name of the snapshot
+ *
+ * This method will attempt to restore a snapshot that was taken by 'virDomainTakeSnapshot'
+ * At present, this is only implemented for QEMU/KVM domains.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainRestoreSnapshot(virDomainPtr domain, const char *name){
+	DEBUG("domain=%p, name=%s",domain,name);
+	virResetLastError();
+	virConnectPtr conn;
+
+	if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+		virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+		return (-1);
+	}
+	if (domain->conn->flags & VIR_CONNECT_RO) {
+		virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+		goto error;
+	}
+	conn = domain->conn;
+	if (name == NULL) {
+		virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+		goto error;
+	}
+	if (conn->driver->domainRestoreSnapshot) {
+		int ret;
+		ret = conn->driver->domainRestoreSnapshot (domain, name);
+		if (ret < 0)
+			goto error;
+		return ret;
+	}
+
+	virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+	error:
+		/* Copy to connection error object for back compatability */
+		virSetConnError(domain->conn);
+		return -1;
+}
+
+/**
+ * virDomainDeleteSnapshot:
+ * @domain: a domain object
+ * @name: name of the snapshot
+ *
+ * This method will attempt to delete a snapshot taken by 'virDomainTakeSnapshot'.
+ * At present, this is only implemented for QEMU/KVM domains.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainDeleteSnapshot(virDomainPtr domain, const char *name){
+	DEBUG("domain=%p, name=%s",domain,name);
+	virResetLastError();
+	virConnectPtr conn;
+
+	if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+		virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+		return (-1);
+	}
+	if (domain->conn->flags & VIR_CONNECT_RO) {
+		virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+		goto error;
+	}
+	conn = domain->conn;
+	if (name == NULL) {
+		virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+		goto error;
+	}
+	if (conn->driver->domainDeleteSnapshot) {
+		int ret;
+		ret = conn->driver->domainDeleteSnapshot (domain, name);
+		if (ret < 0)
+			goto error;
+		return ret;
+	}
+
+	virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+	error:
+		/* Copy to connection error object for back compatability */
+		virSetConnError(domain->conn);
+		return -1;
+}
+
+/**
+ * virDomainListSnapshots:
+ * @domain: a domain object
+ * @sslist: an array of strings
+ * @listsize: the number of elements allocated in the array
+ *
+ * This method will list all snapshots on a given domain. 
+ * At present, this is only implemented for QEMU/KVM domains.
+ *
+ * Returns number of snapshots in case of success and -1 in case of failure.
+ */
+int
+virDomainListSnapshots(virDomainPtr domain, char **sslist,int listsize){
+	DEBUG("domain=%p, sslist=%p",domain,sslist);
+	virResetLastError();
+	virConnectPtr conn;
+
+
+	if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+		virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+		return (-1);
+	}
+	conn = domain->conn;
+	//Make sure we have a valid array to work with
+	if ((sslist == NULL) || (listsize < 0)) {
+		virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+		goto error;
+	}
+	if (conn->driver->domainListSnapshots) {
+		int ret;
+		ret = conn->driver->domainListSnapshots (domain, sslist,listsize);
+		if (ret < 0)
+			goto error;
+		return ret;
+	}
+
+	virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+	error:
+		/* Copy to connection error object for back compatability */
+		virSetConnError(domain->conn);
+		return -1;
+}
+
+/**
+ * virDomainTakeScreenshot:
+ * @domain: a domain object
+ * @name: name of the snapshot
+ *
+ * This method will attempt to take a screenshot of the domain
+ * At present, this is only implemented for QEMU/KVM domains.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainTakeScreenshot(virDomainPtr domain, const char *path){
+	DEBUG("domain=%p, path=%s",domain,path);
+	virResetLastError();
+	virConnectPtr conn;
+
+	if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+		virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+		return (-1);
+	}
+	if (domain->conn->flags & VIR_CONNECT_RO) {
+		virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+		goto error;
+	}
+	conn = domain->conn;
+	if (path == NULL) {
+		virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+		goto error;
+	}
+	if (conn->driver->domainTakeScreenshot) {
+		int ret;
+		ret = conn->driver->domainTakeScreenshot (domain, path);
+		if (ret < 0)
+			goto error;
+		return ret;
+	}
+
+	virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+	error:
+		/* Copy to connection error object for back compatability */
+		virSetConnError(domain->conn);
+		return -1;
+}
+
+
+/**
  * virDomainSave:
  * @domain: a domain object
  * @to: path for the output file
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 0521158..07ec5d2 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -350,3 +350,10 @@ LIBVIRT_0.7.5 {
 } LIBVIRT_0.7.3;
 
 # .... define new API here using predicted next version number ....
+LIBVIRT_0.7.6 {
+	virDomainTakeSnapshot;
+	virDomainRestoreSnapshot;
+	virDomainDeleteSnapshot;
+	virDomainListSnapshots;
+	virDomainTakeScreenshot;
+} LIBVIRT_0.7.5;
diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
index 86606c7..bfd571f 100644
--- a/src/lxc/lxc_driver.c
+++ b/src/lxc/lxc_driver.c
@@ -2456,6 +2456,11 @@ static virDriver lxcDriver = {
     lxcDomainIsActive,
     lxcDomainIsPersistent,
     NULL, /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 static virStateDriver lxcStateDriver = {
diff --git a/src/opennebula/one_driver.c b/src/opennebula/one_driver.c
index ad7faca..20ead3c 100644
--- a/src/opennebula/one_driver.c
+++ b/src/opennebula/one_driver.c
@@ -783,6 +783,11 @@ static virDriver oneDriver = {
     NULL, /* domainIsActive */
     NULL, /* domainIsPersistent */
     NULL, /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 static virStateDriver oneStateDriver = {
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 196fd8c..abe90ab 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -1535,6 +1535,11 @@ static virDriver openvzDriver = {
     openvzDomainIsActive,
     openvzDomainIsPersistent,
     NULL, /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 int openvzRegister(void) {
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index bd5cfc7..a4f1abb 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -1651,6 +1651,11 @@ virDriver phypDriver = {
     NULL,                       /* domainIsActive */
     NULL,                       /* domainIsPersistent */
     NULL,                       /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 int
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a6a1a5a..53b068c 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3622,6 +3622,275 @@ struct qemud_save_header {
     int unused[15];
 };
 
+static int qemudDomainTakeSnapshot(virDomainPtr dom,
+				const char *name)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int fd = -1;
+    int ret = -1;
+    int rc;
+
+	qemuDriverLock(driver);
+	vm = virDomainFindByUUID(&driver->domains,dom->uuid);
+	if(!vm){
+		char uuidstr[VIR_UUID_STRING_BUFLEN];
+		virUUIDFormat(dom->uuid, uuidstr);
+		qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
+				 _("no domain with matching uuid '%s'"), uuidstr);
+		goto cleanup;
+	}
+	
+
+    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
+                         "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+
+	qemuDomainObjEnterMonitorWithDriver(driver, vm);
+        qemuDomainObjPrivatePtr priv = vm->privateData;
+	rc = qemuMonitorTakeSnapshot(priv->mon, name);
+	qemuDomainObjExitMonitorWithDriver(driver, vm);
+	if(rc < 0)
+		goto endjob;
+
+	ret = 0;
+
+endjob:
+    if (vm &&
+        qemuDomainObjEndJob(vm) == 0)
+        vm = NULL;
+
+cleanup:
+    if (fd != -1)
+        close(fd);
+    if (vm)
+        virDomainObjUnlock(vm);
+    qemuDriverUnlock(driver);
+    return ret;
+
+}
+
+static int qemudDomainRestoreSnapshot(virDomainPtr dom,
+				const char *name)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int fd = -1;
+    int ret = -1;
+    int rc;
+
+	qemuDriverLock(driver);
+	vm = virDomainFindByUUID(&driver->domains,dom->uuid);
+	if(!vm){
+		char uuidstr[VIR_UUID_STRING_BUFLEN];
+		virUUIDFormat(dom->uuid, uuidstr);
+		qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
+				 _("no domain with matching uuid '%s'"), uuidstr);
+		goto cleanup;
+	}
+	
+
+    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
+                         "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+
+	qemuDomainObjEnterMonitorWithDriver(driver, vm);
+        qemuDomainObjPrivatePtr priv = vm->privateData;
+	rc = qemuMonitorRestoreSnapshot(priv->mon, name);
+	qemuDomainObjExitMonitorWithDriver(driver, vm);
+	if(rc < 0)
+		goto endjob;
+
+	ret = 0;
+
+endjob:
+    if (vm &&
+        qemuDomainObjEndJob(vm) == 0)
+        vm = NULL;
+
+cleanup:
+    if (fd != -1)
+        close(fd);
+    if (vm)
+        virDomainObjUnlock(vm);
+    qemuDriverUnlock(driver);
+    return ret;
+
+}
+
+static int qemudDomainDeleteSnapshot(virDomainPtr dom,
+				const char *name)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int fd = -1;
+    int ret = -1;
+    int rc;
+
+	qemuDriverLock(driver);
+	vm = virDomainFindByUUID(&driver->domains,dom->uuid);
+	if(!vm){
+		char uuidstr[VIR_UUID_STRING_BUFLEN];
+		virUUIDFormat(dom->uuid, uuidstr);
+		qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
+				 _("no domain with matching uuid '%s'"), uuidstr);
+		goto cleanup;
+	}
+	
+
+    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
+                         "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+
+	qemuDomainObjEnterMonitorWithDriver(driver, vm);
+        qemuDomainObjPrivatePtr priv = vm->privateData;
+	rc = qemuMonitorDeleteSnapshot(priv->mon, name);
+	qemuDomainObjExitMonitorWithDriver(driver, vm);
+	if(rc < 0)
+		goto endjob;
+
+	ret = 0;
+
+endjob:
+    if (vm &&
+        qemuDomainObjEndJob(vm) == 0)
+        vm = NULL;
+
+cleanup:
+    if (fd != -1)
+        close(fd);
+    if (vm)
+        virDomainObjUnlock(vm);
+    qemuDriverUnlock(driver);
+    return ret;
+
+}
+
+static int qemudDomainListSnapshots(virDomainPtr dom,char** sslist,int listsize)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int fd = -1;
+    int ret = -1;
+    int rc;
+
+	qemuDriverLock(driver);
+	vm = virDomainFindByUUID(&driver->domains,dom->uuid);
+	if(!vm){
+		char uuidstr[VIR_UUID_STRING_BUFLEN];
+		virUUIDFormat(dom->uuid, uuidstr);
+		qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
+				 _("no domain with matching uuid '%s'"), uuidstr);
+		goto cleanup;
+	}
+	
+
+    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
+                         "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+
+	qemuDomainObjEnterMonitorWithDriver(driver, vm);
+        qemuDomainObjPrivatePtr priv = vm->privateData;
+	rc = qemuMonitorListSnapshots(priv->mon, sslist,listsize);
+	qemuDomainObjExitMonitorWithDriver(driver, vm);
+	if(rc < 0)
+		goto endjob;
+
+	ret = rc;
+
+endjob:
+    if (vm &&
+        qemuDomainObjEndJob(vm) == 0)
+        vm = NULL;
+
+cleanup:
+    if (fd != -1)
+        close(fd);
+    if (vm)
+        virDomainObjUnlock(vm);
+    qemuDriverUnlock(driver);
+    return ret;
+
+}
+
+static int qemudDomainTakeScreenshot(virDomainPtr dom,
+				const char *path)
+{
+    struct qemud_driver *driver = dom->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int fd = -1;
+    int ret = -1;
+    int rc;
+
+	qemuDriverLock(driver);
+	vm = virDomainFindByUUID(&driver->domains,dom->uuid);
+	if(!vm){
+		char uuidstr[VIR_UUID_STRING_BUFLEN];
+		virUUIDFormat(dom->uuid, uuidstr);
+		qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_DOMAIN,
+				 _("no domain with matching uuid '%s'"), uuidstr);
+		goto cleanup;
+	}
+	
+
+    if (qemuDomainObjBeginJobWithDriver(driver, vm) < 0)
+        goto cleanup;
+
+    if (!virDomainObjIsActive(vm)) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_INVALID,
+                         "%s", _("domain is not running"));
+        goto endjob;
+    }
+
+
+	qemuDomainObjEnterMonitorWithDriver(driver, vm);
+        qemuDomainObjPrivatePtr priv = vm->privateData;
+	rc = qemuMonitorTakeScreenshot(priv->mon, path);
+	qemuDomainObjExitMonitorWithDriver(driver, vm);
+	if(rc < 0)
+		goto endjob;
+
+	ret = 0;
+
+endjob:
+    if (vm &&
+        qemuDomainObjEndJob(vm) == 0)
+        vm = NULL;
+
+cleanup:
+    if (fd != -1)
+        close(fd);
+    if (vm)
+        virDomainObjUnlock(vm);
+    qemuDriverUnlock(driver);
+    return ret;
+
+}
+
 static int qemudDomainSave(virDomainPtr dom,
                            const char *path)
 {
@@ -7990,6 +8259,11 @@ static virDriver qemuDriver = {
     qemuDomainIsActive,
     qemuDomainIsPersistent,
     qemuCPUCompare, /* cpuCompare */
+    qemudDomainTakeSnapshot, /* domainTakeSnapshot */
+    qemudDomainRestoreSnapshot, /* domainRestoreSnapshot */
+    qemudDomainDeleteSnapshot, /* domainDeleteSnapshot */
+    qemudDomainListSnapshots, /* domainListSnapshots */
+    qemudDomainTakeScreenshot, /* domainTakeScreenshot */
 };
 
 
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 750e3e6..73c77fb 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -1276,3 +1276,34 @@ int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
 
     return qemuMonitorTextGetPtyPaths(mon, paths);
 }
+
+int qemuMonitorTakeSnapshot(qemuMonitorPtr mon,
+				const char *name){
+	DEBUG("mon=%p, name=%s",mon,name);
+	return qemuMonitorTextTakeSnapshot(mon,name);
+}
+
+int qemuMonitorRestoreSnapshot(qemuMonitorPtr mon,
+				const char *name){
+	DEBUG("mon=%p, name=%s",mon,name);
+	return qemuMonitorTextRestoreSnapshot(mon,name);
+}
+
+int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon,
+				const char *name){
+	DEBUG("mon=%p, name=%s",mon,name);
+	return qemuMonitorTextDeleteSnapshot(mon,name);
+}
+
+int qemuMonitorListSnapshots(qemuMonitorPtr mon,
+				char **sslist, int listsize){
+	DEBUG("mon=%p, sslist=%p",mon,sslist);
+	return qemuMonitorTextListSnapshots(mon,sslist,listsize);
+}
+
+int qemuMonitorTakeScreenshot(qemuMonitorPtr mon,
+				const char *path){
+	DEBUG("mon=%p, path=%s",mon,path);
+	return qemuMonitorTextTakeScreenshot(mon,path);
+}
+
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index db00b26..a1eb5e0 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -276,4 +276,15 @@ int qemuMonitorRemoveHostNetwork(qemuMonitorPtr mon,
 int qemuMonitorGetPtyPaths(qemuMonitorPtr mon,
                            virHashTablePtr paths);
 
+int qemuMonitorTakeSnapshot(qemuMonitorPtr mon,
+				const char *name);
+int qemuMonitorRestoreSnapshot(qemuMonitorPtr mon,
+				const char *name);
+int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon,
+				const char *name);
+int qemuMonitorListSnapshots(qemuMonitorPtr mon,
+				char **sslist,int listsize);
+int qemuMonitorTakeScreenshot(qemuMonitorPtr mon,
+				const char *path);
+
 #endif /* QEMU_MONITOR_H */
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index ab361c6..a094eba 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -1758,3 +1758,205 @@ cleanup:
     VIR_FREE(reply);
     return ret;
 }
+
+
+int qemuMonitorTextTakeSnapshot(qemuMonitorPtr mon,
+					const char *name)
+{
+	char *cmd;
+	char *reply = NULL;
+	int ret = -1;
+
+	if (virAsprintf(&cmd, "savevm %s",name) < 0){
+		virReportOOMError(NULL);
+		return -1;
+	}
+
+	if(qemuMonitorCommand(mon,cmd,&reply)){
+		qemudReportError(NULL,NULL,NULL,VIR_ERR_OPERATION_FAILED,
+					_("failed to take snapshot using command '%s'"),cmd);
+		goto cleanup;
+	}
+
+	//If there is not a valid drive on which to store snapshots, this is the string that qemu will reply with
+	if(strstr(reply,"No block device can accept snapshots") != NULL){
+		qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_INVALID,
+				 "%s", _("this domain does not have a device to take snapshots"));
+		goto cleanup;
+	}
+
+	ret = 0;
+
+cleanup:
+	VIR_FREE(cmd);
+	VIR_FREE(reply);
+	return ret;
+}
+
+int qemuMonitorTextRestoreSnapshot(qemuMonitorPtr mon,
+					const char *name)
+{
+	char *cmd;
+	char *reply = NULL;
+	int ret = -1;
+
+	if (virAsprintf(&cmd, "loadvm %s",name) < 0){
+		virReportOOMError(NULL);
+		return -1;
+	}
+
+	if(qemuMonitorCommand(mon,cmd,&reply)){
+		qemudReportError(NULL,NULL,NULL,VIR_ERR_OPERATION_FAILED,
+					_("failed to restore snapshot using command '%s'"),cmd);
+		goto cleanup;
+	}
+
+	//If there is not a valid drive on which to store snapshots, this is the string that qemu will reply with
+	if(strstr(reply,"No block device supports snapshots") != NULL){
+		qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_INVALID,
+				 "%s", _("this domain does not have a device to take snapshots"));
+		goto cleanup;
+	}
+	else if(strstr(reply,"Could not find snapshot") != NULL){
+		qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_INVALID,
+				 _("the snapshot '%s' does not exist, and was not restored"),name);
+		goto cleanup;
+	}
+
+	ret = 0;
+
+cleanup:
+	VIR_FREE(cmd);
+	VIR_FREE(reply);
+	return ret;
+}
+
+int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon,
+					const char *name)
+{
+	char *cmd;
+	char *reply = NULL;
+	int ret = -1;
+
+	if (virAsprintf(&cmd, "delvm %s",name) < 0){
+		virReportOOMError(NULL);
+		return -1;
+	}
+
+	if(qemuMonitorCommand(mon,cmd,&reply)){
+		qemudReportError(NULL,NULL,NULL,VIR_ERR_OPERATION_FAILED,
+					_("failed to delete snapshot using command '%s'"),cmd);
+		goto cleanup;
+	}
+
+	//If there is not a valid drive on which to store snapshots, this is the string that qemu will reply with
+	if(strstr(reply,"No block device supports snapshots") != NULL){
+		qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_INVALID,
+				 "%s", _("this domain does not have a device to take snapshots"));
+		goto cleanup;
+	}
+	else if(strstr(reply,"Could not find snapshot") != NULL){
+		qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_INVALID,
+				 _("the snapshot '%s' does not exist, and was not deleted"),name);
+		goto cleanup;
+	}
+
+	ret = 0;
+
+cleanup:
+	VIR_FREE(cmd);
+	VIR_FREE(reply);
+	return ret;
+}
+
+int qemuMonitorTextListSnapshots(qemuMonitorPtr mon,
+					char **sslist,int listsize)
+{
+	char *cmd;
+	char *reply = NULL;
+	int ret = -1;
+	int numsnapshots=0;
+	char* line;
+	char namebuf[1024];
+
+	if (virAsprintf(&cmd, "info snapshots") < 0){
+		virReportOOMError(NULL);
+		return -1;
+	}
+
+	if(qemuMonitorCommand(mon,cmd,&reply)){
+		qemudReportError(NULL,NULL,NULL,VIR_ERR_OPERATION_FAILED,
+					_("failed to take snapshot using command '%s'"),cmd);
+		goto cleanup;
+	}
+
+	//If there is not a valid drive on which to store snapshots, this is the string that qemu will reply with
+	if(strstr(reply,"No available block device supports snapshots") != NULL){
+		qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_INVALID,
+				 "%s", _("this domain does not have a device to take snapshots"));
+		goto cleanup;
+	}
+
+
+	//Output is of the form:
+	//Snapshot devices: ide0-hd0
+	//Snapshot list (from ide0-hd0):
+	//ID        TAG                 VM SIZE                DATE       VM CLOCK
+	//%d         %s                    %lM 2009-12-29 16:44:54   00:00:12.980
+	//%d         %s                    %lM 2009-12-29 19:12:53   02:27:22.059
+	line = reply;
+	while(line != NULL && line+1 != '\0' && numsnapshots < listsize){
+		if(!strstr(line,"Snapshot devices") &&
+			!strstr(line,"Snapshot list") &&
+			!strstr(line,"VM SIZE") &&
+			strlen(line) > 2){
+				sscanf(line,"%*d %s",namebuf);
+				sslist[numsnapshots] = strdup(namebuf);
+				numsnapshots++;
+		}
+		line = strchr(line+1,'\n');
+	}
+	
+	ret = numsnapshots;
+
+cleanup:
+	VIR_FREE(cmd);
+	VIR_FREE(reply);
+	return ret;
+}
+
+int qemuMonitorTextTakeScreenshot(qemuMonitorPtr mon,
+					const char *path)
+{
+	char *cmd;
+	char *reply = NULL;
+	int ret = -1;
+
+	if (virAsprintf(&cmd, "screendump %s",path) < 0){
+		virReportOOMError(NULL);
+		return -1;
+	}
+
+	if(qemuMonitorCommand(mon,cmd,&reply)){
+		qemudReportError(NULL,NULL,NULL,VIR_ERR_OPERATION_FAILED,
+					_("failed to take screenshot using command '%s'"),cmd);
+		goto cleanup;
+	}
+
+	//Qemu doesn't seem to actually report any errors if it cannot dump a screenshot, so make sure that file at least exists when we're done
+	FILE *imgP = fopen(path,"r");
+	if(imgP == NULL){
+		qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_INVALID,
+				 _("failed to dump screenshot to '%s'"),path);
+		goto cleanup;
+	}
+	fclose(imgP);
+
+	ret = 0;
+
+cleanup:
+	VIR_FREE(cmd);
+	VIR_FREE(reply);
+	return ret;
+}
+
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index 5897a03..99e4960 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -160,4 +160,14 @@ int qemuMonitorTextRemoveHostNetwork(qemuMonitorPtr mon,
 int qemuMonitorTextGetPtyPaths(qemuMonitorPtr mon,
                                virHashTablePtr paths);
 
+int qemuMonitorTextTakeSnapshot(qemuMonitorPtr mon,
+					const char *name);
+int qemuMonitorTextRestoreSnapshot(qemuMonitorPtr mon,
+					const char *name);
+int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon,
+					const char *name);
+int qemuMonitorTextListSnapshots(qemuMonitorPtr mon,
+					char **sslist,int listsize);
+int qemuMonitorTextTakeScreenshot(qemuMonitorPtr mon,
+					const char *name);
 #endif /* QEMU_MONITOR_TEXT_H */
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index d6f5fce..86be3fc 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -7535,6 +7535,136 @@ done:
     return rv;
 }
 
+static int
+remoteDomainTakeSnapshot(virDomainPtr dom,const char *name)
+{
+	struct private_data *priv = dom->conn->privateData;
+	remote_domain_take_snapshot_args args;
+	int rv = -1; 
+
+	remoteDriverLock(priv);
+
+        make_nonnull_domain (&args.dom, dom);
+        args.name = (char *) name;
+
+	if(call(dom->conn,priv,0,REMOTE_PROC_DOMAIN_TAKE_SNAPSHOT,
+		(xdrproc_t) xdr_remote_domain_take_snapshot_args, (char *) &args,
+		(xdrproc_t) xdr_void, (char *) NULL) == -1)
+			goto done;
+
+	rv = 0;
+done:
+	remoteDriverUnlock(priv);
+	return rv;
+		
+}
+
+static int
+remoteDomainRestoreSnapshot(virDomainPtr dom,const char *name)
+{
+	struct private_data *priv = dom->conn->privateData;
+	remote_domain_restore_snapshot_args args;
+	int rv = -1; 
+
+	remoteDriverLock(priv);
+
+        make_nonnull_domain (&args.dom, dom);
+        args.name = (char *) name;
+
+	if(call(dom->conn,priv,0,REMOTE_PROC_DOMAIN_RESTORE_SNAPSHOT,
+		(xdrproc_t) xdr_remote_domain_restore_snapshot_args, (char *) &args,
+		(xdrproc_t) xdr_void, (char *) NULL) == -1)
+			goto done;
+
+	rv = 0;
+done:
+	remoteDriverUnlock(priv);
+	return rv;
+		
+}
+
+static int
+remoteDomainDeleteSnapshot(virDomainPtr dom,const char *name)
+{
+	struct private_data *priv = dom->conn->privateData;
+	remote_domain_delete_snapshot_args args;
+	int rv = -1; 
+
+	remoteDriverLock(priv);
+
+        make_nonnull_domain (&args.dom, dom);
+        args.name = (char *) name;
+
+	if(call(dom->conn,priv,0,REMOTE_PROC_DOMAIN_DELETE_SNAPSHOT,
+		(xdrproc_t) xdr_remote_domain_delete_snapshot_args, (char *) &args,
+		(xdrproc_t) xdr_void, (char *) NULL) == -1)
+			goto done;
+
+	rv = 0;
+done:
+	remoteDriverUnlock(priv);
+	return rv;
+		
+}
+
+static int
+remoteDomainListSnapshots(virDomainPtr dom,char **sslist,int listsize)
+{
+	struct private_data *priv = dom->conn->privateData;
+	remote_domain_list_snapshots_args args;
+	remote_domain_list_snapshots_ret ret;
+	int rv = -1; 
+	int i =0;
+
+	remoteDriverLock(priv);
+
+        make_nonnull_domain (&args.dom, dom);
+        args.listsize = listsize;
+
+	memset (&ret, 0, sizeof ret);
+	if (call (dom->conn, priv, 0, REMOTE_PROC_DOMAIN_LIST_SNAPSHOTS,
+	      (xdrproc_t) xdr_remote_domain_list_snapshots_args, (char *) &args,
+	      (xdrproc_t) xdr_remote_domain_list_snapshots_ret, (char *) &ret) == -1)
+		goto done;
+
+	for (i = 0; i < ret.numsnapshots; ++i)
+		sslist[i] = ret.sslist[i];
+
+
+    rv = ret.numsnapshots;
+
+    xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret);
+
+done:
+	remoteDriverUnlock(priv);
+	return rv;
+		
+}
+
+static int
+remoteDomainTakeScreenshot(virDomainPtr dom,const char *path)
+{
+	struct private_data *priv = dom->conn->privateData;
+	remote_domain_take_screenshot_args args;
+	int rv = -1; 
+
+	remoteDriverLock(priv);
+
+        make_nonnull_domain (&args.dom, dom);
+        args.path = (char *) path;
+
+	if(call(dom->conn,priv,0,REMOTE_PROC_DOMAIN_TAKE_SCREENSHOT,
+		(xdrproc_t) xdr_remote_domain_take_screenshot_args, (char *) &args,
+		(xdrproc_t) xdr_void, (char *) NULL) == -1)
+			goto done;
+
+	rv = 0;
+done:
+	remoteDriverUnlock(priv);
+	return rv;
+		
+}
+
 /*----------------------------------------------------------------------*/
 
 
@@ -8923,6 +9053,11 @@ static virDriver remote_driver = {
     remoteDomainIsActive, /* domainIsActive */
     remoteDomainIsPersistent, /* domainIsPersistent */
     remoteCPUCompare, /* cpuCompare */
+    remoteDomainTakeSnapshot, /* domainTakeSnapshot */
+    remoteDomainRestoreSnapshot, /* domainRestoreSnapshot */
+    remoteDomainDeleteSnapshot, /* domainDeleteSnapshot */
+    remoteDomainListSnapshots, /* domainListSnapshots */
+    remoteDomainTakeScreenshot, /* domainTakeScreenshot */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c
index 834eb6b..954933b 100644
--- a/src/remote/remote_protocol.c
+++ b/src/remote/remote_protocol.c
@@ -2912,6 +2912,69 @@ xdr_remote_cpu_compare_ret (XDR *xdrs, remote_cpu_compare_ret *objp)
 }
 
 bool_t
+xdr_remote_domain_take_snapshot_args (XDR *xdrs, remote_domain_take_snapshot_args *objp)
+{
+	if(!xdr_remote_nonnull_string(xdrs,&objp->name))
+		return FALSE;
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
+                 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_remote_domain_restore_snapshot_args (XDR *xdrs, remote_domain_restore_snapshot_args *objp)
+{
+	if(!xdr_remote_nonnull_string(xdrs,&objp->name))
+		return FALSE;
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
+                 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_remote_domain_delete_snapshot_args (XDR *xdrs, remote_domain_delete_snapshot_args *objp)
+{
+	if(!xdr_remote_nonnull_string(xdrs,&objp->name))
+		return FALSE;
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
+                 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_remote_domain_list_snapshots_args (XDR *xdrs, remote_domain_list_snapshots_args *objp)
+{
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->listsize))
+                 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_remote_domain_list_snapshots_ret (XDR *xdrs, remote_domain_list_snapshots_ret *objp)
+{
+        char **objp_cpp0 = (char **) (void *) &objp->sslist;
+
+         if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->numsnapshots, 100, //100 is the max size for the list
+                sizeof (remote_nonnull_string), (xdrproc_t) xdr_remote_nonnull_string))
+                 return FALSE;
+         if (!xdr_int (xdrs, &objp->numsnapshots))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_take_screenshot_args (XDR *xdrs, remote_domain_take_screenshot_args *objp)
+{
+	if(!xdr_remote_nonnull_string(xdrs,&objp->path))
+		return FALSE;
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
+                 return FALSE;
+	return TRUE;
+}
+
+bool_t
 xdr_remote_procedure (XDR *xdrs, remote_procedure *objp)
 {
 
diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h
index 3f3b520..e0174f8 100644
--- a/src/remote/remote_protocol.h
+++ b/src/remote/remote_protocol.h
@@ -1652,6 +1652,42 @@ typedef struct remote_cpu_compare_ret remote_cpu_compare_ret;
 #define REMOTE_PROGRAM 0x20008086
 #define REMOTE_PROTOCOL_VERSION 1
 
+struct remote_domain_take_snapshot_args {
+        remote_nonnull_domain dom;
+        remote_nonnull_string name;
+};
+typedef struct remote_domain_take_snapshot_args remote_domain_take_snapshot_args;
+
+struct remote_domain_restore_snapshot_args {
+        remote_nonnull_domain dom;
+        remote_nonnull_string name;
+};
+typedef struct remote_domain_restore_snapshot_args remote_domain_restore_snapshot_args;
+
+struct remote_domain_delete_snapshot_args {
+        remote_nonnull_domain dom;
+        remote_nonnull_string name;
+};
+typedef struct remote_domain_delete_snapshot_args remote_domain_delete_snapshot_args;
+
+struct remote_domain_list_snapshots_args {
+        remote_nonnull_domain dom;
+        int listsize;
+};
+typedef struct remote_domain_list_snapshots_args remote_domain_list_snapshots_args;
+
+struct remote_domain_list_snapshots_ret {
+        int numsnapshots;
+	char** sslist;
+};
+typedef struct remote_domain_list_snapshots_ret remote_domain_list_snapshots_ret;
+
+struct remote_domain_take_screenshot_args {
+        remote_nonnull_domain dom;
+        remote_nonnull_string path;
+};
+typedef struct remote_domain_take_screenshot_args remote_domain_take_screenshot_args;
+
 enum remote_procedure {
         REMOTE_PROC_OPEN = 1,
         REMOTE_PROC_CLOSE = 2,
@@ -1812,6 +1848,11 @@ enum remote_procedure {
         REMOTE_PROC_GET_LIB_VERSION = 157,
         REMOTE_PROC_CPU_COMPARE = 158,
         REMOTE_PROC_DOMAIN_MEMORY_STATS = 159,
+        REMOTE_PROC_DOMAIN_TAKE_SNAPSHOT = 160,
+        REMOTE_PROC_DOMAIN_RESTORE_SNAPSHOT = 161,
+        REMOTE_PROC_DOMAIN_DELETE_SNAPSHOT = 162,
+        REMOTE_PROC_DOMAIN_LIST_SNAPSHOTS = 163,
+        REMOTE_PROC_DOMAIN_TAKE_SCREENSHOT = 164,
 };
 typedef enum remote_procedure remote_procedure;
 
@@ -2114,6 +2155,13 @@ extern  bool_t xdr_remote_interface_is_active_args (XDR *, remote_interface_is_a
 extern  bool_t xdr_remote_interface_is_active_ret (XDR *, remote_interface_is_active_ret*);
 extern  bool_t xdr_remote_cpu_compare_args (XDR *, remote_cpu_compare_args*);
 extern  bool_t xdr_remote_cpu_compare_ret (XDR *, remote_cpu_compare_ret*);
+extern  bool_t xdr_remote_domain_take_snapshot_args (XDR *, remote_domain_take_snapshot_args*);
+extern  bool_t xdr_remote_domain_restore_snapshot_args (XDR *, remote_domain_restore_snapshot_args*);
+extern  bool_t xdr_remote_domain_delete_snapshot_args (XDR *, remote_domain_delete_snapshot_args*);
+extern  bool_t xdr_remote_domain_list_snapshots_args (XDR *, remote_domain_list_snapshots_args*);
+extern  bool_t xdr_remote_domain_list_snapshots_ret (XDR *, remote_domain_list_snapshots_ret*);
+extern  bool_t xdr_remote_domain_take_screenshot_args (XDR *, remote_domain_take_screenshot_args*);
+//extern  bool_t xdr_remote_domain_take_snapshot_ret (XDR *, remote_domain_take_snapshot_ret*);
 extern  bool_t xdr_remote_procedure (XDR *, remote_procedure*);
 extern  bool_t xdr_remote_message_type (XDR *, remote_message_type*);
 extern  bool_t xdr_remote_message_status (XDR *, remote_message_status*);
@@ -2390,6 +2438,13 @@ extern bool_t xdr_remote_interface_is_active_args ();
 extern bool_t xdr_remote_interface_is_active_ret ();
 extern bool_t xdr_remote_cpu_compare_args ();
 extern bool_t xdr_remote_cpu_compare_ret ();
+extern bool_t xdr_remote_domain_take_snapshot_args ();
+extern bool_t xdr_remote_domain_restore_snapshot_args ();
+extern bool_t xdr_remote_domain_delete_snapshot_args ();
+extern bool_t xdr_remote_domain_list_snapshots_args ();
+extern bool_t xdr_remote_domain_list_snapshots_ret ();
+extern bool_t xdr_remote_domain_take_screenshot_args ();
+//extern bool_t xdr_remote_domain_take_snapshot_ret ();
 extern bool_t xdr_remote_procedure ();
 extern bool_t xdr_remote_message_type ();
 extern bool_t xdr_remote_message_status ();
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index bed3940..2522980 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -1460,7 +1460,15 @@ struct remote_cpu_compare_ret {
     int result;
 };
 
-
+struct remote_domain_take_snapshot_args {
+    remote_nonnull_domain dom;
+    remote_nonnull_string name;
+};
+/*
+struct remote_domain_take_snapshot_ret {
+    int result;
+};
+*/
 /*----- Protocol. -----*/
 
 /* Define the program number, protocol version and procedure numbers here. */
@@ -1641,7 +1649,8 @@ enum remote_procedure {
     REMOTE_PROC_INTERFACE_IS_ACTIVE = 156,
     REMOTE_PROC_GET_LIB_VERSION = 157,
     REMOTE_PROC_CPU_COMPARE = 158,
-    REMOTE_PROC_DOMAIN_MEMORY_STATS = 159
+    REMOTE_PROC_DOMAIN_MEMORY_STATS = 159,
+    REMOTE_PROC_DOMAIN_TAKE_SNAPSHOT = 160,
 
     /*
      * Notice how the entries are grouped in sets of 10 ?
diff --git a/src/test/test_driver.c b/src/test/test_driver.c
index 2122a1b..bcba054 100644
--- a/src/test/test_driver.c
+++ b/src/test/test_driver.c
@@ -5238,6 +5238,11 @@ static virDriver testDriver = {
     testDomainIsActive, /* domainIsActive */
     testDomainIsPersistent, /* domainIsPersistent */
     NULL, /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 static virNetworkDriver testNetworkDriver = {
diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c
index b808090..62c74fd 100644
--- a/src/uml/uml_driver.c
+++ b/src/uml/uml_driver.c
@@ -1924,6 +1924,11 @@ static virDriver umlDriver = {
     umlDomainIsActive,
     umlDomainIsPersistent,
     NULL, /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 
diff --git a/src/vbox/vbox_tmpl.c b/src/vbox/vbox_tmpl.c
index 5a1d8dc..93d4791 100644
--- a/src/vbox/vbox_tmpl.c
+++ b/src/vbox/vbox_tmpl.c
@@ -7051,6 +7051,11 @@ virDriver NAME(Driver) = {
     vboxDomainIsActive,
     vboxDomainIsPersistent,
     NULL, /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 virNetworkDriver NAME(NetworkDriver) = {
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c
index 4911c9e..3f65a0d 100644
--- a/src/xen/xen_driver.c
+++ b/src/xen/xen_driver.c
@@ -1862,6 +1862,11 @@ static virDriver xenUnifiedDriver = {
     xenUnifiedDomainIsActive,
     xenUnifiedDomainisPersistent,
     NULL, /* cpuCompare */
+    NULL,                            /* domainTakeSnapshot */
+    NULL,                            /* domainRestoreSnapshot */
+    NULL,                            /* domainDeleteSnapshot */
+    NULL,                            /* domainListSnapshots */
+    NULL,                            /* domainTakeScreenshot */
 };
 
 /**
--
Libvir-list mailing list
Libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]