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 */ }; /**