[libvirt] [PATCH 11/12] Move virDomain related APIs out of libvirt.c

Daniel P. Berrange berrange at redhat.com
Wed Oct 22 17:15:01 UTC 2014


Introduce a src/libvirt-domain.c file to hold all the
methods related to the virDomain type.
---
 docs/apibuild.py       |     2 +
 po/POTFILES.in         |     1 +
 src/Makefile.am        |     2 +
 src/libvirt-domain.c   | 11112 ++++++++++++++++++++++++++++++++++++++++++
 src/libvirt.c          | 12388 +++--------------------------------------------
 src/libvirt_internal.h |     6 +
 6 files changed, 11774 insertions(+), 11737 deletions(-)
 create mode 100644 src/libvirt-domain.c

diff --git a/docs/apibuild.py b/docs/apibuild.py
index 1eb6fcf..a96260f 100755
--- a/docs/apibuild.py
+++ b/docs/apibuild.py
@@ -24,6 +24,7 @@ included_files = {
   "libvirt.h": "header with general libvirt API definitions",
   "virterror.h": "header with error specific API definitions",
   "libvirt.c": "Main interfaces for the libvirt library",
+  "libvirt-domain.c": "Domain interfaces for the libvirt library",
   "libvirt-domain-snapshot.c": "Domain snapshot interfaces for the libvirt library",
   "libvirt-interface.c": "Interface interfaces for the libvirt library",
   "libvirt-network.c": "Network interfaces for the libvirt library",
@@ -73,6 +74,7 @@ ignored_functions = {
   "virDomainMigratePrepareTunnel3": "private function for tunnelled migration",
   "DllMain": "specific function for Win32",
   "virTypedParamsValidate": "internal function in virtypedparam.c",
+  "virTypedParameterValidateSet": "internal function in virtypedparam.c",
   "virTypedParameterAssign": "internal function in virtypedparam.c",
   "virTypedParameterAssignFromStr": "internal function in virtypedparam.c",
   "virTypedParameterToString": "internal function in virtypedparam.c",
diff --git a/po/POTFILES.in b/po/POTFILES.in
index ade9fdb..d9c9af7 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -57,6 +57,7 @@ src/interface/interface_backend_netcf.c
 src/interface/interface_backend_udev.c
 src/internal.h
 src/libvirt.c
+src/libvirt-domain.c
 src/libvirt-domain-snapshot.c
 src/libvirt-lxc.c
 src/libvirt-network.c
diff --git a/src/Makefile.am b/src/Makefile.am
index f246a23..7da9abd 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -189,6 +189,7 @@ DRIVER_SOURCES =							\
 		fdstream.c fdstream.h					\
 		$(NODE_INFO_SOURCES)					\
 		libvirt.c libvirt_internal.h				\
+		libvirt-domain.c 					\
 		libvirt-domain-snapshot.c 				\
 		libvirt-interface.c	 				\
 		libvirt-network.c	 				\
@@ -2194,6 +2195,7 @@ libvirt_setuid_rpc_client_la_SOURCES = 		\
 		remote/lxc_protocol.c		\
 		datatypes.c			\
 		libvirt.c			\
+		libvirt-domain.c		\
 		libvirt-domain-snapshot.c	\
 		libvirt-interface.c		\
 		libvirt-network.c		\
diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c
new file mode 100644
index 0000000..37b8927
--- /dev/null
+++ b/src/libvirt-domain.c
@@ -0,0 +1,11112 @@
+/*
+ * libvirt-domain.c: entry points for virDomainPtr APIs
+ *
+ * Copyright (C) 2006-2014 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <sys/stat.h>
+
+#include "intprops.h"
+
+#include "datatypes.h"
+#include "viralloc.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "virtypedparam.h"
+
+VIR_LOG_INIT("libvirt.domain");
+
+#define VIR_FROM_THIS VIR_FROM_NONE
+
+
+/**
+ * virConnectListDomains:
+ * @conn: pointer to the hypervisor connection
+ * @ids: array to collect the list of IDs of active domains
+ * @maxids: size of @ids
+ *
+ * Collect the list of active domains, and store their IDs in array @ids
+ *
+ * For inactive domains, see virConnectListDefinedDomains().  For more
+ * control over the results, see virConnectListAllDomains().
+ *
+ * Returns the number of domains found or -1 in case of error.  Note that
+ * this command is inherently racy; a domain can be started between a
+ * call to virConnectNumOfDomains() and this call; you are only guaranteed
+ * that all currently active domains were listed if the return is less
+ * than @maxids.
+ */
+int
+virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
+{
+    VIR_DEBUG("conn=%p, ids=%p, maxids=%d", conn, ids, maxids);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(ids, error);
+    virCheckNonNegativeArgGoto(maxids, error);
+
+    if (conn->driver->connectListDomains) {
+        int ret = conn->driver->connectListDomains(conn, ids, maxids);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virConnectNumOfDomains:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Provides the number of active domains.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+int
+virConnectNumOfDomains(virConnectPtr conn)
+{
+    VIR_DEBUG("conn=%p", conn);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+
+    if (conn->driver->connectNumOfDomains) {
+        int ret = conn->driver->connectNumOfDomains(conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetConnect:
+ * @dom: pointer to a domain
+ *
+ * Provides the connection pointer associated with a domain.  The
+ * reference counter on the connection is not increased by this
+ * call.
+ *
+ * WARNING: When writing libvirt bindings in other languages, do
+ * not use this function.  Instead, store the connection and
+ * the domain object together.
+ *
+ * Returns the virConnectPtr or NULL in case of failure.
+ */
+virConnectPtr
+virDomainGetConnect(virDomainPtr dom)
+{
+    VIR_DOMAIN_DEBUG(dom);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, NULL);
+
+    return dom->conn;
+}
+
+
+/**
+ * virDomainCreateXML:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: string containing an XML description of the domain
+ * @flags: bitwise-OR of supported virDomainCreateFlags
+ *
+ * Launch a new guest domain, based on an XML description similar
+ * to the one returned by virDomainGetXMLDesc()
+ * This function may require privileged access to the hypervisor.
+ * The domain is not persistent, so its definition will disappear when it
+ * is destroyed, or if the host is restarted (see virDomainDefineXML() to
+ * define persistent domains).
+ *
+ * If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain
+ * will be started, but its CPUs will remain paused. The CPUs
+ * can later be manually started using virDomainResume.
+ *
+ * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
+ * domain will be automatically destroyed when the virConnectPtr
+ * object is finally released. This will also happen if the
+ * client application crashes / loses its connection to the
+ * libvirtd daemon. Any domains marked for auto destroy will
+ * block attempts at migration, save-to-file, or snapshots.
+ *
+ * virDomainFree should be used to free the resources after the
+ * domain object is no longer needed.
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+virDomainCreateXML(virConnectPtr conn, const char *xmlDesc,
+                   unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, xmlDesc, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(xmlDesc, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainCreateXML) {
+        virDomainPtr ret;
+        ret = conn->driver->domainCreateXML(conn, xmlDesc, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainCreateXMLWithFiles:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: string containing an XML description of the domain
+ * @nfiles: number of file descriptors passed
+ * @files: list of file descriptors passed
+ * @flags: bitwise-OR of supported virDomainCreateFlags
+ *
+ * Launch a new guest domain, based on an XML description similar
+ * to the one returned by virDomainGetXMLDesc()
+ * This function may require privileged access to the hypervisor.
+ * The domain is not persistent, so its definition will disappear when it
+ * is destroyed, or if the host is restarted (see virDomainDefineXML() to
+ * define persistent domains).
+ *
+ * @files provides an array of file descriptors which will be
+ * made available to the 'init' process of the guest. The file
+ * handles exposed to the guest will be renumbered to start
+ * from 3 (ie immediately following stderr). This is only
+ * supported for guests which use container based virtualization
+ * technology.
+ *
+ * If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain
+ * will be started, but its CPUs will remain paused. The CPUs
+ * can later be manually started using virDomainResume.
+ *
+ * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
+ * domain will be automatically destroyed when the virConnectPtr
+ * object is finally released. This will also happen if the
+ * client application crashes / loses its connection to the
+ * libvirtd daemon. Any domains marked for auto destroy will
+ * block attempts at migration, save-to-file, or snapshots.
+ *
+ * virDomainFree should be used to free the resources after the
+ * domain object is no longer needed.
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+virDomainCreateXMLWithFiles(virConnectPtr conn, const char *xmlDesc,
+                            unsigned int nfiles,
+                            int *files,
+                            unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, xmlDesc=%s, nfiles=%u, files=%p, flags=%x",
+              conn, xmlDesc, nfiles, files, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(xmlDesc, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainCreateXMLWithFiles) {
+        virDomainPtr ret;
+        ret = conn->driver->domainCreateXMLWithFiles(conn, xmlDesc,
+                                                     nfiles, files,
+                                                     flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainCreateLinux:
+ * @conn: pointer to the hypervisor connection
+ * @xmlDesc: string containing an XML description of the domain
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Deprecated after 0.4.6.
+ * Renamed to virDomainCreateXML() providing identical functionality.
+ * This existing name will left indefinitely for API compatibility.
+ *
+ * Returns a new domain object or NULL in case of failure
+ */
+virDomainPtr
+virDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
+                     unsigned int flags)
+{
+    return virDomainCreateXML(conn, xmlDesc, flags);
+}
+
+
+/**
+ * virDomainLookupByID:
+ * @conn: pointer to the hypervisor connection
+ * @id: the domain ID number
+ *
+ * Try to find a domain based on the hypervisor ID number
+ * Note that this won't work for inactive domains which have an ID of -1,
+ * in that case a lookup based on the Name or UUId need to be done instead.
+ *
+ * virDomainFree should be used to free the resources after the
+ * domain object is no longer needed.
+ *
+ * Returns a new domain object or NULL in case of failure.  If the
+ * domain cannot be found, then VIR_ERR_NO_DOMAIN error is raised.
+ */
+virDomainPtr
+virDomainLookupByID(virConnectPtr conn, int id)
+{
+    VIR_DEBUG("conn=%p, id=%d", conn, id);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNegativeArgGoto(id, error);
+
+    if (conn->driver->domainLookupByID) {
+        virDomainPtr ret;
+        ret = conn->driver->domainLookupByID(conn, id);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainLookupByUUID:
+ * @conn: pointer to the hypervisor connection
+ * @uuid: the raw UUID for the domain
+ *
+ * Try to lookup a domain on the given hypervisor based on its UUID.
+ *
+ * virDomainFree should be used to free the resources after the
+ * domain object is no longer needed.
+ *
+ * Returns a new domain object or NULL in case of failure.  If the
+ * domain cannot be found, then VIR_ERR_NO_DOMAIN error is raised.
+ */
+virDomainPtr
+virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+    VIR_UUID_DEBUG(conn, uuid);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(uuid, error);
+
+    if (conn->driver->domainLookupByUUID) {
+        virDomainPtr ret;
+        ret = conn->driver->domainLookupByUUID(conn, uuid);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainLookupByUUIDString:
+ * @conn: pointer to the hypervisor connection
+ * @uuidstr: the string UUID for the domain
+ *
+ * Try to lookup a domain on the given hypervisor based on its UUID.
+ *
+ * virDomainFree should be used to free the resources after the
+ * domain object is no longer needed.
+ *
+ * Returns a new domain object or NULL in case of failure.  If the
+ * domain cannot be found, then VIR_ERR_NO_DOMAIN error is raised.
+ */
+virDomainPtr
+virDomainLookupByUUIDString(virConnectPtr conn, const char *uuidstr)
+{
+    unsigned char uuid[VIR_UUID_BUFLEN];
+    VIR_DEBUG("conn=%p, uuidstr=%s", conn, NULLSTR(uuidstr));
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(uuidstr, error);
+
+    if (virUUIDParse(uuidstr, uuid) < 0) {
+        virReportInvalidArg(uuidstr,
+                            _("uuidstr in %s must be a valid UUID"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    return virDomainLookupByUUID(conn, &uuid[0]);
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainLookupByName:
+ * @conn: pointer to the hypervisor connection
+ * @name: name for the domain
+ *
+ * Try to lookup a domain on the given hypervisor based on its name.
+ *
+ * virDomainFree should be used to free the resources after the
+ * domain object is no longer needed.
+ *
+ * Returns a new domain object or NULL in case of failure.  If the
+ * domain cannot be found, then VIR_ERR_NO_DOMAIN error is raised.
+ */
+virDomainPtr
+virDomainLookupByName(virConnectPtr conn, const char *name)
+{
+    VIR_DEBUG("conn=%p, name=%s", conn, name);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(name, error);
+
+    if (conn->driver->domainLookupByName) {
+        virDomainPtr dom;
+        dom = conn->driver->domainLookupByName(conn, name);
+        if (!dom)
+            goto error;
+        return dom;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainDestroy:
+ * @domain: a domain object
+ *
+ * Destroy the domain object. The running instance is shutdown if not down
+ * already and all resources used by it are given back to the hypervisor. This
+ * does not free the associated virDomainPtr object.
+ * This function may require privileged access.
+ *
+ * virDomainDestroy first requests that a guest terminate
+ * (e.g. SIGTERM), then waits for it to comply. After a reasonable
+ * timeout, if the guest still exists, virDomainDestroy will
+ * forcefully terminate the guest (e.g. SIGKILL) if necessary (which
+ * may produce undesirable results, for example unflushed disk cache
+ * in the guest). To avoid this possibility, it's recommended to
+ * instead call virDomainDestroyFlags, sending the
+ * VIR_DOMAIN_DESTROY_GRACEFUL flag.
+ *
+ * If the domain is transient and has any snapshot metadata (see
+ * virDomainSnapshotNum()), then that metadata will automatically
+ * be deleted when the domain quits.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainDestroy(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainDestroy) {
+        int ret;
+        ret = conn->driver->domainDestroy(domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainDestroyFlags:
+ * @domain: a domain object
+ * @flags: bitwise-OR of virDomainDestroyFlagsValues
+ *
+ * Destroy the domain object. The running instance is shutdown if not down
+ * already and all resources used by it are given back to the hypervisor.
+ * This does not free the associated virDomainPtr object.
+ * This function may require privileged access.
+ *
+ * Calling this function with no @flags set (equal to zero) is
+ * equivalent to calling virDomainDestroy, and after a reasonable
+ * timeout will forcefully terminate the guest (e.g. SIGKILL) if
+ * necessary (which may produce undesirable results, for example
+ * unflushed disk cache in the guest). Including
+ * VIR_DOMAIN_DESTROY_GRACEFUL in the flags will prevent the forceful
+ * termination of the guest, and virDomainDestroyFlags will instead
+ * return an error if the guest doesn't terminate by the end of the
+ * timeout; at that time, the management application can decide if
+ * calling again without VIR_DOMAIN_DESTROY_GRACEFUL is appropriate.
+ *
+ * Another alternative which may produce cleaner results for the
+ * guest's disks is to use virDomainShutdown() instead, but that
+ * depends on guest support (some hypervisor/guest combinations may
+ * ignore the shutdown request).
+ *
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainDestroyFlags(virDomainPtr domain,
+                      unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainDestroyFlags) {
+        int ret;
+        ret = conn->driver->domainDestroyFlags(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainFree:
+ * @domain: a domain object
+ *
+ * Free the domain object. The running instance is kept alive.
+ * The data structure is freed and should not be used thereafter.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainFree(virDomainPtr domain)
+{
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+
+    virObjectUnref(domain);
+    return 0;
+}
+
+
+/**
+ * virDomainRef:
+ * @domain: the domain to hold a reference on
+ *
+ * Increment the reference count on the domain. For each
+ * additional call to this method, there shall be a corresponding
+ * call to virDomainFree to release the reference count, once
+ * the caller no longer needs the reference to this object.
+ *
+ * This method is typically useful for applications where multiple
+ * threads are using a connection, and it is required that the
+ * connection remain open until all threads have finished using
+ * it. ie, each new thread using a domain would increment
+ * the reference count.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainRef(virDomainPtr domain)
+{
+    VIR_DOMAIN_DEBUG(domain, "refs=%d", domain ? domain->object.u.s.refs : 0);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+
+    virObjectRef(domain);
+    return 0;
+}
+
+
+/**
+ * virDomainSuspend:
+ * @domain: a domain object
+ *
+ * Suspends an active domain, the process is frozen without further access
+ * to CPU resources and I/O but the memory used by the domain at the
+ * hypervisor level will stay allocated. Use virDomainResume() to reactivate
+ * the domain.
+ * This function may require privileged access.
+ * Moreover, suspend may not be supported if domain is in some
+ * special state like VIR_DOMAIN_PMSUSPENDED.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainSuspend(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainSuspend) {
+        int ret;
+        ret = conn->driver->domainSuspend(domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainResume:
+ * @domain: a domain object
+ *
+ * Resume a suspended domain, the process is restarted from the state where
+ * it was frozen by calling virDomainSuspend().
+ * This function may require privileged access
+ * Moreover, resume may not be supported if domain is in some
+ * special state like VIR_DOMAIN_PMSUSPENDED.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainResume(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainResume) {
+        int ret;
+        ret = conn->driver->domainResume(domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainPMSuspendForDuration:
+ * @dom: a domain object
+ * @target: a value from virNodeSuspendTarget
+ * @duration: duration in seconds to suspend, or 0 for indefinite
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Attempt to have the guest enter the given @target power management
+ * suspension level.  If @duration is non-zero, also schedule the guest to
+ * resume normal operation after that many seconds, if nothing else has
+ * resumed it earlier.  Some hypervisors require that @duration be 0, for
+ * an indefinite suspension.
+ *
+ * Dependent on hypervisor used, this may require a
+ * guest agent to be available, e.g. QEMU.
+ *
+ * Beware that at least for QEMU, the domain's process will be terminated
+ * when VIR_NODE_SUSPEND_TARGET_DISK is used and a new process will be
+ * launched when libvirt is asked to wake up the domain. As a result of
+ * this, any runtime changes, such as device hotplug or memory settings,
+ * are lost unless such changes were made with VIR_DOMAIN_AFFECT_CONFIG
+ * flag.
+ *
+ * Returns: 0 on success,
+ *          -1 on failure.
+ */
+int
+virDomainPMSuspendForDuration(virDomainPtr dom,
+                              unsigned int target,
+                              unsigned long long duration,
+                              unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "target=%u duration=%llu flags=%x",
+                     target, duration, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainPMSuspendForDuration) {
+        int ret;
+        ret = conn->driver->domainPMSuspendForDuration(dom, target,
+                                                       duration, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainPMWakeup:
+ * @dom: a domain object
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Inject a wakeup into the guest that previously used
+ * virDomainPMSuspendForDuration, rather than waiting for the
+ * previously requested duration (if any) to elapse.
+ *
+ * Returns: 0 on success,
+ *          -1 on failure.
+ */
+int
+virDomainPMWakeup(virDomainPtr dom,
+                  unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainPMWakeup) {
+        int ret;
+        ret = conn->driver->domainPMWakeup(dom, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSave:
+ * @domain: a domain object
+ * @to: path for the output file
+ *
+ * This method will suspend a domain and save its memory contents to
+ * a file on disk. After the call, if successful, the domain is not
+ * listed as running anymore (this ends the life of a transient domain).
+ * Use virDomainRestore() to restore a domain after saving.
+ *
+ * See virDomainSaveFlags() for more control.  Also, a save file can
+ * be inspected or modified slightly with virDomainSaveImageGetXMLDesc()
+ * and virDomainSaveImageDefineXML().
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainSave(virDomainPtr domain, const char *to)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "to=%s", to);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(to, error);
+
+    if (conn->driver->domainSave) {
+        int ret;
+        char *absolute_to;
+
+        /* We must absolutize the file path as the save is done out of process */
+        if (virFileAbsPath(to, &absolute_to) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("could not build absolute output file path"));
+            goto error;
+        }
+
+        ret = conn->driver->domainSave(domain, absolute_to);
+
+        VIR_FREE(absolute_to);
+
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSaveFlags:
+ * @domain: a domain object
+ * @to: path for the output file
+ * @dxml: (optional) XML config for adjusting guest xml used on restore
+ * @flags: bitwise-OR of virDomainSaveRestoreFlags
+ *
+ * This method will suspend a domain and save its memory contents to
+ * a file on disk. After the call, if successful, the domain is not
+ * listed as running anymore (this ends the life of a transient domain).
+ * Use virDomainRestore() to restore a domain after saving.
+ *
+ * If the hypervisor supports it, @dxml can be used to alter
+ * host-specific portions of the domain XML that will be used when
+ * restoring an image.  For example, it is possible to alter the
+ * backing filename that is associated with a disk device, in order to
+ * prepare for file renaming done as part of backing up the disk
+ * device while the domain is stopped.
+ *
+ * If @flags includes VIR_DOMAIN_SAVE_BYPASS_CACHE, then libvirt will
+ * attempt to bypass the file system cache while creating the file, or
+ * fail if it cannot do so for the given system; this can allow less
+ * pressure on file system cache, but also risks slowing saves to NFS.
+ *
+ * Normally, the saved state file will remember whether the domain was
+ * running or paused, and restore defaults to the same state.
+ * Specifying VIR_DOMAIN_SAVE_RUNNING or VIR_DOMAIN_SAVE_PAUSED in
+ * @flags will override what state gets saved into the file.  These
+ * two flags are mutually exclusive.
+ *
+ * A save file can be inspected or modified slightly with
+ * virDomainSaveImageGetXMLDesc() and virDomainSaveImageDefineXML().
+ *
+ * Some hypervisors may prevent this operation if there is a current
+ * block copy operation; in that case, use virDomainBlockJobAbort()
+ * to stop the block copy first.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainSaveFlags(virDomainPtr domain, const char *to,
+                   const char *dxml, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "to=%s, dxml=%s, flags=%x",
+                     to, NULLSTR(dxml), flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(to, error);
+
+    if ((flags & VIR_DOMAIN_SAVE_RUNNING) && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
+        virReportInvalidArg(flags, "%s",
+                            _("running and paused flags are mutually "
+                              "exclusive"));
+        goto error;
+    }
+
+    if (conn->driver->domainSaveFlags) {
+        int ret;
+        char *absolute_to;
+
+        /* We must absolutize the file path as the save is done out of process */
+        if (virFileAbsPath(to, &absolute_to) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("could not build absolute output file path"));
+            goto error;
+        }
+
+        ret = conn->driver->domainSaveFlags(domain, absolute_to, dxml, flags);
+
+        VIR_FREE(absolute_to);
+
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainRestore:
+ * @conn: pointer to the hypervisor connection
+ * @from: path to the input file
+ *
+ * This method will restore a domain saved to disk by virDomainSave().
+ *
+ * See virDomainRestoreFlags() for more control.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainRestore(virConnectPtr conn, const char *from)
+{
+    VIR_DEBUG("conn=%p, from=%s", conn, from);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(from, error);
+
+    if (conn->driver->domainRestore) {
+        int ret;
+        char *absolute_from;
+
+        /* We must absolutize the file path as the restore is done out of process */
+        if (virFileAbsPath(from, &absolute_from) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("could not build absolute input file path"));
+            goto error;
+        }
+
+        ret = conn->driver->domainRestore(conn, absolute_from);
+
+        VIR_FREE(absolute_from);
+
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainRestoreFlags:
+ * @conn: pointer to the hypervisor connection
+ * @from: path to the input file
+ * @dxml: (optional) XML config for adjusting guest xml used on restore
+ * @flags: bitwise-OR of virDomainSaveRestoreFlags
+ *
+ * This method will restore a domain saved to disk by virDomainSave().
+ *
+ * If the hypervisor supports it, @dxml can be used to alter
+ * host-specific portions of the domain XML that will be used when
+ * restoring an image.  For example, it is possible to alter the
+ * backing filename that is associated with a disk device, in order to
+ * prepare for file renaming done as part of backing up the disk
+ * device while the domain is stopped.
+ *
+ * If @flags includes VIR_DOMAIN_SAVE_BYPASS_CACHE, then libvirt will
+ * attempt to bypass the file system cache while restoring the file, or
+ * fail if it cannot do so for the given system; this can allow less
+ * pressure on file system cache, but also risks slowing restores from NFS.
+ *
+ * Normally, the saved state file will remember whether the domain was
+ * running or paused, and restore defaults to the same state.
+ * Specifying VIR_DOMAIN_SAVE_RUNNING or VIR_DOMAIN_SAVE_PAUSED in
+ * @flags will override the default read from the file.  These two
+ * flags are mutually exclusive.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainRestoreFlags(virConnectPtr conn, const char *from, const char *dxml,
+                      unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, from=%s, dxml=%s, flags=%x",
+              conn, from, NULLSTR(dxml), flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(from, error);
+
+    if ((flags & VIR_DOMAIN_SAVE_RUNNING) && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
+        virReportInvalidArg(flags, "%s",
+                            _("running and paused flags are mutually "
+                              "exclusive"));
+        goto error;
+    }
+
+    if (conn->driver->domainRestoreFlags) {
+        int ret;
+        char *absolute_from;
+
+        /* We must absolutize the file path as the restore is done out of process */
+        if (virFileAbsPath(from, &absolute_from) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("could not build absolute input file path"));
+            goto error;
+        }
+
+        ret = conn->driver->domainRestoreFlags(conn, absolute_from, dxml,
+                                               flags);
+
+        VIR_FREE(absolute_from);
+
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSaveImageGetXMLDesc:
+ * @conn: pointer to the hypervisor connection
+ * @file: path to saved state file
+ * @flags: bitwise-OR of subset of virDomainXMLFlags
+ *
+ * This method will extract the XML describing the domain at the time
+ * a saved state file was created.  @file must be a file created
+ * previously by virDomainSave() or virDomainSaveFlags().
+ *
+ * No security-sensitive data will be included unless @flags contains
+ * VIR_DOMAIN_XML_SECURE; this flag is rejected on read-only
+ * connections.  For this API, @flags should not contain either
+ * VIR_DOMAIN_XML_INACTIVE or VIR_DOMAIN_XML_UPDATE_CPU.
+ *
+ * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of
+ * error.  The caller must free() the returned value.
+ */
+char *
+virDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *file,
+                             unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, file=%s, flags=%x",
+              conn, file, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(file, error);
+
+    if ((conn->flags & VIR_CONNECT_RO) && (flags & VIR_DOMAIN_XML_SECURE)) {
+        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
+                       _("virDomainSaveImageGetXMLDesc with secure flag"));
+        goto error;
+    }
+
+    if (conn->driver->domainSaveImageGetXMLDesc) {
+        char *ret;
+        char *absolute_file;
+
+        /* We must absolutize the file path as the read is done out of process */
+        if (virFileAbsPath(file, &absolute_file) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("could not build absolute input file path"));
+            goto error;
+        }
+
+        ret = conn->driver->domainSaveImageGetXMLDesc(conn, absolute_file,
+                                                      flags);
+
+        VIR_FREE(absolute_file);
+
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainSaveImageDefineXML:
+ * @conn: pointer to the hypervisor connection
+ * @file: path to saved state file
+ * @dxml: XML config for adjusting guest xml used on restore
+ * @flags: bitwise-OR of virDomainSaveRestoreFlags
+ *
+ * This updates the definition of a domain stored in a saved state
+ * file.  @file must be a file created previously by virDomainSave()
+ * or virDomainSaveFlags().
+ *
+ * @dxml can be used to alter host-specific portions of the domain XML
+ * that will be used when restoring an image.  For example, it is
+ * possible to alter the backing filename that is associated with a
+ * disk device, to match renaming done as part of backing up the disk
+ * device while the domain is stopped.
+ *
+ * Normally, the saved state file will remember whether the domain was
+ * running or paused, and restore defaults to the same state.
+ * Specifying VIR_DOMAIN_SAVE_RUNNING or VIR_DOMAIN_SAVE_PAUSED in
+ * @flags will override the default saved into the file; omitting both
+ * leaves the file's default unchanged.  These two flags are mutually
+ * exclusive.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainSaveImageDefineXML(virConnectPtr conn, const char *file,
+                            const char *dxml, unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, file=%s, dxml=%s, flags=%x",
+              conn, file, dxml, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(file, error);
+    virCheckNonNullArgGoto(dxml, error);
+
+    if ((flags & VIR_DOMAIN_SAVE_RUNNING) && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
+        virReportInvalidArg(flags, "%s",
+                            _("running and paused flags are mutually "
+                              "exclusive"));
+        goto error;
+    }
+
+    if (conn->driver->domainSaveImageDefineXML) {
+        int ret;
+        char *absolute_file;
+
+        /* We must absolutize the file path as the read is done out of process */
+        if (virFileAbsPath(file, &absolute_file) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("could not build absolute input file path"));
+            goto error;
+        }
+
+        ret = conn->driver->domainSaveImageDefineXML(conn, absolute_file,
+                                                     dxml, flags);
+
+        VIR_FREE(absolute_file);
+
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainCoreDump:
+ * @domain: a domain object
+ * @to: path for the core file
+ * @flags: bitwise-OR of virDomainCoreDumpFlags
+ *
+ * This method will dump the core of a domain on a given file for analysis.
+ * Note that for remote Xen Daemon the file path will be interpreted in
+ * the remote host. Hypervisors may require  the user to manually ensure
+ * proper permissions on the file named by @to.
+ *
+ * If @flags includes VIR_DUMP_CRASH, then leave the guest shut off with
+ * a crashed state after the dump completes.  If @flags includes
+ * VIR_DUMP_LIVE, then make the core dump while continuing to allow
+ * the guest to run; otherwise, the guest is suspended during the dump.
+ * VIR_DUMP_RESET flag forces reset of the guest after dump.
+ * The above three flags are mutually exclusive.
+ *
+ * Additionally, if @flags includes VIR_DUMP_BYPASS_CACHE, then libvirt
+ * will attempt to bypass the file system cache while creating the file,
+ * or fail if it cannot do so for the given system; this can allow less
+ * pressure on file system cache, but also risks slowing saves to NFS.
+ *
+ * For more control over the output format, see virDomainCoreDumpWithFormat().
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainCoreDump(virDomainPtr domain, const char *to, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "to=%s, flags=%x", to, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(to, error);
+
+    if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_LIVE)) {
+        virReportInvalidArg(flags, "%s",
+                            _("crash and live flags are mutually exclusive"));
+        goto error;
+    }
+
+    if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_RESET)) {
+        virReportInvalidArg(flags, "%s",
+                         _("crash and reset flags are mutually exclusive"));
+        goto error;
+    }
+
+    if ((flags & VIR_DUMP_LIVE) && (flags & VIR_DUMP_RESET)) {
+        virReportInvalidArg(flags, "%s",
+                            _("live and reset flags are mutually exclusive"));
+        goto error;
+    }
+
+    if (conn->driver->domainCoreDump) {
+        int ret;
+        char *absolute_to;
+
+        /* We must absolutize the file path as the save is done out of process */
+        if (virFileAbsPath(to, &absolute_to) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("could not build absolute core file path"));
+            goto error;
+        }
+
+        ret = conn->driver->domainCoreDump(domain, absolute_to, flags);
+
+        VIR_FREE(absolute_to);
+
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+/**
+ * virDomainCoreDumpWithFormat:
+ * @domain: a domain object
+ * @to: path for the core file
+ * @dumpformat: format of domain memory's dump
+ * @flags: bitwise-OR of virDomainCoreDumpFlags
+ *
+ * This method will dump the core of a domain on a given file for analysis.
+ * Note that for remote Xen Daemon the file path will be interpreted in
+ * the remote host. Hypervisors may require  the user to manually ensure
+ * proper permissions on the file named by @to.
+ *
+ * @dumpformat controls which format the dump will have; use of
+ * VIR_DOMAIN_CORE_DUMP_FORMAT_RAW mirrors what virDomainCoreDump() will
+ * perform.  Not all hypervisors are able to support all formats.
+ *
+ * If @flags includes VIR_DUMP_CRASH, then leave the guest shut off with
+ * a crashed state after the dump completes.  If @flags includes
+ * VIR_DUMP_LIVE, then make the core dump while continuing to allow
+ * the guest to run; otherwise, the guest is suspended during the dump.
+ * VIR_DUMP_RESET flag forces reset of the guest after dump.
+ * The above three flags are mutually exclusive.
+ *
+ * Additionally, if @flags includes VIR_DUMP_BYPASS_CACHE, then libvirt
+ * will attempt to bypass the file system cache while creating the file,
+ * or fail if it cannot do so for the given system; this can allow less
+ * pressure on file system cache, but also risks slowing saves to NFS.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainCoreDumpWithFormat(virDomainPtr domain, const char *to,
+                            unsigned int dumpformat, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "to=%s, dumpformat=%u, flags=%x",
+                     to, dumpformat, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(to, error);
+
+    if (dumpformat >= VIR_DOMAIN_CORE_DUMP_FORMAT_LAST) {
+        virReportInvalidArg(flags, _("dumpformat '%d' is not supported"),
+                            dumpformat);
+        goto error;
+    }
+
+    if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_LIVE)) {
+        virReportInvalidArg(flags, "%s",
+                            _("crash and live flags are mutually exclusive"));
+        goto error;
+    }
+
+    if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_RESET)) {
+        virReportInvalidArg(flags, "%s",
+                            _("crash and reset flags are mutually exclusive"));
+        goto error;
+    }
+
+    if ((flags & VIR_DUMP_LIVE) && (flags & VIR_DUMP_RESET)) {
+        virReportInvalidArg(flags, "%s",
+                            _("live and reset flags are mutually exclusive"));
+        goto error;
+    }
+
+    if (conn->driver->domainCoreDumpWithFormat) {
+        int ret;
+        char *absolute_to;
+
+        /* We must absolutize the file path as the save is done out of process */
+        if (virFileAbsPath(to, &absolute_to) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("could not build absolute core file path"));
+            goto error;
+        }
+
+        ret = conn->driver->domainCoreDumpWithFormat(domain, absolute_to,
+                                                     dumpformat, flags);
+
+        VIR_FREE(absolute_to);
+
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainScreenshot:
+ * @domain: a domain object
+ * @stream: stream to use as output
+ * @screen: monitor ID to take screenshot from
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Take a screenshot of current domain console as a stream. The image format
+ * is hypervisor specific. Moreover, some hypervisors supports multiple
+ * displays per domain. These can be distinguished by @screen argument.
+ *
+ * This call sets up a stream; subsequent use of stream API is necessary
+ * to transfer actual data, determine how much data is successfully
+ * transferred, and detect any errors.
+ *
+ * The screen ID is the sequential number of screen. In case of multiple
+ * graphics cards, heads are enumerated before devices, e.g. having
+ * two graphics cards, both with four heads, screen ID 5 addresses
+ * the second head on the second card.
+ *
+ * Returns a string representing the mime-type of the image format, or
+ * NULL upon error. The caller must free() the returned value.
+ */
+char *
+virDomainScreenshot(virDomainPtr domain,
+                    virStreamPtr stream,
+                    unsigned int screen,
+                    unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(domain, "stream=%p, flags=%x", stream, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+    virCheckStreamGoto(stream, error);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+
+    if (domain->conn != stream->conn) {
+        virReportInvalidArg(stream,
+                            _("stream in %s must match connection of domain '%s'"),
+                            __FUNCTION__, domain->name);
+        goto error;
+    }
+
+    if (domain->conn->driver->domainScreenshot) {
+        char *ret;
+        ret = domain->conn->driver->domainScreenshot(domain, stream,
+                                                     screen, flags);
+
+        if (ret == NULL)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainShutdown:
+ * @domain: a domain object
+ *
+ * Shutdown a domain, the domain object is still usable thereafter, but
+ * the domain OS is being stopped. Note that the guest OS may ignore the
+ * request. Additionally, the hypervisor may check and support the domain
+ * 'on_poweroff' XML setting resulting in a domain that reboots instead of
+ * shutting down. For guests that react to a shutdown request, the differences
+ * from virDomainDestroy() are that the guests disk storage will be in a
+ * stable state rather than having the (virtual) power cord pulled, and
+ * this command returns as soon as the shutdown request is issued rather
+ * than blocking until the guest is no longer running.
+ *
+ * If the domain is transient and has any snapshot metadata (see
+ * virDomainSnapshotNum()), then that metadata will automatically
+ * be deleted when the domain quits.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainShutdown(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainShutdown) {
+        int ret;
+        ret = conn->driver->domainShutdown(domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainShutdownFlags:
+ * @domain: a domain object
+ * @flags: bitwise-OR of virDomainShutdownFlagValues
+ *
+ * Shutdown a domain, the domain object is still usable thereafter but
+ * the domain OS is being stopped. Note that the guest OS may ignore the
+ * request. Additionally, the hypervisor may check and support the domain
+ * 'on_poweroff' XML setting resulting in a domain that reboots instead of
+ * shutting down. For guests that react to a shutdown request, the differences
+ * from virDomainDestroy() are that the guest's disk storage will be in a
+ * stable state rather than having the (virtual) power cord pulled, and
+ * this command returns as soon as the shutdown request is issued rather
+ * than blocking until the guest is no longer running.
+ *
+ * If the domain is transient and has any snapshot metadata (see
+ * virDomainSnapshotNum()), then that metadata will automatically
+ * be deleted when the domain quits.
+ *
+ * If @flags is set to zero, then the hypervisor will choose the
+ * method of shutdown it considers best. To have greater control
+ * pass one or more of the virDomainShutdownFlagValues. The order
+ * in which the hypervisor tries each shutdown method is undefined,
+ * and a hypervisor is not required to support all methods.
+ *
+ * To use guest agent (VIR_DOMAIN_SHUTDOWN_GUEST_AGENT) the domain XML
+ * must have <channel> configured.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainShutdownFlags) {
+        int ret;
+        ret = conn->driver->domainShutdownFlags(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainReboot:
+ * @domain: a domain object
+ * @flags: bitwise-OR of virDomainRebootFlagValues
+ *
+ * Reboot a domain, the domain object is still usable thereafter, but
+ * the domain OS is being stopped for a restart.
+ * Note that the guest OS may ignore the request.
+ * Additionally, the hypervisor may check and support the domain
+ * 'on_reboot' XML setting resulting in a domain that shuts down instead
+ * of rebooting.
+ *
+ * If @flags is set to zero, then the hypervisor will choose the
+ * method of shutdown it considers best. To have greater control
+ * pass one or more of the virDomainRebootFlagValues. The order
+ * in which the hypervisor tries each shutdown method is undefined,
+ * and a hypervisor is not required to support all methods.
+ *
+ * To use guest agent (VIR_DOMAIN_REBOOT_GUEST_AGENT) the domain XML
+ * must have <channel> configured.
+ *
+ * Due to implementation limitations in some drivers (the qemu driver,
+ * for instance) it is not advised to migrate or save a guest that is
+ * rebooting as a result of this API. Migrating such a guest can lead
+ * to a plain shutdown on the destination.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainReboot(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainReboot) {
+        int ret;
+        ret = conn->driver->domainReboot(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainReset:
+ * @domain: a domain object
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Reset a domain immediately without any guest OS shutdown.
+ * Reset emulates the power reset button on a machine, where all
+ * hardware sees the RST line set and reinitializes internal state.
+ *
+ * Note that there is a risk of data loss caused by reset without any
+ * guest OS shutdown.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainReset(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainReset) {
+        int ret;
+        ret = conn->driver->domainReset(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetName:
+ * @domain: a domain object
+ *
+ * Get the public name for that domain
+ *
+ * Returns a pointer to the name or NULL, the string need not be deallocated
+ * its lifetime will be the same as the domain object.
+ */
+const char *
+virDomainGetName(virDomainPtr domain)
+{
+    VIR_DEBUG("domain=%p", domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+
+    return domain->name;
+}
+
+
+/**
+ * virDomainGetUUID:
+ * @domain: a domain object
+ * @uuid: pointer to a VIR_UUID_BUFLEN bytes array
+ *
+ * Get the UUID for a domain
+ *
+ * Returns -1 in case of error, 0 in case of success
+ */
+int
+virDomainGetUUID(virDomainPtr domain, unsigned char *uuid)
+{
+    VIR_DOMAIN_DEBUG(domain, "uuid=%p", uuid);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(uuid, error);
+
+    memcpy(uuid, &domain->uuid[0], VIR_UUID_BUFLEN);
+
+    return 0;
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetUUIDString:
+ * @domain: a domain object
+ * @buf: pointer to a VIR_UUID_STRING_BUFLEN bytes array
+ *
+ * Get the UUID for a domain as string. For more information about
+ * UUID see RFC4122.
+ *
+ * Returns -1 in case of error, 0 in case of success
+ */
+int
+virDomainGetUUIDString(virDomainPtr domain, char *buf)
+{
+    VIR_DOMAIN_DEBUG(domain, "buf=%p", buf);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(buf, error);
+
+    virUUIDFormat(domain->uuid, buf);
+    return 0;
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetID:
+ * @domain: a domain object
+ *
+ * Get the hypervisor ID number for the domain
+ *
+ * Returns the domain ID number or (unsigned int) -1 in case of error
+ */
+unsigned int
+virDomainGetID(virDomainPtr domain)
+{
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, (unsigned int)-1);
+
+    return domain->id;
+}
+
+
+/**
+ * virDomainGetOSType:
+ * @domain: a domain object
+ *
+ * Get the type of domain operation system.
+ *
+ * Returns the new string or NULL in case of error, the string must be
+ *         freed by the caller.
+ */
+char *
+virDomainGetOSType(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+    conn = domain->conn;
+
+    if (conn->driver->domainGetOSType) {
+        char *ret;
+        ret = conn->driver->domainGetOSType(domain);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainGetMaxMemory:
+ * @domain: a domain object or NULL
+ *
+ * Retrieve the maximum amount of physical memory allocated to a
+ * domain. If domain is NULL, then this get the amount of memory reserved
+ * to Domain0 i.e. the domain where the application runs.
+ *
+ * Returns the memory size in kibibytes (blocks of 1024 bytes), or 0 in
+ * case of error.
+ */
+unsigned long
+virDomainGetMaxMemory(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, 0);
+    conn = domain->conn;
+
+    if (conn->driver->domainGetMaxMemory) {
+        unsigned long long ret;
+        ret = conn->driver->domainGetMaxMemory(domain);
+        if (ret == 0)
+            goto error;
+        if ((unsigned long) ret != ret) {
+            virReportError(VIR_ERR_OVERFLOW, _("result too large: %llu"),
+                           ret);
+            goto error;
+        }
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return 0;
+}
+
+
+/**
+ * virDomainSetMaxMemory:
+ * @domain: a domain object or NULL
+ * @memory: the memory size in kibibytes (blocks of 1024 bytes)
+ *
+ * Dynamically change the maximum amount of physical memory allocated to a
+ * domain. If domain is NULL, then this change the amount of memory reserved
+ * to Domain0 i.e. the domain where the application runs.
+ * This function may require privileged access to the hypervisor.
+ *
+ * This command is hypervisor-specific for whether active, persistent,
+ * or both configurations are changed; for more control, use
+ * virDomainSetMemoryFlags().
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "memory=%lu", memory);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonZeroArgGoto(memory, error);
+
+    if (conn->driver->domainSetMaxMemory) {
+        int ret;
+        ret = conn->driver->domainSetMaxMemory(domain, memory);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetMemory:
+ * @domain: a domain object or NULL
+ * @memory: the memory size in kibibytes (blocks of 1024 bytes)
+ *
+ * Dynamically change the target amount of physical memory allocated to a
+ * domain. If domain is NULL, then this change the amount of memory reserved
+ * to Domain0 i.e. the domain where the application runs.
+ * This function may require privileged access to the hypervisor.
+ *
+ * This command only changes the runtime configuration of the domain,
+ * so can only be called on an active domain.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainSetMemory(virDomainPtr domain, unsigned long memory)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "memory=%lu", memory);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonZeroArgGoto(memory, error);
+
+    if (conn->driver->domainSetMemory) {
+        int ret;
+        ret = conn->driver->domainSetMemory(domain, memory);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetMemoryFlags:
+ * @domain: a domain object or NULL
+ * @memory: the memory size in kibibytes (blocks of 1024 bytes)
+ * @flags: bitwise-OR of virDomainMemoryModFlags
+ *
+ * Dynamically change the target amount of physical memory allocated to a
+ * domain. If domain is NULL, then this change the amount of memory reserved
+ * to Domain0 i.e. the domain where the application runs.
+ * This function may require privileged access to the hypervisor.
+ *
+ * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG.
+ * Both flags may be set. If VIR_DOMAIN_AFFECT_LIVE is set, the change affects
+ * a running domain and will fail if domain is not active.
+ * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state,
+ * and will fail for transient domains. If neither flag is specified
+ * (that is, @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain
+ * modifies persistent setup, while an active domain is hypervisor-dependent
+ * on whether just live or both live and persistent state is changed.
+ * If VIR_DOMAIN_MEM_MAXIMUM is set, the change affects domain's maximum memory
+ * size rather than current memory size.
+ * Not all hypervisors can support all flag combinations.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainSetMemoryFlags(virDomainPtr domain, unsigned long memory,
+                        unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "memory=%lu, flags=%x", memory, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonZeroArgGoto(memory, error);
+
+    if (conn->driver->domainSetMemoryFlags) {
+        int ret;
+        ret = conn->driver->domainSetMemoryFlags(domain, memory, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetMemoryStatsPeriod:
+ * @domain: a domain object or NULL
+ * @period: the period in seconds for stats collection
+ * @flags: bitwise-OR of virDomainMemoryModFlags
+ *
+ * Dynamically change the domain memory balloon driver statistics collection
+ * period. Use 0 to disable and a positive value to enable.
+ *
+ * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG.
+ * Both flags may be set. If VIR_DOMAIN_AFFECT_LIVE is set, the change affects
+ * a running domain and will fail if domain is not active.
+ * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state,
+ * and will fail for transient domains. If neither flag is specified
+ * (that is, @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain
+ * modifies persistent setup, while an active domain is hypervisor-dependent
+ * on whether just live or both live and persistent state is changed.
+ *
+ * Not all hypervisors can support all flag combinations.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainSetMemoryStatsPeriod(virDomainPtr domain, int period,
+                              unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "peroid=%d, flags=%x", period, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    /* This must be positive to set the balloon collection period */
+    virCheckNonNegativeArgGoto(period, error);
+
+    if (conn->driver->domainSetMemoryStatsPeriod) {
+        int ret;
+        ret = conn->driver->domainSetMemoryStatsPeriod(domain, period, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetMemoryParameters:
+ * @domain: pointer to domain object
+ * @params: pointer to memory parameter objects
+ * @nparams: number of memory parameter (this value can be the same or
+ *          less than the number of parameters supported)
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Change all or a subset of the memory tunables.
+ * This function may require privileged access to the hypervisor.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainSetMemoryParameters(virDomainPtr domain,
+                             virTypedParameterPtr params,
+                             int nparams, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
+                     params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(params, error);
+    virCheckPositiveArgGoto(nparams, error);
+
+    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
+        goto error;
+
+    if (conn->driver->domainSetMemoryParameters) {
+        int ret;
+        ret = conn->driver->domainSetMemoryParameters(domain, params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetMemoryParameters:
+ * @domain: pointer to domain object
+ * @params: pointer to memory parameter object
+ *          (return value, allocated by the caller)
+ * @nparams: pointer to number of memory parameters; input and output
+ * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
+ *
+ * Get all memory parameters.  On input, @nparams gives the size of the
+ * @params array; on output, @nparams gives how many slots were filled
+ * with parameter information, which might be less but will not exceed
+ * the input value.
+ *
+ * As a special case, calling with @params as NULL and @nparams as 0 on
+ * input will cause @nparams on output to contain the number of parameters
+ * supported by the hypervisor. The caller should then allocate @params
+ * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
+ * again.
+ *
+ * Here is a sample code snippet:
+ *
+ *   if (virDomainGetMemoryParameters(dom, NULL, &nparams, 0) == 0 &&
+ *       nparams != 0) {
+ *       if ((params = malloc(sizeof(*params) * nparams)) == NULL)
+ *           goto error;
+ *       memset(params, 0, sizeof(*params) * nparams);
+ *       if (virDomainGetMemoryParameters(dom, params, &nparams, 0))
+ *           goto error;
+ *   }
+ *
+ * This function may require privileged access to the hypervisor. This function
+ * expects the caller to allocate the @params.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainGetMemoryParameters(virDomainPtr domain,
+                             virTypedParameterPtr params,
+                             int *nparams, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
+                     params, (nparams) ? *nparams : -1, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (*nparams != 0)
+        virCheckNonNullArgGoto(params, error);
+
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        virReportInvalidArg(flags,
+                            _("flags 'affect live' and 'affect config' in %s "
+                              "are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainGetMemoryParameters) {
+        int ret;
+        ret = conn->driver->domainGetMemoryParameters(domain, params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetNumaParameters:
+ * @domain: pointer to domain object
+ * @params: pointer to numa parameter objects
+ * @nparams: number of numa parameters (this value can be the same or
+ *          less than the number of parameters supported)
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Change all or a subset of the numa tunables.
+ * This function may require privileged access to the hypervisor.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainSetNumaParameters(virDomainPtr domain,
+                           virTypedParameterPtr params,
+                           int nparams, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
+                     params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+    virCheckNonNullArgGoto(params, error);
+    virCheckPositiveArgGoto(nparams, error);
+    if (virTypedParameterValidateSet(domain->conn, params, nparams) < 0)
+        goto error;
+
+    conn = domain->conn;
+
+    if (conn->driver->domainSetNumaParameters) {
+        int ret;
+        ret = conn->driver->domainSetNumaParameters(domain, params, nparams,
+                                                    flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetNumaParameters:
+ * @domain: pointer to domain object
+ * @params: pointer to numa parameter object
+ *          (return value, allocated by the caller)
+ * @nparams: pointer to number of numa parameters
+ * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
+ *
+ * Get all numa parameters.  On input, @nparams gives the size of the
+ * @params array; on output, @nparams gives how many slots were filled
+ * with parameter information, which might be less but will not exceed
+ * the input value.
+ *
+ * As a special case, calling with @params as NULL and @nparams as 0 on
+ * input will cause @nparams on output to contain the number of parameters
+ * supported by the hypervisor. The caller should then allocate @params
+ * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
+ * again.
+ *
+ * See virDomainGetMemoryParameters() for an equivalent usage example.
+ *
+ * This function may require privileged access to the hypervisor. This function
+ * expects the caller to allocate the @params.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainGetNumaParameters(virDomainPtr domain,
+                           virTypedParameterPtr params,
+                           int *nparams, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
+                     params, (nparams) ? *nparams : -1, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (*nparams != 0)
+        virCheckNonNullArgGoto(params, error);
+
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetNumaParameters) {
+        int ret;
+        ret = conn->driver->domainGetNumaParameters(domain, params, nparams,
+                                                    flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetBlkioParameters:
+ * @domain: pointer to domain object
+ * @params: pointer to blkio parameter objects
+ * @nparams: number of blkio parameters (this value can be the same or
+ *          less than the number of parameters supported)
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Change all or a subset of the blkio tunables.
+ * This function may require privileged access to the hypervisor.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainSetBlkioParameters(virDomainPtr domain,
+                            virTypedParameterPtr params,
+                            int nparams, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
+                     params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(params, error);
+    virCheckNonNegativeArgGoto(nparams, error);
+
+    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
+        goto error;
+
+    if (conn->driver->domainSetBlkioParameters) {
+        int ret;
+        ret = conn->driver->domainSetBlkioParameters(domain, params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetBlkioParameters:
+ * @domain: pointer to domain object
+ * @params: pointer to blkio parameter object
+ *          (return value, allocated by the caller)
+ * @nparams: pointer to number of blkio parameters; input and output
+ * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
+ *
+ * Get all blkio parameters.  On input, @nparams gives the size of the
+ * @params array; on output, @nparams gives how many slots were filled
+ * with parameter information, which might be less but will not exceed
+ * the input value.
+ *
+ * As a special case, calling with @params as NULL and @nparams as 0 on
+ * input will cause @nparams on output to contain the number of parameters
+ * supported by the hypervisor. The caller should then allocate @params
+ * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
+ * again.
+ *
+ * See virDomainGetMemoryParameters() for an equivalent usage example.
+ *
+ * This function may require privileged access to the hypervisor. This function
+ * expects the caller to allocate the @params.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainGetBlkioParameters(virDomainPtr domain,
+                            virTypedParameterPtr params,
+                            int *nparams, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
+                     params, (nparams) ? *nparams : -1, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (*nparams != 0)
+        virCheckNonNullArgGoto(params, error);
+
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        virReportInvalidArg(flags,
+                            _("flags 'affect live' and 'affect config' in %s "
+                              "are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainGetBlkioParameters) {
+        int ret;
+        ret = conn->driver->domainGetBlkioParameters(domain, params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetInfo:
+ * @domain: a domain object
+ * @info: pointer to a virDomainInfo structure allocated by the user
+ *
+ * Extract information about a domain. Note that if the connection
+ * used to get the domain is limited only a partial set of the information
+ * can be extracted.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "info=%p", info);
+
+    virResetLastError();
+
+    if (info)
+        memset(info, 0, sizeof(*info));
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(info, error);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetInfo) {
+        int ret;
+        ret = conn->driver->domainGetInfo(domain, info);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetState:
+ * @domain: a domain object
+ * @state: returned state of the domain (one of virDomainState)
+ * @reason: returned reason which led to @state (one of virDomain*Reason
+ * corresponding to the current state); it is allowed to be NULL
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Extract domain state. Each state can be accompanied with a reason (if known)
+ * which led to the state.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainGetState(virDomainPtr domain,
+                  int *state,
+                  int *reason,
+                  unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "state=%p, reason=%p, flags=%x",
+                     state, reason, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(state, error);
+
+    conn = domain->conn;
+    if (conn->driver->domainGetState) {
+        int ret;
+        ret = conn->driver->domainGetState(domain, state, reason, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetControlInfo:
+ * @domain: a domain object
+ * @info: pointer to a virDomainControlInfo structure allocated by the user
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Extract details about current state of control interface to a domain.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainGetControlInfo(virDomainPtr domain,
+                        virDomainControlInfoPtr info,
+                        unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "info=%p, flags=%x", info, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(info, error);
+
+    conn = domain->conn;
+    if (conn->driver->domainGetControlInfo) {
+        int ret;
+        ret = conn->driver->domainGetControlInfo(domain, info, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetXMLDesc:
+ * @domain: a domain object
+ * @flags: bitwise-OR of virDomainXMLFlags
+ *
+ * Provide an XML description of the domain. The description may be reused
+ * later to relaunch the domain with virDomainCreateXML().
+ *
+ * No security-sensitive data will be included unless @flags contains
+ * VIR_DOMAIN_XML_SECURE; this flag is rejected on read-only
+ * connections.  If @flags includes VIR_DOMAIN_XML_INACTIVE, then the
+ * XML represents the configuration that will be used on the next boot
+ * of a persistent domain; otherwise, the configuration represents the
+ * currently running domain.  If @flags contains
+ * VIR_DOMAIN_XML_UPDATE_CPU, then the portion of the domain XML
+ * describing CPU capabilities is modified to match actual
+ * capabilities of the host.
+ *
+ * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
+ *         the caller must free() the returned value.
+ */
+char *
+virDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+    conn = domain->conn;
+
+    if ((conn->flags & VIR_CONNECT_RO) && (flags & VIR_DOMAIN_XML_SECURE)) {
+        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
+                       _("virDomainGetXMLDesc with secure flag"));
+        goto error;
+    }
+
+    if (conn->driver->domainGetXMLDesc) {
+        char *ret;
+        ret = conn->driver->domainGetXMLDesc(domain, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virConnectDomainXMLFromNative:
+ * @conn: a connection object
+ * @nativeFormat: configuration format importing from
+ * @nativeConfig: the configuration data to import
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Reads native configuration data  describing a domain, and
+ * generates libvirt domain XML. The format of the native
+ * data is hypervisor dependant.
+ *
+ * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
+ *         the caller must free() the returned value.
+ */
+char *
+virConnectDomainXMLFromNative(virConnectPtr conn,
+                              const char *nativeFormat,
+                              const char *nativeConfig,
+                              unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, format=%s, config=%s, flags=%x",
+              conn, nativeFormat, nativeConfig, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    virCheckNonNullArgGoto(nativeFormat, error);
+    virCheckNonNullArgGoto(nativeConfig, error);
+
+    if (conn->driver->connectDomainXMLFromNative) {
+        char *ret;
+        ret = conn->driver->connectDomainXMLFromNative(conn,
+                                                       nativeFormat,
+                                                       nativeConfig,
+                                                       flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virConnectDomainXMLToNative:
+ * @conn: a connection object
+ * @nativeFormat: configuration format exporting to
+ * @domainXml: the domain configuration to export
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Reads a domain XML configuration document, and generates
+ * a native configuration file describing the domain.
+ * The format of the native data is hypervisor dependant.
+ *
+ * Returns a 0 terminated UTF-8 encoded native config datafile, or NULL in case of error.
+ *         the caller must free() the returned value.
+ */
+char *
+virConnectDomainXMLToNative(virConnectPtr conn,
+                            const char *nativeFormat,
+                            const char *domainXml,
+                            unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, format=%s, xml=%s, flags=%x",
+              conn, nativeFormat, domainXml, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    virCheckNonNullArgGoto(nativeFormat, error);
+    virCheckNonNullArgGoto(domainXml, error);
+
+    if (conn->driver->connectDomainXMLToNative) {
+        char *ret;
+        ret = conn->driver->connectDomainXMLToNative(conn,
+                                                     nativeFormat,
+                                                     domainXml,
+                                                     flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/*
+ * Sequence v1:
+ *
+ *  Dst: Prepare
+ *        - Get ready to accept incoming VM
+ *        - Generate optional cookie to pass to src
+ *
+ *  Src: Perform
+ *        - Start migration and wait for send completion
+ *        - Kill off VM if successful, resume if failed
+ *
+ *  Dst: Finish
+ *        - Wait for recv completion and check status
+ *        - Kill off VM if unsuccessful
+ *
+ */
+static virDomainPtr
+virDomainMigrateVersion1(virDomainPtr domain,
+                         virConnectPtr dconn,
+                         unsigned long flags,
+                         const char *dname,
+                         const char *uri,
+                         unsigned long bandwidth)
+{
+    virDomainPtr ddomain = NULL;
+    char *uri_out = NULL;
+    char *cookie = NULL;
+    int cookielen = 0, ret;
+    virDomainInfo info;
+    unsigned int destflags;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
+                     dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
+
+    ret = virDomainGetInfo(domain, &info);
+    if (ret == 0 && info.state == VIR_DOMAIN_PAUSED)
+        flags |= VIR_MIGRATE_PAUSED;
+
+    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
+                          VIR_MIGRATE_AUTO_CONVERGE);
+
+    /* Prepare the migration.
+     *
+     * The destination host may return a cookie, or leave cookie as
+     * NULL.
+     *
+     * The destination host MUST set uri_out if uri_in is NULL.
+     *
+     * If uri_in is non-NULL, then the destination host may modify
+     * the URI by setting uri_out.  If it does not wish to modify
+     * the URI, it should leave uri_out as NULL.
+     */
+    if (dconn->driver->domainMigratePrepare
+        (dconn, &cookie, &cookielen, uri, &uri_out, destflags, dname,
+         bandwidth) == -1)
+        goto done;
+
+    if (uri == NULL && uri_out == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("domainMigratePrepare did not set uri"));
+        goto done;
+    }
+    if (uri_out)
+        uri = uri_out; /* Did domainMigratePrepare change URI? */
+
+    /* Perform the migration.  The driver isn't supposed to return
+     * until the migration is complete.
+     */
+    if (domain->conn->driver->domainMigratePerform
+        (domain, cookie, cookielen, uri, flags, dname, bandwidth) == -1)
+        goto done;
+
+    /* Get the destination domain and return it or error.
+     * 'domain' no longer actually exists at this point
+     * (or so we hope), but we still use the object in memory
+     * in order to get the name.
+     */
+    dname = dname ? dname : domain->name;
+    if (dconn->driver->domainMigrateFinish)
+        ddomain = dconn->driver->domainMigrateFinish
+            (dconn, dname, cookie, cookielen, uri, destflags);
+    else
+        ddomain = virDomainLookupByName(dconn, dname);
+
+ done:
+    VIR_FREE(uri_out);
+    VIR_FREE(cookie);
+    return ddomain;
+}
+
+
+/*
+ * Sequence v2:
+ *
+ *  Src: DumpXML
+ *        - Generate XML to pass to dst
+ *
+ *  Dst: Prepare
+ *        - Get ready to accept incoming VM
+ *        - Generate optional cookie to pass to src
+ *
+ *  Src: Perform
+ *        - Start migration and wait for send completion
+ *        - Kill off VM if successful, resume if failed
+ *
+ *  Dst: Finish
+ *        - Wait for recv completion and check status
+ *        - Kill off VM if unsuccessful
+ *
+ */
+static virDomainPtr
+virDomainMigrateVersion2(virDomainPtr domain,
+                         virConnectPtr dconn,
+                         unsigned long flags,
+                         const char *dname,
+                         const char *uri,
+                         unsigned long bandwidth)
+{
+    virDomainPtr ddomain = NULL;
+    char *uri_out = NULL;
+    char *cookie = NULL;
+    char *dom_xml = NULL;
+    int cookielen = 0, ret;
+    virDomainInfo info;
+    virErrorPtr orig_err = NULL;
+    unsigned int getxml_flags = 0;
+    int cancelled;
+    unsigned long destflags;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
+                     dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
+
+    /* Prepare the migration.
+     *
+     * The destination host may return a cookie, or leave cookie as
+     * NULL.
+     *
+     * The destination host MUST set uri_out if uri_in is NULL.
+     *
+     * If uri_in is non-NULL, then the destination host may modify
+     * the URI by setting uri_out.  If it does not wish to modify
+     * the URI, it should leave uri_out as NULL.
+     */
+
+    /* In version 2 of the protocol, the prepare step is slightly
+     * different.  We fetch the domain XML of the source domain
+     * and pass it to Prepare2.
+     */
+    if (!domain->conn->driver->domainGetXMLDesc) {
+        virReportUnsupportedError();
+        return NULL;
+    }
+
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_XML_MIGRATABLE)) {
+        getxml_flags |= VIR_DOMAIN_XML_MIGRATABLE;
+    } else {
+        getxml_flags |= VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_UPDATE_CPU;
+    }
+
+    dom_xml = domain->conn->driver->domainGetXMLDesc(domain, getxml_flags);
+    if (!dom_xml)
+        return NULL;
+
+    ret = virDomainGetInfo(domain, &info);
+    if (ret == 0 && info.state == VIR_DOMAIN_PAUSED)
+        flags |= VIR_MIGRATE_PAUSED;
+
+    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
+                          VIR_MIGRATE_AUTO_CONVERGE);
+
+    VIR_DEBUG("Prepare2 %p flags=%lx", dconn, destflags);
+    ret = dconn->driver->domainMigratePrepare2
+        (dconn, &cookie, &cookielen, uri, &uri_out, destflags, dname,
+         bandwidth, dom_xml);
+    VIR_FREE(dom_xml);
+    if (ret == -1)
+        goto done;
+
+    if (uri == NULL && uri_out == NULL) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("domainMigratePrepare2 did not set uri"));
+        cancelled = 1;
+        /* Make sure Finish doesn't overwrite the error */
+        orig_err = virSaveLastError();
+        goto finish;
+    }
+    if (uri_out)
+        uri = uri_out; /* Did domainMigratePrepare2 change URI? */
+
+    /* Perform the migration.  The driver isn't supposed to return
+     * until the migration is complete.
+     */
+    VIR_DEBUG("Perform %p", domain->conn);
+    ret = domain->conn->driver->domainMigratePerform
+        (domain, cookie, cookielen, uri, flags, dname, bandwidth);
+
+    /* Perform failed. Make sure Finish doesn't overwrite the error */
+    if (ret < 0)
+        orig_err = virSaveLastError();
+
+    /* If Perform returns < 0, then we need to cancel the VM
+     * startup on the destination
+     */
+    cancelled = ret < 0 ? 1 : 0;
+
+ finish:
+    /* In version 2 of the migration protocol, we pass the
+     * status code from the sender to the destination host,
+     * so it can do any cleanup if the migration failed.
+     */
+    dname = dname ? dname : domain->name;
+    VIR_DEBUG("Finish2 %p ret=%d", dconn, ret);
+    ddomain = dconn->driver->domainMigrateFinish2
+        (dconn, dname, cookie, cookielen, uri, destflags, cancelled);
+    if (cancelled && ddomain)
+        VIR_ERROR(_("finish step ignored that migration was cancelled"));
+
+ done:
+    if (orig_err) {
+        virSetError(orig_err);
+        virFreeError(orig_err);
+    }
+    VIR_FREE(uri_out);
+    VIR_FREE(cookie);
+    return ddomain;
+}
+
+
+/*
+ * Sequence v3:
+ *
+ *  Src: Begin
+ *        - Generate XML to pass to dst
+ *        - Generate optional cookie to pass to dst
+ *
+ *  Dst: Prepare
+ *        - Get ready to accept incoming VM
+ *        - Generate optional cookie to pass to src
+ *
+ *  Src: Perform
+ *        - Start migration and wait for send completion
+ *        - Generate optional cookie to pass to dst
+ *
+ *  Dst: Finish
+ *        - Wait for recv completion and check status
+ *        - Kill off VM if failed, resume if success
+ *        - Generate optional cookie to pass to src
+ *
+ *  Src: Confirm
+ *        - Kill off VM if success, resume if failed
+ *
+  * If useParams is true, params and nparams contain migration parameters and
+  * we know it's safe to call the API which supports extensible parameters.
+  * Otherwise, we have to use xmlin, dname, uri, and bandwidth and pass them
+  * to the old-style APIs.
+ */
+static virDomainPtr
+virDomainMigrateVersion3Full(virDomainPtr domain,
+                             virConnectPtr dconn,
+                             const char *xmlin,
+                             const char *dname,
+                             const char *uri,
+                             unsigned long long bandwidth,
+                             virTypedParameterPtr params,
+                             int nparams,
+                             bool useParams,
+                             unsigned int flags)
+{
+    virDomainPtr ddomain = NULL;
+    char *uri_out = NULL;
+    char *cookiein = NULL;
+    char *cookieout = NULL;
+    char *dom_xml = NULL;
+    int cookieinlen = 0;
+    int cookieoutlen = 0;
+    int ret;
+    virDomainInfo info;
+    virErrorPtr orig_err = NULL;
+    int cancelled = 1;
+    unsigned long protection = 0;
+    bool notify_source = true;
+    unsigned int destflags;
+    int state;
+    virTypedParameterPtr tmp;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "dconn=%p, xmlin=%s, dname=%s, uri=%s, bandwidth=%llu, "
+                     "params=%p, nparams=%d, useParams=%d, flags=%x",
+                     dconn, NULLSTR(xmlin), NULLSTR(dname), NULLSTR(uri),
+                     bandwidth, params, nparams, useParams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    if ((!useParams &&
+         (!domain->conn->driver->domainMigrateBegin3 ||
+          !domain->conn->driver->domainMigratePerform3 ||
+          !domain->conn->driver->domainMigrateConfirm3 ||
+          !dconn->driver->domainMigratePrepare3 ||
+          !dconn->driver->domainMigrateFinish3)) ||
+        (useParams &&
+         (!domain->conn->driver->domainMigrateBegin3Params ||
+          !domain->conn->driver->domainMigratePerform3Params ||
+          !domain->conn->driver->domainMigrateConfirm3Params ||
+          !dconn->driver->domainMigratePrepare3Params ||
+          !dconn->driver->domainMigrateFinish3Params))) {
+        virReportUnsupportedError();
+        return NULL;
+    }
+
+    if (virTypedParamsCopy(&tmp, params, nparams) < 0)
+        return NULL;
+    params = tmp;
+
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION))
+        protection = VIR_MIGRATE_CHANGE_PROTECTION;
+
+    VIR_DEBUG("Begin3 %p", domain->conn);
+    if (useParams) {
+        dom_xml = domain->conn->driver->domainMigrateBegin3Params
+            (domain, params, nparams, &cookieout, &cookieoutlen,
+             flags | protection);
+    } else {
+        dom_xml = domain->conn->driver->domainMigrateBegin3
+            (domain, xmlin, &cookieout, &cookieoutlen,
+             flags | protection, dname, bandwidth);
+    }
+    if (!dom_xml)
+        goto done;
+
+    if (useParams) {
+        /* If source is new enough to support extensible migration parameters,
+         * it's certainly new enough to support virDomainGetState. */
+        ret = virDomainGetState(domain, &state, NULL, 0);
+    } else {
+        ret = virDomainGetInfo(domain, &info);
+        state = info.state;
+    }
+    if (ret == 0 && state == VIR_DOMAIN_PAUSED)
+        flags |= VIR_MIGRATE_PAUSED;
+
+    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
+                          VIR_MIGRATE_AUTO_CONVERGE);
+
+    VIR_DEBUG("Prepare3 %p flags=%x", dconn, destflags);
+    cookiein = cookieout;
+    cookieinlen = cookieoutlen;
+    cookieout = NULL;
+    cookieoutlen = 0;
+    if (useParams) {
+        if (virTypedParamsReplaceString(&params, &nparams,
+                                        VIR_MIGRATE_PARAM_DEST_XML,
+                                        dom_xml) < 0)
+            goto done;
+        ret = dconn->driver->domainMigratePrepare3Params
+            (dconn, params, nparams, cookiein, cookieinlen,
+             &cookieout, &cookieoutlen, &uri_out, destflags);
+    } else {
+        ret = dconn->driver->domainMigratePrepare3
+            (dconn, cookiein, cookieinlen, &cookieout, &cookieoutlen,
+             uri, &uri_out, destflags, dname, bandwidth, dom_xml);
+    }
+    if (ret == -1) {
+        if (protection) {
+            /* Begin already started a migration job so we need to cancel it by
+             * calling Confirm while making sure it doesn't overwrite the error
+             */
+            orig_err = virSaveLastError();
+            goto confirm;
+        } else {
+            goto done;
+        }
+    }
+
+    /* Did domainMigratePrepare3 change URI? */
+    if (uri_out) {
+        uri = uri_out;
+        if (useParams &&
+            virTypedParamsReplaceString(&params, &nparams,
+                                        VIR_MIGRATE_PARAM_URI,
+                                        uri_out) < 0) {
+            cancelled = 1;
+            orig_err = virSaveLastError();
+            goto finish;
+        }
+    } else if (!uri &&
+               virTypedParamsGetString(params, nparams,
+                                       VIR_MIGRATE_PARAM_URI, &uri) <= 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("domainMigratePrepare3 did not set uri"));
+        cancelled = 1;
+        orig_err = virSaveLastError();
+        goto finish;
+    }
+
+    if (flags & VIR_MIGRATE_OFFLINE) {
+        VIR_DEBUG("Offline migration, skipping Perform phase");
+        VIR_FREE(cookieout);
+        cookieoutlen = 0;
+        cancelled = 0;
+        goto finish;
+    }
+
+    /* Perform the migration.  The driver isn't supposed to return
+     * until the migration is complete. The src VM should remain
+     * running, but in paused state until the destination can
+     * confirm migration completion.
+     */
+    VIR_DEBUG("Perform3 %p uri=%s", domain->conn, uri);
+    VIR_FREE(cookiein);
+    cookiein = cookieout;
+    cookieinlen = cookieoutlen;
+    cookieout = NULL;
+    cookieoutlen = 0;
+    /* dconnuri not relevant in non-P2P modes, so left NULL here */
+    if (useParams) {
+        ret = domain->conn->driver->domainMigratePerform3Params
+            (domain, NULL, params, nparams, cookiein, cookieinlen,
+             &cookieout, &cookieoutlen, flags | protection);
+    } else {
+        ret = domain->conn->driver->domainMigratePerform3
+            (domain, NULL, cookiein, cookieinlen,
+             &cookieout, &cookieoutlen, NULL,
+             uri, flags | protection, dname, bandwidth);
+    }
+
+    /* Perform failed. Make sure Finish doesn't overwrite the error */
+    if (ret < 0) {
+        orig_err = virSaveLastError();
+        /* Perform failed so we don't need to call confirm to let source know
+         * about the failure.
+         */
+        notify_source = false;
+    }
+
+    /* If Perform returns < 0, then we need to cancel the VM
+     * startup on the destination
+     */
+    cancelled = ret < 0 ? 1 : 0;
+
+ finish:
+    /*
+     * The status code from the source is passed to the destination.
+     * The dest can cleanup if the source indicated it failed to
+     * send all migration data. Returns NULL for ddomain if
+     * the dest was unable to complete migration.
+     */
+    VIR_DEBUG("Finish3 %p ret=%d", dconn, ret);
+    VIR_FREE(cookiein);
+    cookiein = cookieout;
+    cookieinlen = cookieoutlen;
+    cookieout = NULL;
+    cookieoutlen = 0;
+    if (useParams) {
+        if (virTypedParamsGetString(params, nparams,
+                                    VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 &&
+            virTypedParamsReplaceString(&params, &nparams,
+                                        VIR_MIGRATE_PARAM_DEST_NAME,
+                                        domain->name) < 0) {
+            ddomain = NULL;
+        } else {
+            ddomain = dconn->driver->domainMigrateFinish3Params
+                (dconn, params, nparams, cookiein, cookieinlen,
+                 &cookieout, &cookieoutlen, destflags, cancelled);
+        }
+    } else {
+        dname = dname ? dname : domain->name;
+        ddomain = dconn->driver->domainMigrateFinish3
+            (dconn, dname, cookiein, cookieinlen, &cookieout, &cookieoutlen,
+             NULL, uri, destflags, cancelled);
+    }
+    if (cancelled && ddomain)
+        VIR_ERROR(_("finish step ignored that migration was cancelled"));
+
+    /* If ddomain is NULL, then we were unable to start
+     * the guest on the target, and must restart on the
+     * source. There is a small chance that the ddomain
+     * is NULL due to an RPC failure, in which case
+     * ddomain could in fact be running on the dest.
+     * The lock manager plugins should take care of
+     * safety in this scenario.
+     */
+    cancelled = ddomain == NULL ? 1 : 0;
+
+    /* If finish3 set an error, and we don't have an earlier
+     * one we need to preserve it in case confirm3 overwrites
+     */
+    if (!orig_err)
+        orig_err = virSaveLastError();
+
+ confirm:
+    /*
+     * If cancelled, then src VM will be restarted, else it will be killed.
+     * Don't do this if migration failed on source and thus it was already
+     * cancelled there.
+     */
+    if (notify_source) {
+        VIR_DEBUG("Confirm3 %p ret=%d domain=%p", domain->conn, ret, domain);
+        VIR_FREE(cookiein);
+        cookiein = cookieout;
+        cookieinlen = cookieoutlen;
+        cookieout = NULL;
+        cookieoutlen = 0;
+        if (useParams) {
+            ret = domain->conn->driver->domainMigrateConfirm3Params
+                (domain, params, nparams, cookiein, cookieinlen,
+                 flags | protection, cancelled);
+        } else {
+            ret = domain->conn->driver->domainMigrateConfirm3
+                (domain, cookiein, cookieinlen,
+                 flags | protection, cancelled);
+        }
+        /* If Confirm3 returns -1, there's nothing more we can
+         * do, but fortunately worst case is that there is a
+         * domain left in 'paused' state on source.
+         */
+        if (ret < 0) {
+            VIR_WARN("Guest %s probably left in 'paused' state on source",
+                     domain->name);
+        }
+    }
+
+ done:
+    if (orig_err) {
+        virSetError(orig_err);
+        virFreeError(orig_err);
+    }
+    VIR_FREE(dom_xml);
+    VIR_FREE(uri_out);
+    VIR_FREE(cookiein);
+    VIR_FREE(cookieout);
+    virTypedParamsFree(params, nparams);
+    return ddomain;
+}
+
+
+static virDomainPtr
+virDomainMigrateVersion3(virDomainPtr domain,
+                         virConnectPtr dconn,
+                         const char *xmlin,
+                         unsigned long flags,
+                         const char *dname,
+                         const char *uri,
+                         unsigned long bandwidth)
+{
+    return virDomainMigrateVersion3Full(domain, dconn, xmlin, dname, uri,
+                                        bandwidth, NULL, 0, false, flags);
+}
+
+
+static virDomainPtr
+virDomainMigrateVersion3Params(virDomainPtr domain,
+                               virConnectPtr dconn,
+                               virTypedParameterPtr params,
+                               int nparams,
+                               unsigned int flags)
+{
+    return virDomainMigrateVersion3Full(domain, dconn, NULL, NULL, NULL, 0,
+                                        params, nparams, true, flags);
+}
+
+
+/*
+ * In normal migration, the libvirt client co-ordinates communication
+ * between the 2 libvirtd instances on source & dest hosts.
+ *
+ * In this peer-2-peer migration alternative, the libvirt client
+ * only talks to the source libvirtd instance. The source libvirtd
+ * then opens its own connection to the destination and co-ordinates
+ * migration itself.
+ *
+ * If useParams is true, params and nparams contain migration parameters and
+ * we know it's safe to call the API which supports extensible parameters.
+ * Otherwise, we have to use xmlin, dname, uri, and bandwidth and pass them
+ * to the old-style APIs.
+ */
+static int
+virDomainMigratePeer2PeerFull(virDomainPtr domain,
+                              const char *dconnuri,
+                              const char *xmlin,
+                              const char *dname,
+                              const char *uri,
+                              unsigned long long bandwidth,
+                              virTypedParameterPtr params,
+                              int nparams,
+                              bool useParams,
+                              unsigned int flags)
+{
+    virURIPtr tempuri = NULL;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "dconnuri=%s, xmlin=%s, dname=%s, uri=%s, bandwidth=%llu "
+                     "params=%p, nparams=%d, useParams=%d, flags=%x",
+                     dconnuri, NULLSTR(xmlin), NULLSTR(dname), NULLSTR(uri),
+                     bandwidth, params, nparams, useParams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    if ((useParams && !domain->conn->driver->domainMigratePerform3Params) ||
+        (!useParams &&
+         !domain->conn->driver->domainMigratePerform &&
+         !domain->conn->driver->domainMigratePerform3)) {
+        virReportUnsupportedError();
+        return -1;
+    }
+
+    if (!(tempuri = virURIParse(dconnuri)))
+        return -1;
+    if (!tempuri->server || STRPREFIX(tempuri->server, "localhost")) {
+        virReportInvalidArg(dconnuri,
+                            _("unable to parse server from dconnuri in %s"),
+                            __FUNCTION__);
+        virURIFree(tempuri);
+        return -1;
+    }
+    virURIFree(tempuri);
+
+    if (useParams) {
+        VIR_DEBUG("Using migration protocol 3 with extensible parameters");
+        return domain->conn->driver->domainMigratePerform3Params
+                (domain, dconnuri, params, nparams,
+                 NULL, 0, NULL, NULL, flags);
+    } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                        VIR_DRV_FEATURE_MIGRATION_V3)) {
+        VIR_DEBUG("Using migration protocol 3");
+        return domain->conn->driver->domainMigratePerform3
+                (domain, xmlin, NULL, 0, NULL, NULL, dconnuri,
+                 uri, flags, dname, bandwidth);
+    } else {
+        VIR_DEBUG("Using migration protocol 2");
+        if (xmlin) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("Unable to change target guest XML during "
+                             "migration"));
+            return -1;
+        }
+        if (uri) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Unable to override peer2peer migration URI"));
+            return -1;
+        }
+        return domain->conn->driver->domainMigratePerform
+                (domain, NULL, 0, dconnuri, flags, dname, bandwidth);
+    }
+}
+
+
+static int
+virDomainMigratePeer2Peer(virDomainPtr domain,
+                          const char *xmlin,
+                          unsigned long flags,
+                          const char *dname,
+                          const char *dconnuri,
+                          const char *uri,
+                          unsigned long bandwidth)
+{
+    return virDomainMigratePeer2PeerFull(domain, dconnuri, xmlin, dname, uri,
+                                         bandwidth, NULL, 0, false, flags);
+}
+
+
+static int
+virDomainMigratePeer2PeerParams(virDomainPtr domain,
+                                const char *dconnuri,
+                                virTypedParameterPtr params,
+                                int nparams,
+                                unsigned int flags)
+{
+    return virDomainMigratePeer2PeerFull(domain, dconnuri, NULL, NULL, NULL, 0,
+                                         params, nparams, true, flags);
+}
+
+
+/*
+ * In normal migration, the libvirt client co-ordinates communication
+ * between the 2 libvirtd instances on source & dest hosts.
+ *
+ * Some hypervisors support an alternative, direct migration where
+ * there is no requirement for a libvirtd instance on the dest host.
+ * In this case
+ *
+ * eg, XenD can talk direct to XenD, so libvirtd on dest does not
+ * need to be involved at all, or even running
+ */
+static int
+virDomainMigrateDirect(virDomainPtr domain,
+                       const char *xmlin,
+                       unsigned long flags,
+                       const char *dname,
+                       const char *uri,
+                       unsigned long bandwidth)
+{
+    VIR_DOMAIN_DEBUG(domain,
+                     "xmlin=%s, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
+                     NULLSTR(xmlin), flags, NULLSTR(dname), NULLSTR(uri),
+                     bandwidth);
+
+    if (!domain->conn->driver->domainMigratePerform) {
+        virReportUnsupportedError();
+        return -1;
+    }
+
+    /* Perform the migration.  The driver isn't supposed to return
+     * until the migration is complete.
+     */
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_MIGRATION_V3)) {
+        VIR_DEBUG("Using migration protocol 3");
+        /* dconn URI not relevant in direct migration, since no
+         * target libvirtd is involved */
+        return domain->conn->driver->domainMigratePerform3(domain,
+                                                           xmlin,
+                                                           NULL, /* cookiein */
+                                                           0,    /* cookieinlen */
+                                                           NULL, /* cookieoutlen */
+                                                           NULL, /* cookieoutlen */
+                                                           NULL, /* dconnuri */
+                                                           uri,
+                                                           flags,
+                                                           dname,
+                                                           bandwidth);
+    } else {
+        VIR_DEBUG("Using migration protocol 2");
+        if (xmlin) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("Unable to change target guest XML during migration"));
+            return -1;
+        }
+        return domain->conn->driver->domainMigratePerform(domain,
+                                                          NULL, /* cookie */
+                                                          0,    /* cookielen */
+                                                          uri,
+                                                          flags,
+                                                          dname,
+                                                          bandwidth);
+    }
+}
+
+
+/**
+ * virDomainMigrate:
+ * @domain: a domain object
+ * @dconn: destination host (a connection object)
+ * @flags: bitwise-OR of virDomainMigrateFlags
+ * @dname: (optional) rename domain to this at destination
+ * @uri: (optional) dest hostname/URI as seen from the source host
+ * @bandwidth: (optional) specify migration bandwidth limit in MiB/s
+ *
+ * Migrate the domain object from its current host to the destination
+ * host given by dconn (a connection to the destination host).
+ *
+ * Flags may be one of more of the following:
+ *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
+ *   VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
+ *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
+ *   VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
+ *                            on the destination host.
+ *   VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
+ *                               domain on the source host.
+ *   VIR_MIGRATE_PAUSED    Leave the domain suspended on the remote side.
+ *   VIR_MIGRATE_NON_SHARED_DISK Migration with non-shared storage with full
+ *                               disk copy
+ *   VIR_MIGRATE_NON_SHARED_INC  Migration with non-shared storage with
+ *                               incremental disk copy
+ *   VIR_MIGRATE_CHANGE_PROTECTION Protect against domain configuration
+ *                                 changes during the migration process (set
+ *                                 automatically when supported).
+ *   VIR_MIGRATE_UNSAFE    Force migration even if it is considered unsafe.
+ *   VIR_MIGRATE_OFFLINE Migrate offline
+ *
+ * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
+ * Applications using the VIR_MIGRATE_PEER2PEER flag will probably
+ * prefer to invoke virDomainMigrateToURI, avoiding the need to
+ * open connection to the destination host themselves.
+ *
+ * If a hypervisor supports renaming domains during migration,
+ * then you may set the dname parameter to the new name (otherwise
+ * it keeps the same name).  If this is not supported by the
+ * hypervisor, dname must be NULL or else you will get an error.
+ *
+ * If the VIR_MIGRATE_PEER2PEER flag is set, the uri parameter
+ * must be a valid libvirt connection URI, by which the source
+ * libvirt driver can connect to the destination libvirt. If
+ * omitted, the dconn connection object will be queried for its
+ * current URI.
+ *
+ * If the VIR_MIGRATE_PEER2PEER flag is NOT set, the URI parameter
+ * takes a hypervisor specific format. The hypervisor capabilities
+ * XML includes details of the support URI schemes. If omitted
+ * the dconn will be asked for a default URI.
+ *
+ * If you want to copy non-shared storage within migration you
+ * can use either VIR_MIGRATE_NON_SHARED_DISK or
+ * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
+ *
+ * In either case it is typically only necessary to specify a
+ * URI if the destination host has multiple interfaces and a
+ * specific interface is required to transmit migration data.
+ *
+ * The maximum bandwidth (in MiB/s) that will be used to do migration
+ * can be specified with the bandwidth parameter.  If set to 0,
+ * libvirt will choose a suitable default.  Some hypervisors do
+ * not support this feature and will return an error if bandwidth
+ * is not 0.
+ *
+ * To see which features are supported by the current hypervisor,
+ * see virConnectGetCapabilities, /capabilities/host/migration_features.
+ *
+ * There are many limitations on migration imposed by the underlying
+ * technology - for example it may not be possible to migrate between
+ * different processors even with the same architecture, or between
+ * different types of hypervisor.
+ *
+ * virDomainFree should be used to free the resources after the
+ * returned domain object is no longer needed.
+ *
+ * Returns the new domain object if the migration was successful,
+ *   or NULL in case of error.  Note that the new domain object
+ *   exists in the scope of the destination connection (dconn).
+ */
+virDomainPtr
+virDomainMigrate(virDomainPtr domain,
+                 virConnectPtr dconn,
+                 unsigned long flags,
+                 const char *dname,
+                 const char *uri,
+                 unsigned long bandwidth)
+{
+    virDomainPtr ddomain = NULL;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
+                     dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
+
+    virResetLastError();
+
+    /* First checkout the source */
+    virCheckDomainReturn(domain, NULL);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+
+    /* Now checkout the destination */
+    virCheckConnectGoto(dconn, error);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
+        flags & VIR_MIGRATE_NON_SHARED_INC) {
+        virReportInvalidArg(flags,
+                            _("flags 'shared disk' and 'shared incremental' "
+                              "in %s are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (flags & VIR_MIGRATE_OFFLINE) {
+        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("offline migration is not supported by "
+                             "the source host"));
+            goto error;
+        }
+        if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("offline migration is not supported by "
+                             "the destination host"));
+            goto error;
+        }
+    }
+
+    if (flags & VIR_MIGRATE_PEER2PEER) {
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_P2P)) {
+            char *dstURI = NULL;
+            if (uri == NULL) {
+                dstURI = virConnectGetURI(dconn);
+                if (!dstURI)
+                    return NULL;
+            }
+
+            VIR_DEBUG("Using peer2peer migration");
+            if (virDomainMigratePeer2Peer(domain, NULL, flags, dname,
+                                          uri ? uri : dstURI, NULL, bandwidth) < 0) {
+                VIR_FREE(dstURI);
+                goto error;
+            }
+            VIR_FREE(dstURI);
+
+            ddomain = virDomainLookupByName(dconn, dname ? dname : domain->name);
+        } else {
+            /* This driver does not support peer to peer migration */
+            virReportUnsupportedError();
+            goto error;
+        }
+    } else {
+        /* Change protection requires support only on source side, and
+         * is only needed in v3 migration, which automatically re-adds
+         * the flag for just the source side.  We mask it out for
+         * non-peer2peer to allow migration from newer source to an
+         * older destination that rejects the flag.  */
+        if (flags & VIR_MIGRATE_CHANGE_PROTECTION &&
+            !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION)) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("cannot enforce change protection"));
+            goto error;
+        }
+        flags &= ~VIR_MIGRATE_CHANGE_PROTECTION;
+        if (flags & VIR_MIGRATE_TUNNELLED) {
+            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                           _("cannot perform tunnelled migration without using peer2peer flag"));
+            goto error;
+        }
+
+        /* Check that migration is supported by both drivers. */
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_V3) &&
+            VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                     VIR_DRV_FEATURE_MIGRATION_V3)) {
+            VIR_DEBUG("Using migration protocol 3");
+            ddomain = virDomainMigrateVersion3(domain, dconn, NULL,
+                                               flags, dname, uri, bandwidth);
+        } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                            VIR_DRV_FEATURE_MIGRATION_V2) &&
+                   VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                          VIR_DRV_FEATURE_MIGRATION_V2)) {
+            VIR_DEBUG("Using migration protocol 2");
+            ddomain = virDomainMigrateVersion2(domain, dconn, flags,
+                                               dname, uri, bandwidth);
+        } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                            VIR_DRV_FEATURE_MIGRATION_V1) &&
+                   VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                            VIR_DRV_FEATURE_MIGRATION_V1)) {
+            VIR_DEBUG("Using migration protocol 1");
+            ddomain = virDomainMigrateVersion1(domain, dconn, flags,
+                                               dname, uri, bandwidth);
+        } else {
+            /* This driver does not support any migration method */
+            virReportUnsupportedError();
+            goto error;
+        }
+    }
+
+    if (ddomain == NULL)
+        goto error;
+
+    return ddomain;
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainMigrate2:
+ * @domain: a domain object
+ * @dconn: destination host (a connection object)
+ * @flags: bitwise-OR of virDomainMigrateFlags
+ * @dxml: (optional) XML config for launching guest on target
+ * @dname: (optional) rename domain to this at destination
+ * @uri: (optional) dest hostname/URI as seen from the source host
+ * @bandwidth: (optional) specify migration bandwidth limit in MiB/s
+ *
+ * Migrate the domain object from its current host to the destination
+ * host given by dconn (a connection to the destination host).
+ *
+ * Flags may be one of more of the following:
+ *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
+ *   VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
+ *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
+ *   VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
+ *                            on the destination host.
+ *   VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
+ *                               domain on the source host.
+ *   VIR_MIGRATE_PAUSED    Leave the domain suspended on the remote side.
+ *   VIR_MIGRATE_NON_SHARED_DISK Migration with non-shared storage with full
+ *                               disk copy
+ *   VIR_MIGRATE_NON_SHARED_INC  Migration with non-shared storage with
+ *                               incremental disk copy
+ *   VIR_MIGRATE_CHANGE_PROTECTION Protect against domain configuration
+ *                                 changes during the migration process (set
+ *                                 automatically when supported).
+ *   VIR_MIGRATE_UNSAFE    Force migration even if it is considered unsafe.
+ *   VIR_MIGRATE_OFFLINE Migrate offline
+ *
+ * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
+ * Applications using the VIR_MIGRATE_PEER2PEER flag will probably
+ * prefer to invoke virDomainMigrateToURI, avoiding the need to
+ * open connection to the destination host themselves.
+ *
+ * If a hypervisor supports renaming domains during migration,
+ * then you may set the dname parameter to the new name (otherwise
+ * it keeps the same name).  If this is not supported by the
+ * hypervisor, dname must be NULL or else you will get an error.
+ *
+ * If the VIR_MIGRATE_PEER2PEER flag is set, the uri parameter
+ * must be a valid libvirt connection URI, by which the source
+ * libvirt driver can connect to the destination libvirt. If
+ * omitted, the dconn connection object will be queried for its
+ * current URI.
+ *
+ * If the VIR_MIGRATE_PEER2PEER flag is NOT set, the URI parameter
+ * takes a hypervisor specific format. The hypervisor capabilities
+ * XML includes details of the support URI schemes. If omitted
+ * the dconn will be asked for a default URI.
+ *
+ * If you want to copy non-shared storage within migration you
+ * can use either VIR_MIGRATE_NON_SHARED_DISK or
+ * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
+ *
+ * In either case it is typically only necessary to specify a
+ * URI if the destination host has multiple interfaces and a
+ * specific interface is required to transmit migration data.
+ *
+ * The maximum bandwidth (in MiB/s) that will be used to do migration
+ * can be specified with the bandwidth parameter.  If set to 0,
+ * libvirt will choose a suitable default.  Some hypervisors do
+ * not support this feature and will return an error if bandwidth
+ * is not 0.
+ *
+ * To see which features are supported by the current hypervisor,
+ * see virConnectGetCapabilities, /capabilities/host/migration_features.
+ *
+ * There are many limitations on migration imposed by the underlying
+ * technology - for example it may not be possible to migrate between
+ * different processors even with the same architecture, or between
+ * different types of hypervisor.
+ *
+ * If the hypervisor supports it, @dxml can be used to alter
+ * host-specific portions of the domain XML that will be used on
+ * the destination.  For example, it is possible to alter the
+ * backing filename that is associated with a disk device, in order
+ * to account for naming differences between source and destination
+ * in accessing the underlying storage.  The migration will fail
+ * if @dxml would cause any guest-visible changes.  Pass NULL
+ * if no changes are needed to the XML between source and destination.
+ * @dxml cannot be used to rename the domain during migration (use
+ * @dname for that purpose).  Domain name in @dxml must match the
+ * original domain name.
+ *
+ * virDomainFree should be used to free the resources after the
+ * returned domain object is no longer needed.
+ *
+ * Returns the new domain object if the migration was successful,
+ *   or NULL in case of error.  Note that the new domain object
+ *   exists in the scope of the destination connection (dconn).
+ */
+virDomainPtr
+virDomainMigrate2(virDomainPtr domain,
+                  virConnectPtr dconn,
+                  const char *dxml,
+                  unsigned long flags,
+                  const char *dname,
+                  const char *uri,
+                  unsigned long bandwidth)
+{
+    virDomainPtr ddomain = NULL;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
+                     dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
+
+    virResetLastError();
+
+    /* First checkout the source */
+    virCheckDomainReturn(domain, NULL);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+
+    /* Now checkout the destination */
+    virCheckConnectGoto(dconn, error);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
+        flags & VIR_MIGRATE_NON_SHARED_INC) {
+        virReportInvalidArg(flags,
+                            _("flags 'shared disk' and 'shared incremental' "
+                              "in %s are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (flags & VIR_MIGRATE_OFFLINE) {
+        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("offline migration is not supported by "
+                             "the source host"));
+            goto error;
+        }
+        if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("offline migration is not supported by "
+                             "the destination host"));
+            goto error;
+        }
+    }
+
+    if (flags & VIR_MIGRATE_PEER2PEER) {
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_P2P)) {
+            char *dstURI = virConnectGetURI(dconn);
+            if (!dstURI)
+                return NULL;
+
+            VIR_DEBUG("Using peer2peer migration");
+            if (virDomainMigratePeer2Peer(domain, dxml, flags, dname,
+                                          dstURI, uri, bandwidth) < 0) {
+                VIR_FREE(dstURI);
+                goto error;
+            }
+            VIR_FREE(dstURI);
+
+            ddomain = virDomainLookupByName(dconn, dname ? dname : domain->name);
+        } else {
+            /* This driver does not support peer to peer migration */
+            virReportUnsupportedError();
+            goto error;
+        }
+    } else {
+        /* Change protection requires support only on source side, and
+         * is only needed in v3 migration, which automatically re-adds
+         * the flag for just the source side.  We mask it out for
+         * non-peer2peer to allow migration from newer source to an
+         * older destination that rejects the flag.  */
+        if (flags & VIR_MIGRATE_CHANGE_PROTECTION &&
+            !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION)) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("cannot enforce change protection"));
+            goto error;
+        }
+        flags &= ~VIR_MIGRATE_CHANGE_PROTECTION;
+        if (flags & VIR_MIGRATE_TUNNELLED) {
+            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                           _("cannot perform tunnelled migration without using peer2peer flag"));
+            goto error;
+        }
+
+        /* Check that migration is supported by both drivers. */
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_V3) &&
+            VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                     VIR_DRV_FEATURE_MIGRATION_V3)) {
+            VIR_DEBUG("Using migration protocol 3");
+            ddomain = virDomainMigrateVersion3(domain, dconn, dxml,
+                                               flags, dname, uri, bandwidth);
+        } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                            VIR_DRV_FEATURE_MIGRATION_V2) &&
+                   VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                          VIR_DRV_FEATURE_MIGRATION_V2)) {
+            VIR_DEBUG("Using migration protocol 2");
+            if (dxml) {
+                virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                               _("Unable to change target guest XML during migration"));
+                goto error;
+            }
+            ddomain = virDomainMigrateVersion2(domain, dconn, flags,
+                                               dname, uri, bandwidth);
+        } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                            VIR_DRV_FEATURE_MIGRATION_V1) &&
+                   VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                            VIR_DRV_FEATURE_MIGRATION_V1)) {
+            VIR_DEBUG("Using migration protocol 1");
+            if (dxml) {
+                virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                               _("Unable to change target guest XML during migration"));
+                goto error;
+            }
+            ddomain = virDomainMigrateVersion1(domain, dconn, flags,
+                                               dname, uri, bandwidth);
+        } else {
+            /* This driver does not support any migration method */
+            virReportUnsupportedError();
+            goto error;
+        }
+    }
+
+    if (ddomain == NULL)
+        goto error;
+
+    return ddomain;
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainMigrate3:
+ * @domain: a domain object
+ * @dconn: destination host (a connection object)
+ * @params: (optional) migration parameters
+ * @nparams: (optional) number of migration parameters in @params
+ * @flags: bitwise-OR of virDomainMigrateFlags
+ *
+ * Migrate the domain object from its current host to the destination host
+ * given by dconn (a connection to the destination host).
+ *
+ * See virDomainMigrateFlags documentation for description of individual flags.
+ *
+ * VIR_MIGRATE_TUNNELLED and VIR_MIGRATE_PEER2PEER are not supported by this
+ * API, use virDomainMigrateToURI3 instead.
+ *
+ * If you want to copy non-shared storage within migration you
+ * can use either VIR_MIGRATE_NON_SHARED_DISK or
+ * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
+ *
+ * There are many limitations on migration imposed by the underlying
+ * technology - for example it may not be possible to migrate between
+ * different processors even with the same architecture, or between
+ * different types of hypervisor.
+ *
+ * virDomainFree should be used to free the resources after the
+ * returned domain object is no longer needed.
+ *
+ * Returns the new domain object if the migration was successful,
+ *   or NULL in case of error.  Note that the new domain object
+ *   exists in the scope of the destination connection (dconn).
+ */
+virDomainPtr
+virDomainMigrate3(virDomainPtr domain,
+                  virConnectPtr dconn,
+                  virTypedParameterPtr params,
+                  unsigned int nparams,
+                  unsigned int flags)
+{
+    virDomainPtr ddomain = NULL;
+    const char *compatParams[] = { VIR_MIGRATE_PARAM_URI,
+                                   VIR_MIGRATE_PARAM_DEST_NAME,
+                                   VIR_MIGRATE_PARAM_DEST_XML,
+                                   VIR_MIGRATE_PARAM_BANDWIDTH };
+    const char *uri = NULL;
+    const char *dname = NULL;
+    const char *dxml = NULL;
+    unsigned long long bandwidth = 0;
+
+    VIR_DOMAIN_DEBUG(domain, "dconn=%p, params=%p, nparms=%u flags=%x",
+                     dconn, params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    /* First checkout the source */
+    virCheckDomainReturn(domain, NULL);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+
+    /* Now checkout the destination */
+    virCheckConnectGoto(dconn, error);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
+        flags & VIR_MIGRATE_NON_SHARED_INC) {
+        virReportInvalidArg(flags,
+                            _("flags 'shared disk' and 'shared incremental' "
+                              "in %s are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+    if (flags & VIR_MIGRATE_PEER2PEER) {
+        virReportInvalidArg(flags, "%s",
+                            _("use virDomainMigrateToURI3 for peer-to-peer "
+                              "migration"));
+        goto error;
+    }
+    if (flags & VIR_MIGRATE_TUNNELLED) {
+        virReportInvalidArg(flags, "%s",
+                            _("cannot perform tunnelled migration "
+                              "without using peer2peer flag"));
+        goto error;
+    }
+
+    if (flags & VIR_MIGRATE_OFFLINE) {
+        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("offline migration is not supported by "
+                             "the source host"));
+            goto error;
+        }
+        if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("offline migration is not supported by "
+                             "the destination host"));
+            goto error;
+        }
+    }
+
+    /* Change protection requires support only on source side, and
+     * is only needed in v3 migration, which automatically re-adds
+     * the flag for just the source side.  We mask it out to allow
+     * migration from newer source to an older destination that
+     * rejects the flag.  */
+    if (flags & VIR_MIGRATE_CHANGE_PROTECTION &&
+        !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                  VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION)) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("cannot enforce change protection"));
+        goto error;
+    }
+    flags &= ~VIR_MIGRATE_CHANGE_PROTECTION;
+
+    /* Prefer extensible API but fall back to older migration APIs if params
+     * only contains parameters which were supported by the older API. */
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_MIGRATION_PARAMS) &&
+        VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                 VIR_DRV_FEATURE_MIGRATION_PARAMS)) {
+        VIR_DEBUG("Using migration protocol 3 with extensible parameters");
+        ddomain = virDomainMigrateVersion3Params(domain, dconn, params,
+                                                 nparams, flags);
+        goto done;
+    }
+
+    if (!virTypedParamsCheck(params, nparams, compatParams,
+                             ARRAY_CARDINALITY(compatParams))) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("Migration APIs with extensible parameters are not "
+                         "supported but extended parameters were passed"));
+        goto error;
+    }
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_URI, &uri) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_XML, &dxml) < 0 ||
+        virTypedParamsGetULLong(params, nparams,
+                                VIR_MIGRATE_PARAM_BANDWIDTH, &bandwidth) < 0) {
+        goto error;
+    }
+
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_MIGRATION_V3) &&
+        VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                 VIR_DRV_FEATURE_MIGRATION_V3)) {
+        VIR_DEBUG("Using migration protocol 3");
+        ddomain = virDomainMigrateVersion3(domain, dconn, dxml, flags,
+                                           dname, uri, bandwidth);
+    } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                        VIR_DRV_FEATURE_MIGRATION_V2) &&
+               VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                      VIR_DRV_FEATURE_MIGRATION_V2)) {
+        VIR_DEBUG("Using migration protocol 2");
+        if (dxml) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("Unable to change target guest XML during "
+                             "migration"));
+            goto error;
+        }
+        ddomain = virDomainMigrateVersion2(domain, dconn, flags,
+                                           dname, uri, bandwidth);
+    } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                        VIR_DRV_FEATURE_MIGRATION_V1) &&
+               VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
+                                        VIR_DRV_FEATURE_MIGRATION_V1)) {
+        VIR_DEBUG("Using migration protocol 1");
+        if (dxml) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("Unable to change target guest XML during "
+                             "migration"));
+            goto error;
+        }
+        ddomain = virDomainMigrateVersion1(domain, dconn, flags,
+                                           dname, uri, bandwidth);
+    } else {
+        /* This driver does not support any migration method */
+        virReportUnsupportedError();
+        goto error;
+    }
+
+ done:
+    if (ddomain == NULL)
+        goto error;
+
+    return ddomain;
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainMigrateToURI:
+ * @domain: a domain object
+ * @duri: mandatory URI for the destination host
+ * @flags: bitwise-OR of virDomainMigrateFlags
+ * @dname: (optional) rename domain to this at destination
+ * @bandwidth: (optional) specify migration bandwidth limit in MiB/s
+ *
+ * Migrate the domain object from its current host to the destination
+ * host given by duri.
+ *
+ * Flags may be one of more of the following:
+ *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
+ *   VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
+ *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
+ *   VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
+ *                            on the destination host.
+ *   VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
+ *                               domain on the source host.
+ *   VIR_MIGRATE_PAUSED    Leave the domain suspended on the remote side.
+ *   VIR_MIGRATE_NON_SHARED_DISK Migration with non-shared storage with full
+ *                               disk copy
+ *   VIR_MIGRATE_NON_SHARED_INC  Migration with non-shared storage with
+ *                               incremental disk copy
+ *   VIR_MIGRATE_CHANGE_PROTECTION Protect against domain configuration
+ *                                 changes during the migration process (set
+ *                                 automatically when supported).
+ *   VIR_MIGRATE_UNSAFE    Force migration even if it is considered unsafe.
+ *   VIR_MIGRATE_OFFLINE Migrate offline
+ *
+ * The operation of this API hinges on the VIR_MIGRATE_PEER2PEER flag.
+ * If the VIR_MIGRATE_PEER2PEER flag is NOT set, the duri parameter
+ * takes a hypervisor specific format. The uri_transports element of the
+ * hypervisor capabilities XML includes details of the supported URI
+ * schemes. Not all hypervisors will support this mode of migration, so
+ * if the VIR_MIGRATE_PEER2PEER flag is not set, then it may be necessary
+ * to use the alternative virDomainMigrate API providing and explicit
+ * virConnectPtr for the destination host.
+ *
+ * If the VIR_MIGRATE_PEER2PEER flag IS set, the duri parameter
+ * must be a valid libvirt connection URI, by which the source
+ * libvirt driver can connect to the destination libvirt.
+ *
+ * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
+ *
+ * If you want to copy non-shared storage within migration you
+ * can use either VIR_MIGRATE_NON_SHARED_DISK or
+ * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
+ *
+ * If a hypervisor supports renaming domains during migration,
+ * the dname parameter specifies the new name for the domain.
+ * Setting dname to NULL keeps the domain name the same.  If domain
+ * renaming is not supported by the hypervisor, dname must be NULL or
+ * else an error will be returned.
+ *
+ * The maximum bandwidth (in MiB/s) that will be used to do migration
+ * can be specified with the bandwidth parameter.  If set to 0,
+ * libvirt will choose a suitable default.  Some hypervisors do
+ * not support this feature and will return an error if bandwidth
+ * is not 0.
+ *
+ * To see which features are supported by the current hypervisor,
+ * see virConnectGetCapabilities, /capabilities/host/migration_features.
+ *
+ * There are many limitations on migration imposed by the underlying
+ * technology - for example it may not be possible to migrate between
+ * different processors even with the same architecture, or between
+ * different types of hypervisor.
+ *
+ * Returns 0 if the migration succeeded, -1 upon error.
+ */
+int
+virDomainMigrateToURI(virDomainPtr domain,
+                      const char *duri,
+                      unsigned long flags,
+                      const char *dname,
+                      unsigned long bandwidth)
+{
+    VIR_DOMAIN_DEBUG(domain, "duri=%p, flags=%lx, dname=%s, bandwidth=%lu",
+                     NULLSTR(duri), flags, NULLSTR(dname), bandwidth);
+
+    virResetLastError();
+
+    /* First checkout the source */
+    virCheckDomainReturn(domain, -1);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+
+    virCheckNonNullArgGoto(duri, error);
+
+    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
+        flags & VIR_MIGRATE_NON_SHARED_INC) {
+        virReportInvalidArg(flags,
+                            _("flags 'shared disk' and 'shared incremental' "
+                              "in %s are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (flags & VIR_MIGRATE_OFFLINE &&
+        !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                  VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("offline migration is not supported by "
+                         "the source host"));
+        goto error;
+    }
+
+    if (flags & VIR_MIGRATE_PEER2PEER) {
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_P2P)) {
+            VIR_DEBUG("Using peer2peer migration");
+            if (virDomainMigratePeer2Peer(domain, NULL, flags,
+                                          dname, duri, NULL, bandwidth) < 0)
+                goto error;
+        } else {
+            /* No peer to peer migration supported */
+            virReportUnsupportedError();
+            goto error;
+        }
+    } else {
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_DIRECT)) {
+            VIR_DEBUG("Using direct migration");
+            if (virDomainMigrateDirect(domain, NULL, flags,
+                                       dname, duri, bandwidth) < 0)
+                goto error;
+        } else {
+            /* Cannot do a migration with only the perform step */
+            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                           _("direct migration is not supported by the"
+                             " connection driver"));
+            goto error;
+        }
+    }
+
+    return 0;
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMigrateToURI2:
+ * @domain: a domain object
+ * @dconnuri: (optional) URI for target libvirtd if @flags includes VIR_MIGRATE_PEER2PEER
+ * @miguri: (optional) URI for invoking the migration, not if @flags includs VIR_MIGRATE_TUNNELLED
+ * @dxml: (optional) XML config for launching guest on target
+ * @flags: bitwise-OR of virDomainMigrateFlags
+ * @dname: (optional) rename domain to this at destination
+ * @bandwidth: (optional) specify migration bandwidth limit in MiB/s
+ *
+ * Migrate the domain object from its current host to the destination
+ * host given by duri.
+ *
+ * Flags may be one of more of the following:
+ *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
+ *   VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
+ *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
+ *   VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
+ *                            on the destination host.
+ *   VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
+ *                               domain on the source host.
+ *   VIR_MIGRATE_PAUSED    Leave the domain suspended on the remote side.
+ *   VIR_MIGRATE_NON_SHARED_DISK Migration with non-shared storage with full
+ *                               disk copy
+ *   VIR_MIGRATE_NON_SHARED_INC  Migration with non-shared storage with
+ *                               incremental disk copy
+ *   VIR_MIGRATE_CHANGE_PROTECTION Protect against domain configuration
+ *                                 changes during the migration process (set
+ *                                 automatically when supported).
+ *   VIR_MIGRATE_UNSAFE    Force migration even if it is considered unsafe.
+ *   VIR_MIGRATE_OFFLINE Migrate offline
+ *
+ * The operation of this API hinges on the VIR_MIGRATE_PEER2PEER flag.
+ *
+ * If the VIR_MIGRATE_PEER2PEER flag is set, the @dconnuri parameter
+ * must be a valid libvirt connection URI, by which the source
+ * libvirt driver can connect to the destination libvirt. If the
+ * VIR_MIGRATE_PEER2PEER flag is NOT set, then @dconnuri must be
+ * NULL.
+ *
+ * If the VIR_MIGRATE_TUNNELLED flag is NOT set, then the @miguri
+ * parameter allows specification of a URI to use to initiate the
+ * VM migration. It takes a hypervisor specific format. The uri_transports
+ * element of the hypervisor capabilities XML includes details of the
+ * supported URI schemes.
+ *
+ * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
+ *
+ * If you want to copy non-shared storage within migration you
+ * can use either VIR_MIGRATE_NON_SHARED_DISK or
+ * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
+ *
+ * If a hypervisor supports changing the configuration of the guest
+ * during migration, the @dxml parameter specifies the new config
+ * for the guest. The configuration must include an identical set
+ * of virtual devices, to ensure a stable guest ABI across migration.
+ * Only parameters related to host side configuration can be
+ * changed in the XML. Hypervisors will validate this and refuse to
+ * allow migration if the provided XML would cause a change in the
+ * guest ABI,
+ *
+ * If a hypervisor supports renaming domains during migration,
+ * the dname parameter specifies the new name for the domain.
+ * Setting dname to NULL keeps the domain name the same.  If domain
+ * renaming is not supported by the hypervisor, dname must be NULL or
+ * else an error will be returned.
+ *
+ * The maximum bandwidth (in MiB/s) that will be used to do migration
+ * can be specified with the bandwidth parameter.  If set to 0,
+ * libvirt will choose a suitable default.  Some hypervisors do
+ * not support this feature and will return an error if bandwidth
+ * is not 0.
+ *
+ * To see which features are supported by the current hypervisor,
+ * see virConnectGetCapabilities, /capabilities/host/migration_features.
+ *
+ * There are many limitations on migration imposed by the underlying
+ * technology - for example it may not be possible to migrate between
+ * different processors even with the same architecture, or between
+ * different types of hypervisor.
+ *
+ * Returns 0 if the migration succeeded, -1 upon error.
+ */
+int
+virDomainMigrateToURI2(virDomainPtr domain,
+                       const char *dconnuri,
+                       const char *miguri,
+                       const char *dxml,
+                       unsigned long flags,
+                       const char *dname,
+                       unsigned long bandwidth)
+{
+    VIR_DOMAIN_DEBUG(domain, "dconnuri=%s, miguri=%s, dxml=%s, "
+                     "flags=%lx, dname=%s, bandwidth=%lu",
+                     NULLSTR(dconnuri), NULLSTR(miguri), NULLSTR(dxml),
+                     flags, NULLSTR(dname), bandwidth);
+
+    virResetLastError();
+
+    /* First checkout the source */
+    virCheckDomainReturn(domain, -1);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+
+    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
+        flags & VIR_MIGRATE_NON_SHARED_INC) {
+        virReportInvalidArg(flags,
+                            _("flags 'shared disk' and 'shared incremental' "
+                              "in %s are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (flags & VIR_MIGRATE_PEER2PEER) {
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_P2P)) {
+            VIR_DEBUG("Using peer2peer migration");
+            if (virDomainMigratePeer2Peer(domain, dxml, flags,
+                                          dname, dconnuri, miguri, bandwidth) < 0)
+                goto error;
+        } else {
+            /* No peer to peer migration supported */
+            virReportUnsupportedError();
+            goto error;
+        }
+    } else {
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_DIRECT)) {
+            VIR_DEBUG("Using direct migration");
+            if (virDomainMigrateDirect(domain, dxml, flags,
+                                       dname, miguri, bandwidth) < 0)
+                goto error;
+        } else {
+            /* Cannot do a migration with only the perform step */
+            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                           _("direct migration is not supported by the"
+                             " connection driver"));
+            goto error;
+        }
+    }
+
+    return 0;
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMigrateToURI3:
+ * @domain: a domain object
+ * @dconnuri: (optional) URI for target libvirtd if @flags includes VIR_MIGRATE_PEER2PEER
+ * @params: (optional) migration parameters
+ * @nparams: (optional) number of migration parameters in @params
+ * @flags: bitwise-OR of virDomainMigrateFlags
+ *
+ * Migrate the domain object from its current host to the destination host
+ * given by URI.
+ *
+ * See virDomainMigrateFlags documentation for description of individual flags.
+ *
+ * The operation of this API hinges on the VIR_MIGRATE_PEER2PEER flag.
+ *
+ * If the VIR_MIGRATE_PEER2PEER flag is set, the @dconnuri parameter must be a
+ * valid libvirt connection URI, by which the source libvirt daemon can connect
+ * to the destination libvirt.
+ *
+ * If the VIR_MIGRATE_PEER2PEER flag is NOT set, then @dconnuri must be NULL
+ * and VIR_MIGRATE_PARAM_URI migration parameter must be filled in with
+ * hypervisor specific URI used to initiate the migration. This is called
+ * "direct" migration.
+ *
+ * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
+ *
+ * If you want to copy non-shared storage within migration you
+ * can use either VIR_MIGRATE_NON_SHARED_DISK or
+ * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
+ *
+ * There are many limitations on migration imposed by the underlying
+ * technology - for example it may not be possible to migrate between
+ * different processors even with the same architecture, or between
+ * different types of hypervisor.
+ *
+ * Returns 0 if the migration succeeded, -1 upon error.
+ */
+int
+virDomainMigrateToURI3(virDomainPtr domain,
+                       const char *dconnuri,
+                       virTypedParameterPtr params,
+                       unsigned int nparams,
+                       unsigned int flags)
+{
+    bool compat;
+    const char *compatParams[] = { VIR_MIGRATE_PARAM_URI,
+                                   VIR_MIGRATE_PARAM_DEST_NAME,
+                                   VIR_MIGRATE_PARAM_DEST_XML,
+                                   VIR_MIGRATE_PARAM_BANDWIDTH };
+    const char *uri = NULL;
+    const char *dname = NULL;
+    const char *dxml = NULL;
+    unsigned long long bandwidth = 0;
+
+    VIR_DOMAIN_DEBUG(domain, "dconnuri=%s, params=%p, nparms=%u flags=%x",
+                     NULLSTR(dconnuri), params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    /* First checkout the source */
+    virCheckDomainReturn(domain, -1);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+
+    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
+        flags & VIR_MIGRATE_NON_SHARED_INC) {
+        virReportInvalidArg(flags,
+                            _("flags 'shared disk' and 'shared incremental' "
+                              "in %s are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    compat = virTypedParamsCheck(params, nparams, compatParams,
+                                 ARRAY_CARDINALITY(compatParams));
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_URI, &uri) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_XML, &dxml) < 0 ||
+        virTypedParamsGetULLong(params, nparams,
+                                VIR_MIGRATE_PARAM_BANDWIDTH, &bandwidth) < 0) {
+        goto error;
+    }
+
+    if (flags & VIR_MIGRATE_PEER2PEER) {
+        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATION_P2P)) {
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                           _("Peer-to-peer migration is not supported by "
+                             "the connection driver"));
+            goto error;
+        }
+
+        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                     VIR_DRV_FEATURE_MIGRATION_PARAMS)) {
+            VIR_DEBUG("Using peer2peer migration with extensible parameters");
+            if (virDomainMigratePeer2PeerParams(domain, dconnuri, params,
+                                                nparams, flags) < 0)
+                goto error;
+        } else if (compat) {
+            VIR_DEBUG("Using peer2peer migration");
+            if (virDomainMigratePeer2Peer(domain, dxml, flags, dname,
+                                          dconnuri, uri, bandwidth) < 0)
+                goto error;
+        } else {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("Peer-to-peer migration with extensible "
+                             "parameters is not supported but extended "
+                             "parameters were passed"));
+            goto error;
+        }
+    } else {
+        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                      VIR_DRV_FEATURE_MIGRATION_DIRECT)) {
+            /* Cannot do a migration with only the perform step */
+            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
+                           _("Direct migration is not supported by the"
+                             " connection driver"));
+            goto error;
+        }
+
+        if (!compat) {
+            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                           _("Direct migration does not support extensible "
+                             "parameters"));
+            goto error;
+        }
+
+        VIR_DEBUG("Using direct migration");
+        if (virDomainMigrateDirect(domain, dxml, flags,
+                                   dname, uri, bandwidth) < 0)
+            goto error;
+    }
+
+    return 0;
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePrepare(virConnectPtr dconn,
+                        char **cookie,
+                        int *cookielen,
+                        const char *uri_in,
+                        char **uri_out,
+                        unsigned long flags,
+                        const char *dname,
+                        unsigned long bandwidth)
+{
+    VIR_DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p, "
+              "flags=%lx, dname=%s, bandwidth=%lu", dconn, cookie, cookielen,
+              NULLSTR(uri_in), uri_out, flags, NULLSTR(dname), bandwidth);
+
+    virResetLastError();
+
+    virCheckConnectReturn(dconn, -1);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (dconn->driver->domainMigratePrepare) {
+        int ret;
+        ret = dconn->driver->domainMigratePrepare(dconn, cookie, cookielen,
+                                                  uri_in, uri_out,
+                                                  flags, dname, bandwidth);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dconn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePerform(virDomainPtr domain,
+                        const char *cookie,
+                        int cookielen,
+                        const char *uri,
+                        unsigned long flags,
+                        const char *dname,
+                        unsigned long bandwidth)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "cookie=%p, cookielen=%d, uri=%s, flags=%lx, "
+                     "dname=%s, bandwidth=%lu", cookie, cookielen, uri, flags,
+                     NULLSTR(dname), bandwidth);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigratePerform) {
+        int ret;
+        ret = conn->driver->domainMigratePerform(domain, cookie, cookielen,
+                                                 uri,
+                                                 flags, dname, bandwidth);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+virDomainPtr
+virDomainMigrateFinish(virConnectPtr dconn,
+                       const char *dname,
+                       const char *cookie,
+                       int cookielen,
+                       const char *uri,
+                       unsigned long flags)
+{
+    VIR_DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, "
+              "flags=%lx", dconn, NULLSTR(dname), cookie, cookielen,
+              uri, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(dconn, NULL);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (dconn->driver->domainMigrateFinish) {
+        virDomainPtr ret;
+        ret = dconn->driver->domainMigrateFinish(dconn, dname,
+                                                 cookie, cookielen,
+                                                 uri, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dconn);
+    return NULL;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePrepare2(virConnectPtr dconn,
+                         char **cookie,
+                         int *cookielen,
+                         const char *uri_in,
+                         char **uri_out,
+                         unsigned long flags,
+                         const char *dname,
+                         unsigned long bandwidth,
+                         const char *dom_xml)
+{
+    VIR_DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p,"
+              "flags=%lx, dname=%s, bandwidth=%lu, dom_xml=%s", dconn,
+              cookie, cookielen, uri_in, uri_out, flags, NULLSTR(dname),
+              bandwidth, dom_xml);
+
+    virResetLastError();
+
+    virCheckConnectReturn(dconn, -1);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (dconn->driver->domainMigratePrepare2) {
+        int ret;
+        ret = dconn->driver->domainMigratePrepare2(dconn, cookie, cookielen,
+                                                   uri_in, uri_out,
+                                                   flags, dname, bandwidth,
+                                                   dom_xml);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dconn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+virDomainPtr
+virDomainMigrateFinish2(virConnectPtr dconn,
+                        const char *dname,
+                        const char *cookie,
+                        int cookielen,
+                        const char *uri,
+                        unsigned long flags,
+                        int retcode)
+{
+    VIR_DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, "
+              "flags=%lx, retcode=%d", dconn, NULLSTR(dname), cookie,
+              cookielen, uri, flags, retcode);
+
+    virResetLastError();
+
+    virCheckConnectReturn(dconn, NULL);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (dconn->driver->domainMigrateFinish2) {
+        virDomainPtr ret;
+        ret = dconn->driver->domainMigrateFinish2(dconn, dname,
+                                                  cookie, cookielen,
+                                                  uri, flags,
+                                                  retcode);
+        if (!ret && !retcode)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dconn);
+    return NULL;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePrepareTunnel(virConnectPtr conn,
+                              virStreamPtr st,
+                              unsigned long flags,
+                              const char *dname,
+                              unsigned long bandwidth,
+                              const char *dom_xml)
+{
+    VIR_DEBUG("conn=%p, stream=%p, flags=%lx, dname=%s, "
+              "bandwidth=%lu, dom_xml=%s", conn, st, flags,
+              NULLSTR(dname), bandwidth, dom_xml);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn != st->conn) {
+        virReportInvalidArg(conn,
+                            _("conn in %s must match stream connection"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainMigratePrepareTunnel) {
+        int rv = conn->driver->domainMigratePrepareTunnel(conn, st,
+                                                          flags, dname,
+                                                          bandwidth, dom_xml);
+        if (rv < 0)
+            goto error;
+        return rv;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+char *
+virDomainMigrateBegin3(virDomainPtr domain,
+                       const char *xmlin,
+                       char **cookieout,
+                       int *cookieoutlen,
+                       unsigned long flags,
+                       const char *dname,
+                       unsigned long bandwidth)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "xmlin=%s cookieout=%p, cookieoutlen=%p, "
+                     "flags=%lx, dname=%s, bandwidth=%lu",
+                     NULLSTR(xmlin), cookieout, cookieoutlen, flags,
+                     NULLSTR(dname), bandwidth);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigrateBegin3) {
+        char *xml;
+        xml = conn->driver->domainMigrateBegin3(domain, xmlin,
+                                                cookieout, cookieoutlen,
+                                                flags, dname, bandwidth);
+        VIR_DEBUG("xml %s", NULLSTR(xml));
+        if (!xml)
+            goto error;
+        return xml;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePrepare3(virConnectPtr dconn,
+                         const char *cookiein,
+                         int cookieinlen,
+                         char **cookieout,
+                         int *cookieoutlen,
+                         const char *uri_in,
+                         char **uri_out,
+                         unsigned long flags,
+                         const char *dname,
+                         unsigned long bandwidth,
+                         const char *dom_xml)
+{
+    VIR_DEBUG("dconn=%p, cookiein=%p, cookieinlen=%d, cookieout=%p, "
+              "cookieoutlen=%p, uri_in=%s, uri_out=%p, flags=%lx, dname=%s, "
+              "bandwidth=%lu, dom_xml=%s",
+              dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in,
+              uri_out, flags, NULLSTR(dname), bandwidth, dom_xml);
+
+    virResetLastError();
+
+    virCheckConnectReturn(dconn, -1);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (dconn->driver->domainMigratePrepare3) {
+        int ret;
+        ret = dconn->driver->domainMigratePrepare3(dconn,
+                                                   cookiein, cookieinlen,
+                                                   cookieout, cookieoutlen,
+                                                   uri_in, uri_out,
+                                                   flags, dname, bandwidth,
+                                                   dom_xml);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dconn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePrepareTunnel3(virConnectPtr conn,
+                               virStreamPtr st,
+                               const char *cookiein,
+                               int cookieinlen,
+                               char **cookieout,
+                               int *cookieoutlen,
+                               unsigned long flags,
+                               const char *dname,
+                               unsigned long bandwidth,
+                               const char *dom_xml)
+{
+    VIR_DEBUG("conn=%p, stream=%p, cookiein=%p, cookieinlen=%d, cookieout=%p, "
+              "cookieoutlen=%p, flags=%lx, dname=%s, bandwidth=%lu, "
+              "dom_xml=%s",
+              conn, st, cookiein, cookieinlen, cookieout, cookieoutlen, flags,
+              NULLSTR(dname), bandwidth, dom_xml);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn != st->conn) {
+        virReportInvalidArg(conn,
+                            _("conn in %s must match stream connection"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainMigratePrepareTunnel3) {
+        int rv = conn->driver->domainMigratePrepareTunnel3(conn, st,
+                                                           cookiein, cookieinlen,
+                                                           cookieout, cookieoutlen,
+                                                           flags, dname,
+                                                           bandwidth, dom_xml);
+        if (rv < 0)
+            goto error;
+        return rv;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePerform3(virDomainPtr domain,
+                         const char *xmlin,
+                         const char *cookiein,
+                         int cookieinlen,
+                         char **cookieout,
+                         int *cookieoutlen,
+                         const char *dconnuri,
+                         const char *uri,
+                         unsigned long flags,
+                         const char *dname,
+                         unsigned long bandwidth)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "xmlin=%s cookiein=%p, cookieinlen=%d, "
+                     "cookieout=%p, cookieoutlen=%p, dconnuri=%s, "
+                     "uri=%s, flags=%lx, dname=%s, bandwidth=%lu",
+                     NULLSTR(xmlin), cookiein, cookieinlen,
+                     cookieout, cookieoutlen, NULLSTR(dconnuri),
+                     NULLSTR(uri), flags, NULLSTR(dname), bandwidth);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigratePerform3) {
+        int ret;
+        ret = conn->driver->domainMigratePerform3(domain, xmlin,
+                                                  cookiein, cookieinlen,
+                                                  cookieout, cookieoutlen,
+                                                  dconnuri, uri,
+                                                  flags, dname, bandwidth);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+virDomainPtr
+virDomainMigrateFinish3(virConnectPtr dconn,
+                        const char *dname,
+                        const char *cookiein,
+                        int cookieinlen,
+                        char **cookieout,
+                        int *cookieoutlen,
+                        const char *dconnuri,
+                        const char *uri,
+                        unsigned long flags,
+                        int cancelled)
+{
+    VIR_DEBUG("dconn=%p, dname=%s, cookiein=%p, cookieinlen=%d, cookieout=%p,"
+              "cookieoutlen=%p, dconnuri=%s, uri=%s, flags=%lx, retcode=%d",
+              dconn, NULLSTR(dname), cookiein, cookieinlen, cookieout,
+              cookieoutlen, NULLSTR(dconnuri), NULLSTR(uri), flags, cancelled);
+
+    virResetLastError();
+
+    virCheckConnectReturn(dconn, NULL);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (dconn->driver->domainMigrateFinish3) {
+        virDomainPtr ret;
+        ret = dconn->driver->domainMigrateFinish3(dconn, dname,
+                                                  cookiein, cookieinlen,
+                                                  cookieout, cookieoutlen,
+                                                  dconnuri, uri, flags,
+                                                  cancelled);
+        if (!ret && !cancelled)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dconn);
+    return NULL;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigrateConfirm3(virDomainPtr domain,
+                         const char *cookiein,
+                         int cookieinlen,
+                         unsigned long flags,
+                         int cancelled)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "cookiein=%p, cookieinlen=%d, flags=%lx, cancelled=%d",
+                     cookiein, cookieinlen, flags, cancelled);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigrateConfirm3) {
+        int ret;
+        ret = conn->driver->domainMigrateConfirm3(domain,
+                                                  cookiein, cookieinlen,
+                                                  flags, cancelled);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+char *
+virDomainMigrateBegin3Params(virDomainPtr domain,
+                             virTypedParameterPtr params,
+                             int nparams,
+                             char **cookieout,
+                             int *cookieoutlen,
+                             unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, "
+                     "cookieout=%p, cookieoutlen=%p, flags=%x",
+                     params, nparams, cookieout, cookieoutlen, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigrateBegin3Params) {
+        char *xml;
+        xml = conn->driver->domainMigrateBegin3Params(domain, params, nparams,
+                                                      cookieout, cookieoutlen,
+                                                      flags);
+        VIR_DEBUG("xml %s", NULLSTR(xml));
+        if (!xml)
+            goto error;
+        return xml;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePrepare3Params(virConnectPtr dconn,
+                               virTypedParameterPtr params,
+                               int nparams,
+                               const char *cookiein,
+                               int cookieinlen,
+                               char **cookieout,
+                               int *cookieoutlen,
+                               char **uri_out,
+                               unsigned int flags)
+{
+    VIR_DEBUG("dconn=%p, params=%p, nparams=%d, cookiein=%p, cookieinlen=%d, "
+              "cookieout=%p, cookieoutlen=%p, uri_out=%p, flags=%x",
+              dconn, params, nparams, cookiein, cookieinlen,
+              cookieout, cookieoutlen, uri_out, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckConnectReturn(dconn, -1);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (dconn->driver->domainMigratePrepare3Params) {
+        int ret;
+        ret = dconn->driver->domainMigratePrepare3Params(dconn, params, nparams,
+                                                         cookiein, cookieinlen,
+                                                         cookieout, cookieoutlen,
+                                                         uri_out, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dconn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePrepareTunnel3Params(virConnectPtr conn,
+                                     virStreamPtr st,
+                                     virTypedParameterPtr params,
+                                     int nparams,
+                                     const char *cookiein,
+                                     int cookieinlen,
+                                     char **cookieout,
+                                     int *cookieoutlen,
+                                     unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, stream=%p, params=%p, nparams=%d, cookiein=%p, "
+              "cookieinlen=%d, cookieout=%p, cookieoutlen=%p, flags=%x",
+              conn, st, params, nparams, cookiein, cookieinlen,
+              cookieout, cookieoutlen, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn != st->conn) {
+        virReportInvalidArg(conn,
+                            _("conn in %s must match stream connection"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainMigratePrepareTunnel3Params) {
+        int rv;
+        rv = conn->driver->domainMigratePrepareTunnel3Params(
+                conn, st, params, nparams, cookiein, cookieinlen,
+                cookieout, cookieoutlen, flags);
+        if (rv < 0)
+            goto error;
+        return rv;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigratePerform3Params(virDomainPtr domain,
+                               const char *dconnuri,
+                               virTypedParameterPtr params,
+                               int nparams,
+                               const char *cookiein,
+                               int cookieinlen,
+                               char **cookieout,
+                               int *cookieoutlen,
+                               unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "dconnuri=%s, params=%p, nparams=%d, cookiein=%p, "
+                     "cookieinlen=%d, cookieout=%p, cookieoutlen=%p, flags=%x",
+                     NULLSTR(dconnuri), params, nparams, cookiein,
+                     cookieinlen, cookieout, cookieoutlen, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigratePerform3Params) {
+        int ret;
+        ret = conn->driver->domainMigratePerform3Params(
+                domain, dconnuri, params, nparams, cookiein, cookieinlen,
+                cookieout, cookieoutlen, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+virDomainPtr
+virDomainMigrateFinish3Params(virConnectPtr dconn,
+                              virTypedParameterPtr params,
+                              int nparams,
+                              const char *cookiein,
+                              int cookieinlen,
+                              char **cookieout,
+                              int *cookieoutlen,
+                              unsigned int flags,
+                              int cancelled)
+{
+    VIR_DEBUG("dconn=%p, params=%p, nparams=%d, cookiein=%p, cookieinlen=%d, "
+              "cookieout=%p, cookieoutlen=%p, flags=%x, cancelled=%d",
+              dconn, params, nparams, cookiein, cookieinlen, cookieout,
+              cookieoutlen, flags, cancelled);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckConnectReturn(dconn, NULL);
+    virCheckReadOnlyGoto(dconn->flags, error);
+
+    if (dconn->driver->domainMigrateFinish3Params) {
+        virDomainPtr ret;
+        ret = dconn->driver->domainMigrateFinish3Params(
+                dconn, params, nparams, cookiein, cookieinlen,
+                cookieout, cookieoutlen, flags, cancelled);
+        if (!ret && !cancelled)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dconn);
+    return NULL;
+}
+
+
+/*
+ * Not for public use.  This function is part of the internal
+ * implementation of migration in the remote case.
+ */
+int
+virDomainMigrateConfirm3Params(virDomainPtr domain,
+                               virTypedParameterPtr params,
+                               int nparams,
+                               const char *cookiein,
+                               int cookieinlen,
+                               unsigned int flags,
+                               int cancelled)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, cookiein=%p, "
+                     "cookieinlen=%d, flags=%x, cancelled=%d",
+                     params, nparams, cookiein, cookieinlen, flags, cancelled);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigrateConfirm3Params) {
+        int ret;
+        ret = conn->driver->domainMigrateConfirm3Params(
+                domain, params, nparams,
+                cookiein, cookieinlen, flags, cancelled);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetSchedulerType:
+ * @domain: pointer to domain object
+ * @nparams: pointer to number of scheduler parameters, can be NULL
+ *           (return value)
+ *
+ * Get the scheduler type and the number of scheduler parameters.
+ *
+ * Returns NULL in case of error. The caller must free the returned string.
+ */
+char *
+virDomainGetSchedulerType(virDomainPtr domain, int *nparams)
+{
+    virConnectPtr conn;
+    char *schedtype;
+
+    VIR_DOMAIN_DEBUG(domain, "nparams=%p", nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+    conn = domain->conn;
+
+    if (conn->driver->domainGetSchedulerType) {
+        schedtype = conn->driver->domainGetSchedulerType(domain, nparams);
+        if (!schedtype)
+            goto error;
+        return schedtype;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainGetSchedulerParameters:
+ * @domain: pointer to domain object
+ * @params: pointer to scheduler parameter objects
+ *          (return value)
+ * @nparams: pointer to number of scheduler parameter objects
+ *          (this value should generally be as large as the returned value
+ *           nparams of virDomainGetSchedulerType()); input and output
+ *
+ * Get all scheduler parameters.  On input, @nparams gives the size of the
+ * @params array; on output, @nparams gives how many slots were filled
+ * with parameter information, which might be less but will not exceed
+ * the input value.  @nparams cannot be 0.
+ *
+ * It is hypervisor specific whether this returns the live or
+ * persistent state; for more control, use
+ * virDomainGetSchedulerParametersFlags().
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainGetSchedulerParameters(virDomainPtr domain,
+                                virTypedParameterPtr params, int *nparams)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%p", params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+
+    virCheckNonNullArgGoto(params, error);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckPositiveArgGoto(*nparams, error);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetSchedulerParameters) {
+        int ret;
+        ret = conn->driver->domainGetSchedulerParameters(domain, params, nparams);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetSchedulerParametersFlags:
+ * @domain: pointer to domain object
+ * @params: pointer to scheduler parameter object
+ *          (return value)
+ * @nparams: pointer to number of scheduler parameter
+ *          (this value should be same than the returned value
+ *           nparams of virDomainGetSchedulerType()); input and output
+ * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
+ *
+ * Get all scheduler parameters.  On input, @nparams gives the size of the
+ * @params array; on output, @nparams gives how many slots were filled
+ * with parameter information, which might be less but will not exceed
+ * the input value.  @nparams cannot be 0.
+ *
+ * The value of @flags can be exactly VIR_DOMAIN_AFFECT_CURRENT,
+ * VIR_DOMAIN_AFFECT_LIVE, or VIR_DOMAIN_AFFECT_CONFIG.
+ *
+ * Here is a sample code snippet:
+ *
+ *   char *ret = virDomainGetSchedulerType(dom, &nparams);
+ *   if (ret && nparams != 0) {
+ *       if ((params = malloc(sizeof(*params) * nparams)) == NULL)
+ *           goto error;
+ *       memset(params, 0, sizeof(*params) * nparams);
+ *       if (virDomainGetSchedulerParametersFlags(dom, params, &nparams, 0))
+ *           goto error;
+ *   }
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainGetSchedulerParametersFlags(virDomainPtr domain,
+                                     virTypedParameterPtr params, int *nparams,
+                                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%p, flags=%x",
+                     params, nparams, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+
+    virCheckNonNullArgGoto(params, error);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckPositiveArgGoto(*nparams, error);
+
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        virReportInvalidArg(flags,
+                            _("flags 'affect live' and 'affect config' in %s "
+                              "are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainGetSchedulerParametersFlags) {
+        int ret;
+        ret = conn->driver->domainGetSchedulerParametersFlags(domain, params,
+                                                              nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetSchedulerParameters:
+ * @domain: pointer to domain object
+ * @params: pointer to scheduler parameter objects
+ * @nparams: number of scheduler parameter objects
+ *          (this value can be the same or less than the returned value
+ *           nparams of virDomainGetSchedulerType)
+ *
+ * Change all or a subset or the scheduler parameters.  It is
+ * hypervisor-specific whether this sets live, persistent, or both
+ * settings; for more control, use
+ * virDomainSetSchedulerParametersFlags.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainSetSchedulerParameters(virDomainPtr domain,
+                                virTypedParameterPtr params, int nparams)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d", params, nparams);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(params, error);
+    virCheckNonNegativeArgGoto(nparams, error);
+
+    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
+        goto error;
+
+    if (conn->driver->domainSetSchedulerParameters) {
+        int ret;
+        ret = conn->driver->domainSetSchedulerParameters(domain, params, nparams);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetSchedulerParametersFlags:
+ * @domain: pointer to domain object
+ * @params: pointer to scheduler parameter objects
+ * @nparams: number of scheduler parameter objects
+ *          (this value can be the same or less than the returned value
+ *           nparams of virDomainGetSchedulerType)
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Change a subset or all scheduler parameters.  The value of @flags
+ * should be either VIR_DOMAIN_AFFECT_CURRENT, or a bitwise-or of
+ * values from VIR_DOMAIN_AFFECT_LIVE and
+ * VIR_DOMAIN_AFFECT_CURRENT, although hypervisors vary in which
+ * flags are supported.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainSetSchedulerParametersFlags(virDomainPtr domain,
+                                     virTypedParameterPtr params,
+                                     int nparams,
+                                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
+                     params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(params, error);
+    virCheckNonNegativeArgGoto(nparams, error);
+
+    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
+        goto error;
+
+    if (conn->driver->domainSetSchedulerParametersFlags) {
+        int ret;
+        ret = conn->driver->domainSetSchedulerParametersFlags(domain,
+                                                              params,
+                                                              nparams,
+                                                              flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockStats:
+ * @dom: pointer to the domain object
+ * @disk: path to the block device, or device shorthand
+ * @stats: block device stats (returned)
+ * @size: size of stats structure
+ *
+ * This function returns block device (disk) stats for block
+ * devices attached to the domain.
+ *
+ * The @disk parameter is either the device target shorthand (the
+ * <target dev='...'/> sub-element, such as "vda"), or (since 0.9.8)
+ * an unambiguous source name of the block device (the <source
+ * file='...'/> sub-element, such as "/path/to/image").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk. Some drivers might also
+ * accept the empty string for the @disk parameter, and then yield
+ * summary stats for the entire domain.
+ *
+ * Domains may have more than one block device.  To get stats for
+ * each you should make multiple calls to this function.
+ *
+ * Individual fields within the stats structure may be returned
+ * as -1, which indicates that the hypervisor does not support
+ * that particular statistic.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainBlockStats(virDomainPtr dom, const char *disk,
+                    virDomainBlockStatsPtr stats, size_t size)
+{
+    virConnectPtr conn;
+    virDomainBlockStatsStruct stats2 = { -1, -1, -1, -1, -1 };
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, stats=%p, size=%zi", disk, stats, size);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckNonNullArgGoto(disk, error);
+    virCheckNonNullArgGoto(stats, error);
+    if (size > sizeof(stats2)) {
+        virReportInvalidArg(size,
+                            _("size in %s must not exceed %zu"),
+                            __FUNCTION__, sizeof(stats2));
+        goto error;
+    }
+    conn = dom->conn;
+
+    if (conn->driver->domainBlockStats) {
+        if (conn->driver->domainBlockStats(dom, disk, &stats2) == -1)
+            goto error;
+
+        memcpy(stats, &stats2, size);
+        return 0;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockStatsFlags:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @params: pointer to block stats parameter object
+ *          (return value, allocated by the caller)
+ * @nparams: pointer to number of block stats; input and output
+ * @flags: bitwise-OR of virTypedParameterFlags
+ *
+ * This function is to get block stats parameters for block
+ * devices attached to the domain.
+ *
+ * The @disk parameter is either the device target shorthand (the
+ * <target dev='...'/> sub-element, such as "vda"), or (since 0.9.8)
+ * an unambiguous source name of the block device (the <source
+ * file='...'/> sub-element, such as "/path/to/image").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk. Some drivers might also
+ * accept the empty string for the @disk parameter, and then yield
+ * summary stats for the entire domain.
+ *
+ * Domains may have more than one block device.  To get stats for
+ * each you should make multiple calls to this function.
+ *
+ * On input, @nparams gives the size of the @params array; on output,
+ * @nparams gives how many slots were filled with parameter
+ * information, which might be less but will not exceed the input
+ * value.
+ *
+ * As a special case, calling with @params as NULL and @nparams as 0 on
+ * input will cause @nparams on output to contain the number of parameters
+ * supported by the hypervisor. (Note that block devices of different types
+ * might support different parameters, so it might be necessary to compute
+ * @nparams for each block device). The caller should then allocate @params
+ * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
+ * again. See virDomainGetMemoryParameters() for more details.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainBlockStatsFlags(virDomainPtr dom,
+                         const char *disk,
+                         virTypedParameterPtr params,
+                         int *nparams,
+                         unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, params=%p, nparams=%d, flags=%x",
+                     disk, params, nparams ? *nparams : -1, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckNonNullArgGoto(disk, error);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (*nparams != 0)
+        virCheckNonNullArgGoto(params, error);
+
+    if (VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+    conn = dom->conn;
+
+    if (conn->driver->domainBlockStatsFlags) {
+        int ret;
+        ret = conn->driver->domainBlockStatsFlags(dom, disk, params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainInterfaceStats:
+ * @dom: pointer to the domain object
+ * @path: path to the interface
+ * @stats: network interface stats (returned)
+ * @size: size of stats structure
+ *
+ * This function returns network interface stats for interfaces
+ * attached to the domain.
+ *
+ * The path parameter is the name of the network interface.
+ *
+ * Domains may have more than one network interface.  To get stats for
+ * each you should make multiple calls to this function.
+ *
+ * Individual fields within the stats structure may be returned
+ * as -1, which indicates that the hypervisor does not support
+ * that particular statistic.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainInterfaceStats(virDomainPtr dom, const char *path,
+                        virDomainInterfaceStatsPtr stats, size_t size)
+{
+    virConnectPtr conn;
+    virDomainInterfaceStatsStruct stats2 = { -1, -1, -1, -1,
+                                             -1, -1, -1, -1 };
+
+    VIR_DOMAIN_DEBUG(dom, "path=%s, stats=%p, size=%zi",
+                     path, stats, size);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckNonNullArgGoto(path, error);
+    virCheckNonNullArgGoto(stats, error);
+    if (size > sizeof(stats2)) {
+        virReportInvalidArg(size,
+                            _("size in %s must not exceed %zu"),
+                            __FUNCTION__, sizeof(stats2));
+        goto error;
+    }
+
+    conn = dom->conn;
+
+    if (conn->driver->domainInterfaceStats) {
+        if (conn->driver->domainInterfaceStats(dom, path, &stats2) == -1)
+            goto error;
+
+        memcpy(stats, &stats2, size);
+        return 0;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetInterfaceParameters:
+ * @domain: pointer to domain object
+ * @device: the interface name or mac address
+ * @params: pointer to interface parameter objects
+ * @nparams: number of interface parameter (this value can be the same or
+ *          less than the number of parameters supported)
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Change a subset or all parameters of interface; currently this
+ * includes bandwidth parameters.  The value of @flags should be
+ * either VIR_DOMAIN_AFFECT_CURRENT, or a bitwise-or of values
+ * VIR_DOMAIN_AFFECT_LIVE and VIR_DOMAIN_AFFECT_CONFIG, although
+ * hypervisors vary in which flags are supported.
+ *
+ * This function may require privileged access to the hypervisor.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainSetInterfaceParameters(virDomainPtr domain,
+                                const char *device,
+                                virTypedParameterPtr params,
+                                int nparams, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "device=%s, params=%p, nparams=%d, flags=%x",
+                     device, params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(params, error);
+    virCheckPositiveArgGoto(nparams, error);
+
+    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
+        goto error;
+
+    if (conn->driver->domainSetInterfaceParameters) {
+        int ret;
+        ret = conn->driver->domainSetInterfaceParameters(domain, device,
+                                                         params, nparams,
+                                                         flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetInterfaceParameters:
+ * @domain: pointer to domain object
+ * @device: the interface name or mac address
+ * @params: pointer to interface parameter objects
+ *          (return value, allocated by the caller)
+ * @nparams: pointer to number of interface parameter; input and output
+ * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
+ *
+ * Get all interface parameters. On input, @nparams gives the size of
+ * the @params array; on output, @nparams gives how many slots were
+ * filled with parameter information, which might be less but will not
+ * exceed the input value.
+ *
+ * As a special case, calling with @params as NULL and @nparams as 0 on
+ * input will cause @nparams on output to contain the number of parameters
+ * supported by the hypervisor. The caller should then allocate @params
+ * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the
+ * API again. See virDomainGetMemoryParameters() for an equivalent usage
+ * example.
+ *
+ * This function may require privileged access to the hypervisor. This function
+ * expects the caller to allocate the @params.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainGetInterfaceParameters(virDomainPtr domain,
+                                const char *device,
+                                virTypedParameterPtr params,
+                                int *nparams, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "device=%s, params=%p, nparams=%d, flags=%x",
+                     device, params, (nparams) ? *nparams : -1, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (*nparams != 0)
+        virCheckNonNullArgGoto(params, error);
+
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetInterfaceParameters) {
+        int ret;
+        ret = conn->driver->domainGetInterfaceParameters(domain, device,
+                                                         params, nparams,
+                                                         flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMemoryStats:
+ * @dom: pointer to the domain object
+ * @stats: nr_stats-sized array of stat structures (returned)
+ * @nr_stats: number of memory statistics requested
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * This function provides memory statistics for the domain.
+ *
+ * Up to 'nr_stats' elements of 'stats' will be populated with memory statistics
+ * from the domain.  Only statistics supported by the domain, the driver, and
+ * this version of libvirt will be returned.
+ *
+ * Memory Statistics:
+ *
+ * VIR_DOMAIN_MEMORY_STAT_SWAP_IN:
+ *     The total amount of data read from swap space (in kb).
+ * VIR_DOMAIN_MEMORY_STAT_SWAP_OUT:
+ *     The total amount of memory written out to swap space (in kb).
+ * VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT:
+ *     The number of page faults that required disk IO to service.
+ * VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT:
+ *     The number of page faults serviced without disk IO.
+ * VIR_DOMAIN_MEMORY_STAT_UNUSED:
+ *     The amount of memory which is not being used for any purpose (in kb).
+ * VIR_DOMAIN_MEMORY_STAT_AVAILABLE:
+ *     The total amount of memory available to the domain's OS (in kb).
+ * VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON:
+ *     Current balloon value (in kb).
+ *
+ * Returns: The number of stats provided or -1 in case of failure.
+ */
+int
+virDomainMemoryStats(virDomainPtr dom, virDomainMemoryStatPtr stats,
+                     unsigned int nr_stats, unsigned int flags)
+{
+    virConnectPtr conn;
+    unsigned long nr_stats_ret = 0;
+
+    VIR_DOMAIN_DEBUG(dom, "stats=%p, nr_stats=%u, flags=%x",
+                     stats, nr_stats, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    if (!stats || nr_stats == 0)
+        return 0;
+
+    if (nr_stats > VIR_DOMAIN_MEMORY_STAT_NR)
+        nr_stats = VIR_DOMAIN_MEMORY_STAT_NR;
+
+    conn = dom->conn;
+    if (conn->driver->domainMemoryStats) {
+        nr_stats_ret = conn->driver->domainMemoryStats(dom, stats, nr_stats,
+                                                       flags);
+        if (nr_stats_ret == -1)
+            goto error;
+        return nr_stats_ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockPeek:
+ * @dom: pointer to the domain object
+ * @disk: path to the block device, or device shorthand
+ * @offset: offset within block device
+ * @size: size to read
+ * @buffer: return buffer (must be at least size bytes)
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * This function allows you to read the contents of a domain's
+ * disk device.
+ *
+ * Typical uses for this are to determine if the domain has
+ * written a Master Boot Record (indicating that the domain
+ * has completed installation), or to try to work out the state
+ * of the domain's filesystems.
+ *
+ * (Note that in the local case you might try to open the
+ * block device or file directly, but that won't work in the
+ * remote case, nor if you don't have sufficient permission.
+ * Hence the need for this call).
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or (since 0.9.5) the device target shorthand
+ * (the <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * 'offset' and 'size' represent an area which must lie entirely
+ * within the device or file.  'size' may be 0 to test if the
+ * call would succeed.
+ *
+ * 'buffer' is the return buffer and must be at least 'size' bytes.
+ *
+ * NB. The remote driver imposes a 64K byte limit on 'size'.
+ * For your program to be able to work reliably over a remote
+ * connection you should split large requests to <= 65536 bytes.
+ * However, with 0.9.13 this RPC limit has been raised to 1M byte.
+ * Starting with version 1.0.6 the RPC limit has been raised again.
+ * Now large requests up to 16M byte are supported.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainBlockPeek(virDomainPtr dom,
+                   const char *disk,
+                   unsigned long long offset /* really 64 bits */,
+                   size_t size,
+                   void *buffer,
+                   unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, offset=%lld, size=%zi, buffer=%p, flags=%x",
+                     disk, offset, size, buffer, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+
+    /* Allow size == 0 as an access test. */
+    if (size > 0)
+        virCheckNonNullArgGoto(buffer, error);
+
+    if (conn->driver->domainBlockPeek) {
+        int ret;
+        ret = conn->driver->domainBlockPeek(dom, disk, offset, size,
+                                            buffer, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockResize:
+ * @dom: pointer to the domain object
+ * @disk: path to the block image, or shorthand
+ * @size: new size of the block image, see below for unit
+ * @flags: bitwise-OR of virDomainBlockResizeFlags
+ *
+ * Resize a block device of domain while the domain is running.  If
+ * @flags is 0, then @size is in kibibytes (blocks of 1024 bytes);
+ * since 0.9.11, if @flags includes VIR_DOMAIN_BLOCK_RESIZE_BYTES,
+ * @size is in bytes instead.  @size is taken directly as the new
+ * size.  Depending on the file format, the hypervisor may round up
+ * to the next alignment boundary.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or (since 0.9.5) the device target shorthand
+ * (the <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * Note that this call may fail if the underlying virtualization hypervisor
+ * does not support it; this call requires privileged access to the
+ * hypervisor.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainBlockResize(virDomainPtr dom,
+                     const char *disk,
+                     unsigned long long size,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, size=%llu, flags=%x", disk, size, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+
+    if (conn->driver->domainBlockResize) {
+        int ret;
+        ret = conn->driver->domainBlockResize(dom, disk, size, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMemoryPeek:
+ * @dom: pointer to the domain object
+ * @start: start of memory to peek
+ * @size: size of memory to peek
+ * @buffer: return buffer (must be at least size bytes)
+ * @flags: bitwise-OR of virDomainMemoryFlags
+ *
+ * This function allows you to read the contents of a domain's
+ * memory.
+ *
+ * The memory which is read is controlled by the 'start', 'size'
+ * and 'flags' parameters.
+ *
+ * If 'flags' is VIR_MEMORY_VIRTUAL then the 'start' and 'size'
+ * parameters are interpreted as virtual memory addresses for
+ * whichever task happens to be running on the domain at the
+ * moment.  Although this sounds haphazard it is in fact what
+ * you want in order to read Linux kernel state, because it
+ * ensures that pointers in the kernel image can be interpreted
+ * coherently.
+ *
+ * 'buffer' is the return buffer and must be at least 'size' bytes.
+ * 'size' may be 0 to test if the call would succeed.
+ *
+ * NB. The remote driver imposes a 64K byte limit on 'size'.
+ * For your program to be able to work reliably over a remote
+ * connection you should split large requests to <= 65536 bytes.
+ * However, with 0.9.13 this RPC limit has been raised to 1M byte.
+ * Starting with version 1.0.6 the RPC limit has been raised again.
+ * Now large requests up to 16M byte are supported.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainMemoryPeek(virDomainPtr dom,
+                    unsigned long long start /* really 64 bits */,
+                    size_t size,
+                    void *buffer,
+                    unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "start=%lld, size=%zi, buffer=%p, flags=%x",
+                     start, size, buffer, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    /* Note on access to physical memory: A VIR_MEMORY_PHYSICAL flag is
+     * a possibility.  However it isn't really useful unless the caller
+     * can also access registers, particularly CR3 on x86 in order to
+     * get the Page Table Directory.  Since registers are different on
+     * every architecture, that would imply another call to get the
+     * machine registers.
+     *
+     * The QEMU driver handles VIR_MEMORY_VIRTUAL, mapping it
+     * to the qemu 'memsave' command which does the virtual to physical
+     * mapping inside qemu.
+     *
+     * The QEMU driver also handles VIR_MEMORY_PHYSICAL, mapping it
+     * to the qemu 'pmemsave' command.
+     *
+     * At time of writing there is no Xen driver.  However the Xen
+     * hypervisor only lets you map physical pages from other domains,
+     * and so the Xen driver would have to do the virtual to physical
+     * mapping by chasing 2, 3 or 4-level page tables from the PTD.
+     * There is example code in libxc (xc_translate_foreign_address)
+     * which does this, although we cannot copy this code directly
+     * because of incompatible licensing.
+     */
+
+    /* Exactly one of these two flags must be set.  */
+    if (!(flags & VIR_MEMORY_VIRTUAL) == !(flags & VIR_MEMORY_PHYSICAL)) {
+        virReportInvalidArg(flags,
+                            _("flags in %s must include VIR_MEMORY_VIRTUAL or "
+                              "VIR_MEMORY_PHYSICAL"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    /* Allow size == 0 as an access test. */
+    if (size > 0)
+        virCheckNonNullArgGoto(buffer, error);
+
+    if (conn->driver->domainMemoryPeek) {
+        int ret;
+        ret = conn->driver->domainMemoryPeek(dom, start, size,
+                                             buffer, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetBlockInfo:
+ * @domain: a domain object
+ * @disk: path to the block device, or device shorthand
+ * @info: pointer to a virDomainBlockInfo structure allocated by the user
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Extract information about a domain's block device.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or (since 0.9.5) the device target shorthand
+ * (the <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * For QEMU domains, the allocation and physical virDomainBlockInfo
+ * values returned will generally be the same, except when using a
+ * non raw, block backing device, such as qcow2 for an active domain.
+ * When the persistent domain is not active, QEMU will return the
+ * default which is the same value for allocation and physical.
+ *
+ * Active QEMU domains can return an allocation value which is more
+ * representative of the currently used blocks by the device compared
+ * to the physical size of the device. Applications can use/monitor
+ * the allocation value with the understanding that if the domain
+ * becomes inactive during an attempt to get the value, the default
+ * values will be returned. Thus, the application should check
+ * after the call for the domain being inactive if the values are
+ * the same. Optionally, the application could be watching for a
+ * shutdown event and then ignore any values received afterwards.
+ * This can be an issue when a domain is being migrated and the
+ * exact timing of the domain being made inactive and check of
+ * the allocation value results the default being returned. For
+ * a transient domain in the similar situation, this call will return
+ * -1 and an error message indicating the "domain is not running".
+ *
+ * The following is some pseudo code illustrating the call sequence:
+ *
+ *   ...
+ *   virDomainPtr dom;
+ *   virDomainBlockInfo info;
+ *   char *device;
+ *   ...
+ *   // Either get a list of all domains or a specific domain
+ *   // via a virDomainLookupBy*() call.
+ *   //
+ *   // It's also required to fill in the device pointer, but that's
+ *   // specific to the implementation. For the purposes of this example
+ *   // a qcow2 backed device name string would need to be provided.
+ *   ...
+ *   // If the following call is made on a persistent domain with a
+ *   // qcow2 block backed block device, then it's possible the returned
+ *   // allocation equals the physical value. In that case, the domain
+ *   // that may have been active prior to calling has become inactive,
+ *   // such as is the case during a domain migration. Thus once we
+ *   // get data returned, check for active domain when the values are
+ *   // the same.
+ *   if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
+ *       goto failure;
+ *   if (info.allocation == info.physical) {
+ *       // If the domain is no longer active,
+ *       // then the defaults are being returned.
+ *       if (!virDomainIsActive())
+ *               goto ignore_return;
+ *   }
+ *   // Do something with the allocation and physical values
+ *   ...
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainGetBlockInfo(virDomainPtr domain, const char *disk,
+                      virDomainBlockInfoPtr info, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "info=%p, flags=%x", info, flags);
+
+    virResetLastError();
+
+    if (info)
+        memset(info, 0, sizeof(*info));
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(disk, error);
+    virCheckNonNullArgGoto(info, error);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetBlockInfo) {
+        int ret;
+        ret = conn->driver->domainGetBlockInfo(domain, disk, info, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainDefineXML:
+ * @conn: pointer to the hypervisor connection
+ * @xml: the XML description for the domain, preferably in UTF-8
+ *
+ * Define a domain, but does not start it.
+ * This definition is persistent, until explicitly undefined with
+ * virDomainUndefine(). A previous definition for this domain would be
+ * overridden if it already exists.
+ *
+ * Some hypervisors may prevent this operation if there is a current
+ * block copy operation on a transient domain with the same id as the
+ * domain being defined; in that case, use virDomainBlockJobAbort() to
+ * stop the block copy first.
+ *
+ * virDomainFree should be used to free the resources after the
+ * domain object is no longer needed.
+ *
+ * Returns NULL in case of error, a pointer to the domain otherwise
+ */
+virDomainPtr
+virDomainDefineXML(virConnectPtr conn, const char *xml)
+{
+    VIR_DEBUG("conn=%p, xml=%s", conn, xml);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(xml, error);
+
+    if (conn->driver->domainDefineXML) {
+        virDomainPtr ret;
+        ret = conn->driver->domainDefineXML(conn, xml);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainUndefine:
+ * @domain: pointer to a defined domain
+ *
+ * Undefine a domain. If the domain is running, it's converted to
+ * transient domain, without stopping it. If the domain is inactive,
+ * the domain configuration is removed.
+ *
+ * If the domain has a managed save image (see
+ * virDomainHasManagedSaveImage()), or if it is inactive and has any
+ * snapshot metadata (see virDomainSnapshotNum()), then the undefine will
+ * fail. See virDomainUndefineFlags() for more control.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+virDomainUndefine(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainUndefine) {
+        int ret;
+        ret = conn->driver->domainUndefine(domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainUndefineFlags:
+ * @domain: pointer to a defined domain
+ * @flags: bitwise-OR of supported virDomainUndefineFlagsValues
+ *
+ * Undefine a domain. If the domain is running, it's converted to
+ * transient domain, without stopping it. If the domain is inactive,
+ * the domain configuration is removed.
+ *
+ * If the domain has a managed save image (see virDomainHasManagedSaveImage()),
+ * then including VIR_DOMAIN_UNDEFINE_MANAGED_SAVE in @flags will also remove
+ * that file, and omitting the flag will cause the undefine process to fail.
+ *
+ * If the domain is inactive and has any snapshot metadata (see
+ * virDomainSnapshotNum()), then including
+ * VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA in @flags will also remove
+ * that metadata.  Omitting the flag will cause the undefine of an
+ * inactive domain to fail.  Active snapshots will retain snapshot
+ * metadata until the (now-transient) domain halts, regardless of
+ * whether this flag is present.  On hypervisors where snapshots do
+ * not use libvirt metadata, this flag has no effect.
+ *
+ * If the domain has any nvram specified, then including
+ * VIR_DOMAIN_UNDEFINE_NVRAM will also remove that file, and omitting the flag
+ * will cause the undefine process to fail.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+virDomainUndefineFlags(virDomainPtr domain,
+                       unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainUndefineFlags) {
+        int ret;
+        ret = conn->driver->domainUndefineFlags(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virConnectNumOfDefinedDomains:
+ * @conn: pointer to the hypervisor connection
+ *
+ * Provides the number of defined but inactive domains.
+ *
+ * Returns the number of domain found or -1 in case of error
+ */
+int
+virConnectNumOfDefinedDomains(virConnectPtr conn)
+{
+    VIR_DEBUG("conn=%p", conn);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+
+    if (conn->driver->connectNumOfDefinedDomains) {
+        int ret;
+        ret = conn->driver->connectNumOfDefinedDomains(conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virConnectListDefinedDomains:
+ * @conn: pointer to the hypervisor connection
+ * @names: pointer to an array to store the names
+ * @maxnames: size of the array
+ *
+ * list the defined but inactive domains, stores the pointers to the names
+ * in @names
+ *
+ * For active domains, see virConnectListDomains().  For more control over
+ * the results, see virConnectListAllDomains().
+ *
+ * Returns the number of names provided in the array or -1 in case of error.
+ * Note that this command is inherently racy; a domain can be defined between
+ * a call to virConnectNumOfDefinedDomains() and this call; you are only
+ * guaranteed that all currently defined domains were listed if the return
+ * is less than @maxids.  The client must call free() on each returned name.
+ */
+int
+virConnectListDefinedDomains(virConnectPtr conn, char **const names,
+                             int maxnames)
+{
+    VIR_DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(names, error);
+    virCheckNonNegativeArgGoto(maxnames, error);
+
+    if (conn->driver->connectListDefinedDomains) {
+        int ret;
+        ret = conn->driver->connectListDefinedDomains(conn, names, maxnames);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virConnectListAllDomains:
+ * @conn: Pointer to the hypervisor connection.
+ * @domains: Pointer to a variable to store the array containing domain objects
+ *           or NULL if the list is not required (just returns number of guests).
+ * @flags: bitwise-OR of virConnectListAllDomainsFlags
+ *
+ * Collect a possibly-filtered list of all domains, and return an allocated
+ * array of information for each.  This API solves the race inherent in
+ * virConnectListDomains() and virConnectListDefinedDomains().
+ *
+ * Normally, all domains are returned; however, @flags can be used to
+ * filter the results for a smaller list of targeted domains.  The valid
+ * flags are divided into groups, where each group contains bits that
+ * describe mutually exclusive attributes of a domain, and where all bits
+ * within a group describe all possible domains.  Some hypervisors might
+ * reject explicit bits from a group where the hypervisor cannot make a
+ * distinction (for example, not all hypervisors can tell whether domains
+ * have snapshots).  For a group supported by a given hypervisor, the
+ * behavior when no bits of a group are set is identical to the behavior
+ * when all bits in that group are set.  When setting bits from more than
+ * one group, it is possible to select an impossible combination (such
+ * as an inactive transient domain), in that case a hypervisor may return
+ * either 0 or an error.
+ *
+ * The first group of @flags is VIR_CONNECT_LIST_DOMAINS_ACTIVE (online
+ * domains) and VIR_CONNECT_LIST_DOMAINS_INACTIVE (offline domains).
+ *
+ * The next group of @flags is VIR_CONNECT_LIST_DOMAINS_PERSISTENT (defined
+ * domains) and VIR_CONNECT_LIST_DOMAINS_TRANSIENT (running but not defined).
+ *
+ * The next group of @flags covers various domain states:
+ * VIR_CONNECT_LIST_DOMAINS_RUNNING, VIR_CONNECT_LIST_DOMAINS_PAUSED,
+ * VIR_CONNECT_LIST_DOMAINS_SHUTOFF, and a catch-all for all other states
+ * (such as crashed, this catch-all covers the possibility of adding new
+ * states).
+ *
+ * The remaining groups cover boolean attributes commonly asked about
+ * domains; they include VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE and
+ * VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE, for filtering based on whether
+ * a managed save image exists; VIR_CONNECT_LIST_DOMAINS_AUTOSTART and
+ * VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART, for filtering based on autostart;
+ * VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT and
+ * VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT, for filtering based on whether
+ * a domain has snapshots.
+ *
+ * Example of usage:
+ *
+ *   virDomainPtr *domains;
+ *   size_t i;
+ *   int ret;
+ *   unsigned int flags = VIR_CONNECT_LIST_DOMAINS_RUNNING |
+ *                        VIR_CONNECT_LIST_DOMAINS_PERSISTENT;
+ *   ret = virConnectListAllDomains(conn, &domains, flags);
+ *   if (ret < 0)
+ *       error();
+ *   for (i = 0; i < ret; i++) {
+ *        do_something_with_domain(domains[i]);
+ *        //here or in a separate loop if needed
+ *        virDomainFree(domains[i]);
+ *   }
+ *   free(domains);
+ *
+ * Returns the number of domains found or -1 and sets domains to NULL in case of
+ * error.  On success, the array stored into @domains is guaranteed to have an
+ * extra allocated element set to NULL but not included in the return count, to
+ * make iteration easier. The caller is responsible for calling virDomainFree()
+ * on each array element, then calling free() on @domains.
+ */
+int
+virConnectListAllDomains(virConnectPtr conn,
+                         virDomainPtr **domains,
+                         unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, domains=%p, flags=%x", conn, domains, flags);
+
+    virResetLastError();
+
+    if (domains)
+        *domains = NULL;
+
+    virCheckConnectReturn(conn, -1);
+
+    if (conn->driver->connectListAllDomains) {
+        int ret;
+        ret = conn->driver->connectListAllDomains(conn, domains, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainCreate:
+ * @domain: pointer to a defined domain
+ *
+ * Launch a defined domain. If the call succeeds the domain moves from the
+ * defined to the running domains pools.  The domain will be paused only
+ * if restoring from managed state created from a paused domain.  For more
+ * control, see virDomainCreateWithFlags().
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+virDomainCreate(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainCreate) {
+        int ret;
+        ret = conn->driver->domainCreate(domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainCreateWithFlags:
+ * @domain: pointer to a defined domain
+ * @flags: bitwise-OR of supported virDomainCreateFlags
+ *
+ * Launch a defined domain. If the call succeeds the domain moves from the
+ * defined to the running domains pools.
+ *
+ * If the VIR_DOMAIN_START_PAUSED flag is set, or if the guest domain
+ * has a managed save image that requested paused state (see
+ * virDomainManagedSave()) the guest domain will be started, but its
+ * CPUs will remain paused. The CPUs can later be manually started
+ * using virDomainResume().  In all other cases, the guest domain will
+ * be running.
+ *
+ * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
+ * domain will be automatically destroyed when the virConnectPtr
+ * object is finally released. This will also happen if the
+ * client application crashes / loses its connection to the
+ * libvirtd daemon. Any domains marked for auto destroy will
+ * block attempts at migration, save-to-file, or snapshots.
+ *
+ * If the VIR_DOMAIN_START_BYPASS_CACHE flag is set, and there is a
+ * managed save file for this domain (created by virDomainManagedSave()),
+ * then libvirt will attempt to bypass the file system cache while restoring
+ * the file, or fail if it cannot do so for the given system; this can allow
+ * less pressure on file system cache, but also risks slowing loads from NFS.
+ *
+ * If the VIR_DOMAIN_START_FORCE_BOOT flag is set, then any managed save
+ * file for this domain is discarded, and the domain boots from scratch.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+virDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainCreateWithFlags) {
+        int ret;
+        ret = conn->driver->domainCreateWithFlags(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainCreateWithFiles:
+ * @domain: pointer to a defined domain
+ * @nfiles: number of file descriptors passed
+ * @files: list of file descriptors passed
+ * @flags: bitwise-OR of supported virDomainCreateFlags
+ *
+ * Launch a defined domain. If the call succeeds the domain moves from the
+ * defined to the running domains pools.
+ *
+ * @files provides an array of file descriptors which will be
+ * made available to the 'init' process of the guest. The file
+ * handles exposed to the guest will be renumbered to start
+ * from 3 (ie immediately following stderr). This is only
+ * supported for guests which use container based virtualization
+ * technology.
+ *
+ * If the VIR_DOMAIN_START_PAUSED flag is set, or if the guest domain
+ * has a managed save image that requested paused state (see
+ * virDomainManagedSave()) the guest domain will be started, but its
+ * CPUs will remain paused. The CPUs can later be manually started
+ * using virDomainResume().  In all other cases, the guest domain will
+ * be running.
+ *
+ * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
+ * domain will be automatically destroyed when the virConnectPtr
+ * object is finally released. This will also happen if the
+ * client application crashes / loses its connection to the
+ * libvirtd daemon. Any domains marked for auto destroy will
+ * block attempts at migration, save-to-file, or snapshots.
+ *
+ * If the VIR_DOMAIN_START_BYPASS_CACHE flag is set, and there is a
+ * managed save file for this domain (created by virDomainManagedSave()),
+ * then libvirt will attempt to bypass the file system cache while restoring
+ * the file, or fail if it cannot do so for the given system; this can allow
+ * less pressure on file system cache, but also risks slowing loads from NFS.
+ *
+ * If the VIR_DOMAIN_START_FORCE_BOOT flag is set, then any managed save
+ * file for this domain is discarded, and the domain boots from scratch.
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+virDomainCreateWithFiles(virDomainPtr domain, unsigned int nfiles,
+                         int *files, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "nfiles=%u, files=%p, flags=%x",
+                     nfiles, files, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainCreateWithFiles) {
+        int ret;
+        ret = conn->driver->domainCreateWithFiles(domain,
+                                                  nfiles, files,
+                                                  flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetAutostart:
+ * @domain: a domain object
+ * @autostart: the value returned
+ *
+ * Provides a boolean value indicating whether the domain
+ * configured to be automatically started when the host
+ * machine boots.
+ *
+ * Returns -1 in case of error, 0 in case of success
+ */
+int
+virDomainGetAutostart(virDomainPtr domain,
+                      int *autostart)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "autostart=%p", autostart);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(autostart, error);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetAutostart) {
+        int ret;
+        ret = conn->driver->domainGetAutostart(domain, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetAutostart:
+ * @domain: a domain object
+ * @autostart: whether the domain should be automatically started 0 or 1
+ *
+ * Configure the domain to be automatically started
+ * when the host machine boots.
+ *
+ * Returns -1 in case of error, 0 in case of success
+ */
+int
+virDomainSetAutostart(virDomainPtr domain,
+                      int autostart)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "autostart=%d", autostart);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainSetAutostart) {
+        int ret;
+        ret = conn->driver->domainSetAutostart(domain, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainInjectNMI:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Send NMI to the guest
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainInjectNMI(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainInjectNMI) {
+        int ret;
+        ret = conn->driver->domainInjectNMI(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSendKey:
+ * @domain:    pointer to domain object, or NULL for Domain0
+ * @codeset:   the code set of keycodes, from virKeycodeSet
+ * @holdtime:  the duration (in milliseconds) that the keys will be held
+ * @keycodes:  array of keycodes
+ * @nkeycodes: number of keycodes, up to VIR_DOMAIN_SEND_KEY_MAX_KEYS
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Send key(s) to the guest.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainSendKey(virDomainPtr domain,
+                 unsigned int codeset,
+                 unsigned int holdtime,
+                 unsigned int *keycodes,
+                 int nkeycodes,
+                 unsigned int flags)
+{
+    virConnectPtr conn;
+    VIR_DOMAIN_DEBUG(domain, "codeset=%u, holdtime=%u, nkeycodes=%u, flags=%x",
+                     codeset, holdtime, nkeycodes, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(keycodes, error);
+    virCheckPositiveArgGoto(nkeycodes, error);
+
+    if (nkeycodes > VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
+        virReportInvalidArg(nkeycodes,
+                            _("nkeycodes in %s must be <= %d"),
+                            __FUNCTION__, VIR_DOMAIN_SEND_KEY_MAX_KEYS);
+        goto error;
+    }
+
+    if (conn->driver->domainSendKey) {
+        int ret;
+        ret = conn->driver->domainSendKey(domain, codeset, holdtime,
+                                          keycodes, nkeycodes, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSendProcessSignal:
+ * @domain: pointer to domain object
+ * @pid_value: a positive integer process ID, or negative integer process group ID
+ * @signum: a signal from the virDomainProcessSignal enum
+ * @flags: one of the virDomainProcessSignalFlag values
+ *
+ * Send a signal to the designated process in the guest
+ *
+ * The signal numbers must be taken from the virDomainProcessSignal
+ * enum. These will be translated to the corresponding signal
+ * number for the guest OS, by the guest agent delivering the
+ * signal. If there is no mapping from virDomainProcessSignal to
+ * the native OS signals, this API will report an error.
+ *
+ * If @pid_value is an integer greater than zero, it is
+ * treated as a process ID. If @pid_value is an integer
+ * less than zero, it is treated as a process group ID.
+ * All the @pid_value numbers are from the container/guest
+ * namespace. The value zero is not valid.
+ *
+ * Not all hypervisors will support sending signals to
+ * arbitrary processes or process groups. If this API is
+ * implemented the minimum requirement is to be able to
+ * use @pid_value == 1 (i.e. kill init). No other value is
+ * required to be supported.
+ *
+ * If the @signum is VIR_DOMAIN_PROCESS_SIGNAL_NOP then this
+ * API will simply report whether the process is running in
+ * the container/guest.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainSendProcessSignal(virDomainPtr domain,
+                           long long pid_value,
+                           unsigned int signum,
+                           unsigned int flags)
+{
+    virConnectPtr conn;
+    VIR_DOMAIN_DEBUG(domain, "pid=%lld, signum=%u flags=%x",
+                     pid_value, signum, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonZeroArgGoto(pid_value, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainSendProcessSignal) {
+        int ret;
+        ret = conn->driver->domainSendProcessSignal(domain,
+                                                    pid_value,
+                                                    signum,
+                                                    flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @nvcpus: the new number of virtual CPUs for this domain
+ *
+ * Dynamically change the number of virtual CPUs used by the domain.
+ * Note that this call may fail if the underlying virtualization hypervisor
+ * does not support it or if growing the number is arbitrarily limited.
+ * This function may require privileged access to the hypervisor.
+ *
+ * Note that if this call is executed before the guest has finished booting,
+ * the guest may fail to process the change.
+ *
+ * This command only changes the runtime configuration of the domain,
+ * so can only be called on an active domain.  It is hypervisor-dependent
+ * whether it also affects persistent configuration; for more control,
+ * use virDomainSetVcpusFlags().
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "nvcpus=%u", nvcpus);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonZeroArgGoto(nvcpus, error);
+
+    if (conn->driver->domainSetVcpus) {
+        int ret;
+        ret = conn->driver->domainSetVcpus(domain, nvcpus);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetVcpusFlags:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @nvcpus: the new number of virtual CPUs for this domain, must be at least 1
+ * @flags: bitwise-OR of virDomainVcpuFlags
+ *
+ * Dynamically change the number of virtual CPUs used by the domain.
+ * Note that this call may fail if the underlying virtualization hypervisor
+ * does not support it or if growing the number is arbitrarily limited.
+ * This function may require privileged access to the hypervisor.
+ *
+ * @flags may include VIR_DOMAIN_AFFECT_LIVE to affect a running
+ * domain (which may fail if domain is not active), or
+ * VIR_DOMAIN_AFFECT_CONFIG to affect the next boot via the XML
+ * description of the domain.  Both flags may be set.
+ * If neither flag is specified (that is, @flags is VIR_DOMAIN_AFFECT_CURRENT),
+ * then an inactive domain modifies persistent setup, while an active domain
+ * is hypervisor-dependent on whether just live or both live and persistent
+ * state is changed.
+ *
+ * Note that if this call is executed before the guest has finished booting,
+ * the guest may fail to process the change.
+ *
+ * If @flags includes VIR_DOMAIN_VCPU_MAXIMUM, then
+ * VIR_DOMAIN_AFFECT_LIVE must be clear, and only the maximum virtual
+ * CPU limit is altered; generally, this value must be less than or
+ * equal to virConnectGetMaxVcpus().  Otherwise, this call affects the
+ * current virtual CPU limit, which must be less than or equal to the
+ * maximum limit.
+ *
+ * If @flags includes VIR_DOMAIN_VCPU_GUEST, then the state of processors is
+ * modified inside the guest instead of the hypervisor. This flag can only
+ * be used with live guests and is incompatible with VIR_DOMAIN_VCPU_MAXIMUM.
+ * The usage of this flag may require a guest agent configured.
+ *
+ * Not all hypervisors can support all flag combinations.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
+                       unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "nvcpus=%u, flags=%x", nvcpus, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckReadOnlyGoto(domain->conn->flags, error);
+
+    if (flags & VIR_DOMAIN_VCPU_GUEST &&
+        flags & VIR_DOMAIN_VCPU_MAXIMUM) {
+        virReportInvalidArg(flags,
+                            _("flags 'VIR_DOMAIN_VCPU_MAXIMUM' and "
+                              "'VIR_DOMAIN_VCPU_GUEST' in '%s' are mutually "
+                              "exclusive"), __FUNCTION__);
+        goto error;
+    }
+
+    virCheckNonZeroArgGoto(nvcpus, error);
+
+    if ((unsigned short) nvcpus != nvcpus) {
+        virReportError(VIR_ERR_OVERFLOW, _("input too large: %u"), nvcpus);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainSetVcpusFlags) {
+        int ret;
+        ret = conn->driver->domainSetVcpusFlags(domain, nvcpus, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetVcpusFlags:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @flags: bitwise-OR of virDomainVcpuFlags
+ *
+ * Query the number of virtual CPUs used by the domain.  Note that
+ * this call may fail if the underlying virtualization hypervisor does
+ * not support it.  This function may require privileged access to the
+ * hypervisor.
+ *
+ * If @flags includes VIR_DOMAIN_AFFECT_LIVE, this will query a
+ * running domain (which will fail if domain is not active); if
+ * it includes VIR_DOMAIN_AFFECT_CONFIG, this will query the XML
+ * description of the domain.  It is an error to set both flags.
+ * If neither flag is set (that is, VIR_DOMAIN_AFFECT_CURRENT),
+ * then the configuration queried depends on whether the domain
+ * is currently running.
+ *
+ * If @flags includes VIR_DOMAIN_VCPU_MAXIMUM, then the maximum
+ * virtual CPU limit is queried.  Otherwise, this call queries the
+ * current virtual CPU count.
+ *
+ * If @flags includes VIR_DOMAIN_VCPU_GUEST, then the state of the processors
+ * is queried in the guest instead of the hypervisor. This flag is only usable
+ * on live domains. Guest agent may be needed for this flag to be available.
+ *
+ * Returns the number of vCPUs in case of success, -1 in case of failure.
+ */
+int
+virDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    if (flags & VIR_DOMAIN_VCPU_GUEST)
+        virCheckReadOnlyGoto(conn->flags, error);
+
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        virReportInvalidArg(flags,
+                            _("flags 'affect live' and 'affect config' in %s "
+                              "are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainGetVcpusFlags) {
+        int ret;
+        ret = conn->driver->domainGetVcpusFlags(domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainPinVcpu:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @vcpu: virtual CPU number
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN)
+ *      Each bit set to 1 means that corresponding CPU is usable.
+ *      Bytes are stored in little-endian order: CPU0-7, 8-15...
+ *      In each byte, lowest CPU number is least significant bit.
+ * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in
+ *      underlying virtualization system (Xen...).
+ *      If maplen < size, missing bytes are set to zero.
+ *      If maplen > size, failure code is returned.
+ *
+ * Dynamically change the real CPUs which can be allocated to a virtual CPU.
+ * This function may require privileged access to the hypervisor.
+ *
+ * This command only changes the runtime configuration of the domain,
+ * so can only be called on an active domain.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
+                 unsigned char *cpumap, int maplen)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "vcpu=%u, cpumap=%p, maplen=%d",
+                     vcpu, cpumap, maplen);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(cpumap, error);
+    virCheckPositiveArgGoto(maplen, error);
+
+    if ((unsigned short) vcpu != vcpu) {
+        virReportError(VIR_ERR_OVERFLOW, _("input too large: %u"), vcpu);
+        goto error;
+    }
+
+    if (conn->driver->domainPinVcpu) {
+        int ret;
+        ret = conn->driver->domainPinVcpu(domain, vcpu, cpumap, maplen);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainPinVcpuFlags:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @vcpu: virtual CPU number
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN)
+ *      Each bit set to 1 means that corresponding CPU is usable.
+ *      Bytes are stored in little-endian order: CPU0-7, 8-15...
+ *      In each byte, lowest CPU number is least significant bit.
+ * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in
+ *      underlying virtualization system (Xen...).
+ *      If maplen < size, missing bytes are set to zero.
+ *      If maplen > size, failure code is returned.
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Dynamically change the real CPUs which can be allocated to a virtual CPU.
+ * This function may require privileged access to the hypervisor.
+ *
+ * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG.
+ * Both flags may be set.
+ * If VIR_DOMAIN_AFFECT_LIVE is set, the change affects a running domain
+ * and may fail if domain is not alive.
+ * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state,
+ * and will fail for transient domains. If neither flag is specified (that is,
+ * @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain modifies
+ * persistent setup, while an active domain is hypervisor-dependent on whether
+ * just live or both live and persistent state is changed.
+ * Not all hypervisors can support all flag combinations.
+ *
+ * See also virDomainGetVcpuPinInfo for querying this information.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ *
+ */
+int
+virDomainPinVcpuFlags(virDomainPtr domain, unsigned int vcpu,
+                      unsigned char *cpumap, int maplen, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "vcpu=%u, cpumap=%p, maplen=%d, flags=%x",
+                     vcpu, cpumap, maplen, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(cpumap, error);
+    virCheckPositiveArgGoto(maplen, error);
+
+    if ((unsigned short) vcpu != vcpu) {
+        virReportError(VIR_ERR_OVERFLOW, _("input too large: %u"), vcpu);
+        goto error;
+    }
+
+    if (conn->driver->domainPinVcpuFlags) {
+        int ret;
+        ret = conn->driver->domainPinVcpuFlags(domain, vcpu, cpumap, maplen, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetVcpuPinInfo:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @ncpumaps: the number of cpumap (listed first to match virDomainGetVcpus)
+ * @cpumaps: pointer to a bit map of real CPUs for all vcpus of this
+ *     domain (in 8-bit bytes) (OUT)
+ *     It's assumed there is <ncpumaps> cpumap in cpumaps array.
+ *     The memory allocated to cpumaps must be (ncpumaps * maplen) bytes
+ *     (ie: calloc(ncpumaps, maplen)).
+ *     One cpumap inside cpumaps has the format described in
+ *     virDomainPinVcpu() API.
+ *     Must not be NULL.
+ * @maplen: the number of bytes in one cpumap, from 1 up to size of CPU map.
+ *     Must be positive.
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *     Must not be VIR_DOMAIN_AFFECT_LIVE and
+ *     VIR_DOMAIN_AFFECT_CONFIG concurrently.
+ *
+ * Query the CPU affinity setting of all virtual CPUs of domain, store it
+ * in cpumaps.
+ *
+ * Returns the number of virtual CPUs in case of success,
+ * -1 in case of failure.
+ */
+int
+virDomainGetVcpuPinInfo(virDomainPtr domain, int ncpumaps,
+                        unsigned char *cpumaps, int maplen, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "ncpumaps=%d, cpumaps=%p, maplen=%d, flags=%x",
+                     ncpumaps, cpumaps, maplen, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(cpumaps, error);
+    virCheckPositiveArgGoto(ncpumaps, error);
+    virCheckPositiveArgGoto(maplen, error);
+
+    if (INT_MULTIPLY_OVERFLOW(ncpumaps, maplen)) {
+        virReportError(VIR_ERR_OVERFLOW, _("input too large: %d * %d"),
+                       ncpumaps, maplen);
+        goto error;
+    }
+
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        virReportInvalidArg(flags,
+                            _("flags 'affect live' and 'affect config' in %s "
+                              "are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainGetVcpuPinInfo) {
+        int ret;
+        ret = conn->driver->domainGetVcpuPinInfo(domain, ncpumaps,
+                                                 cpumaps, maplen, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainPinEmulator:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN)
+ *      Each bit set to 1 means that corresponding CPU is usable.
+ *      Bytes are stored in little-endian order: CPU0-7, 8-15...
+ *      In each byte, lowest CPU number is least significant bit.
+ * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in
+ *      underlying virtualization system (Xen...).
+ *      If maplen < size, missing bytes are set to zero.
+ *      If maplen > size, failure code is returned.
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Dynamically change the real CPUs which can be allocated to all emulator
+ * threads. This function may require privileged access to the hypervisor.
+ *
+ * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG.
+ * Both flags may be set.
+ * If VIR_DOMAIN_AFFECT_LIVE is set, the change affects a running domain
+ * and may fail if domain is not alive.
+ * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state,
+ * and will fail for transient domains. If neither flag is specified (that is,
+ * @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain modifies
+ * persistent setup, while an active domain is hypervisor-dependent on whether
+ * just live or both live and persistent state is changed.
+ * Not all hypervisors can support all flag combinations.
+ *
+ * See also virDomainGetEmulatorPinInfo for querying this information.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ *
+ */
+int
+virDomainPinEmulator(virDomainPtr domain, unsigned char *cpumap,
+                     int maplen, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "cpumap=%p, maplen=%d, flags=%x",
+                     cpumap, maplen, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    virCheckNonNullArgGoto(cpumap, error);
+    virCheckPositiveArgGoto(maplen, error);
+
+    if (conn->driver->domainPinEmulator) {
+        int ret;
+        ret = conn->driver->domainPinEmulator(domain, cpumap, maplen, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetEmulatorPinInfo:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @cpumap: pointer to a bit map of real CPUs for all emulator threads of
+ *     this domain (in 8-bit bytes) (OUT)
+ *     There is only one cpumap for all emulator threads.
+ *     Must not be NULL.
+ * @maplen: the number of bytes in one cpumap, from 1 up to size of CPU map.
+ *     Must be positive.
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *     Must not be VIR_DOMAIN_AFFECT_LIVE and
+ *     VIR_DOMAIN_AFFECT_CONFIG concurrently.
+ *
+ * Query the CPU affinity setting of all emulator threads of domain, store
+ * it in cpumap.
+ *
+ * Returns 1 in case of success,
+ * 0 in case of no emulator threads are pined to pcpus,
+ * -1 in case of failure.
+ */
+int
+virDomainGetEmulatorPinInfo(virDomainPtr domain, unsigned char *cpumap,
+                            int maplen, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "cpumap=%p, maplen=%d, flags=%x",
+                     cpumap, maplen, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+
+    virCheckNonNullArgGoto(cpumap, error);
+    virCheckPositiveArgGoto(maplen, error);
+
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        virReportInvalidArg(flags,
+                            _("flags 'affect live' and 'affect config' in %s "
+                              "are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainGetEmulatorPinInfo) {
+        int ret;
+        ret = conn->driver->domainGetEmulatorPinInfo(domain, cpumap,
+                                                     maplen, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetVcpus:
+ * @domain: pointer to domain object, or NULL for Domain0
+ * @info: pointer to an array of virVcpuInfo structures (OUT)
+ * @maxinfo: number of structures in info array
+ * @cpumaps: pointer to a bit map of real CPUs for all vcpus of this
+ *      domain (in 8-bit bytes) (OUT)
+ *      If cpumaps is NULL, then no cpumap information is returned by the API.
+ *      It's assumed there is <maxinfo> cpumap in cpumaps array.
+ *      The memory allocated to cpumaps must be (maxinfo * maplen) bytes
+ *      (ie: calloc(maxinfo, maplen)).
+ *      One cpumap inside cpumaps has the format described in
+ *      virDomainPinVcpu() API.
+ * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
+ *      underlying virtualization system (Xen...).
+ *      Must be zero when cpumaps is NULL and positive when it is non-NULL.
+ *
+ * Extract information about virtual CPUs of domain, store it in info array
+ * and also in cpumaps if this pointer isn't NULL.  This call may fail
+ * on an inactive domain.
+ *
+ * See also virDomainGetVcpuPinInfo for querying just cpumaps, including on
+ * an inactive domain.
+ *
+ * Returns the number of info filled in case of success, -1 in case of failure.
+ */
+int
+virDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
+                  unsigned char *cpumaps, int maplen)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "info=%p, maxinfo=%d, cpumaps=%p, maplen=%d",
+                     info, maxinfo, cpumaps, maplen);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(info, error);
+    virCheckPositiveArgGoto(maxinfo, error);
+
+    /* Ensure that domainGetVcpus (aka remoteDomainGetVcpus) does not
+       try to memcpy anything into a NULL pointer.  */
+    if (cpumaps)
+        virCheckPositiveArgGoto(maplen, error);
+    else
+        virCheckZeroArgGoto(maplen, error);
+
+    if (cpumaps && INT_MULTIPLY_OVERFLOW(maxinfo, maplen)) {
+        virReportError(VIR_ERR_OVERFLOW, _("input too large: %d * %d"),
+                       maxinfo, maplen);
+        goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetVcpus) {
+        int ret;
+        ret = conn->driver->domainGetVcpus(domain, info, maxinfo,
+                                           cpumaps, maplen);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetMaxVcpus:
+ * @domain: pointer to domain object
+ *
+ * Provides the maximum number of virtual CPUs supported for
+ * the guest VM. If the guest is inactive, this is basically
+ * the same as virConnectGetMaxVcpus(). If the guest is running
+ * this will reflect the maximum number of virtual CPUs the
+ * guest was booted with.  For more details, see virDomainGetVcpusFlags().
+ *
+ * Returns the maximum of virtual CPU or -1 in case of error.
+ */
+int
+virDomainGetMaxVcpus(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    if (conn->driver->domainGetMaxVcpus) {
+        int ret;
+        ret = conn->driver->domainGetMaxVcpus(domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetSecurityLabel:
+ * @domain: a domain object
+ * @seclabel: pointer to a virSecurityLabel structure
+ *
+ * Extract security label of an active domain. The 'label' field
+ * in the @seclabel argument will be initialized to the empty
+ * string if the domain is not running under a security model.
+ *
+ * Returns 0 in case of success, -1 in case of failure
+ */
+int
+virDomainGetSecurityLabel(virDomainPtr domain, virSecurityLabelPtr seclabel)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "seclabel=%p", seclabel);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(seclabel, error);
+
+    if (conn->driver->domainGetSecurityLabel) {
+        int ret;
+        ret = conn->driver->domainGetSecurityLabel(domain, seclabel);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetSecurityLabelList:
+ * @domain: a domain object
+ * @seclabels: will be auto-allocated and filled with domains' security labels.
+ * Caller must free memory on return.
+ *
+ * Extract the security labels of an active domain. The 'label' field
+ * in the @seclabels argument will be initialized to the empty
+ * string if the domain is not running under a security model.
+ *
+ * Returns number of elemnets in @seclabels on success, -1 in case of failure.
+ */
+int
+virDomainGetSecurityLabelList(virDomainPtr domain,
+                              virSecurityLabelPtr* seclabels)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "seclabels=%p", seclabels);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+
+    virCheckNonNullArgGoto(seclabels, error);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetSecurityLabelList) {
+        int ret;
+        ret = conn->driver->domainGetSecurityLabelList(domain, seclabels);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetMetadata:
+ * @domain: a domain object
+ * @type: type of metadata, from virDomainMetadataType
+ * @metadata: new metadata text
+ * @key: XML namespace key, or NULL
+ * @uri: XML namespace URI, or NULL
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Sets the appropriate domain element given by @type to the
+ * value of @metadata.  A @type of VIR_DOMAIN_METADATA_DESCRIPTION
+ * is free-form text; VIR_DOMAIN_METADATA_TITLE is free-form, but no
+ * newlines are permitted, and should be short (although the length is
+ * not enforced). For these two options @key and @uri are irrelevant and
+ * must be set to NULL.
+ *
+ * For type VIR_DOMAIN_METADATA_ELEMENT @metadata  must be well-formed
+ * XML belonging to namespace defined by @uri with local name @key.
+ *
+ * Passing NULL for @metadata says to remove that element from the
+ * domain XML (passing the empty string leaves the element present).
+ *
+ * The resulting metadata will be present in virDomainGetXMLDesc(),
+ * as well as quick access through virDomainGetMetadata().
+ *
+ * @flags controls whether the live domain, persistent configuration,
+ * or both will be modified.
+ *
+ * Returns 0 on success, -1 in case of failure.
+ */
+int
+virDomainSetMetadata(virDomainPtr domain,
+                     int type,
+                     const char *metadata,
+                     const char *key,
+                     const char *uri,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "type=%d, metadata='%s', key='%s', uri='%s', flags=%x",
+                     type, NULLSTR(metadata), NULLSTR(key), NULLSTR(uri),
+                     flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    switch (type) {
+    case VIR_DOMAIN_METADATA_TITLE:
+        if (metadata && strchr(metadata, '\n')) {
+            virReportInvalidArg(metadata,
+                                _("metadata title in %s can't contain "
+                                  "newlines"),
+                                __FUNCTION__);
+            goto error;
+        }
+        /* fallthrough */
+    case VIR_DOMAIN_METADATA_DESCRIPTION:
+        virCheckNullArgGoto(uri, error);
+        virCheckNullArgGoto(key, error);
+        break;
+    case VIR_DOMAIN_METADATA_ELEMENT:
+        virCheckNonNullArgGoto(uri, error);
+        if (metadata)
+            virCheckNonNullArgGoto(key, error);
+        break;
+    default:
+        /* For future expansion */
+        break;
+    }
+
+    if (conn->driver->domainSetMetadata) {
+        int ret;
+        ret = conn->driver->domainSetMetadata(domain, type, metadata, key, uri,
+                                              flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetMetadata:
+ * @domain: a domain object
+ * @type: type of metadata, from virDomainMetadataType
+ * @uri: XML namespace identifier
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Retrieves the appropriate domain element given by @type.
+ * If VIR_DOMAIN_METADATA_ELEMENT is requested parameter @uri
+ * must be set to the name of the namespace the requested elements
+ * belong to, otherwise must be NULL.
+ *
+ * If an element of the domain XML is not present, the resulting
+ * error will be VIR_ERR_NO_DOMAIN_METADATA.  This method forms
+ * a shortcut for seeing information from virDomainSetMetadata()
+ * without having to go through virDomainGetXMLDesc().
+ *
+ * @flags controls whether the live domain or persistent
+ * configuration will be queried.
+ *
+ * Returns the metadata string on success (caller must free),
+ * or NULL in case of failure.
+ */
+char *
+virDomainGetMetadata(virDomainPtr domain,
+                     int type,
+                     const char *uri,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "type=%d, uri='%s', flags=%x",
+                     type, NULLSTR(uri), flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+
+    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        virReportInvalidArg(flags,
+                            _("flags 'affect live' and 'affect config' in %s "
+                              "are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    switch (type) {
+    case VIR_DOMAIN_METADATA_TITLE:
+    case VIR_DOMAIN_METADATA_DESCRIPTION:
+        virCheckNullArgGoto(uri, error);
+        break;
+    case VIR_DOMAIN_METADATA_ELEMENT:
+        virCheckNonNullArgGoto(uri, error);
+        break;
+    default:
+        /* For future expansion */
+        break;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetMetadata) {
+        char *ret;
+        if (!(ret = conn->driver->domainGetMetadata(domain, type, uri, flags)))
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainAttachDevice:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of one device
+ *
+ * Create a virtual device attachment to backend.  This function,
+ * having hotplug semantics, is only allowed on an active domain.
+ *
+ * For compatibility, this method can also be used to change the media
+ * in an existing CDROM/Floppy device, however, applications are
+ * recommended to use the virDomainUpdateDeviceFlag method instead.
+ *
+ * Be aware that hotplug changes might not persist across a domain going
+ * into S4 state (also known as hibernation) unless you also modify the
+ * persistent domain definition.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainAttachDevice(virDomainPtr domain, const char *xml)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "xml=%s", xml);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(xml, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainAttachDevice) {
+       int ret;
+       ret = conn->driver->domainAttachDevice(domain, xml);
+       if (ret < 0)
+          goto error;
+       return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainAttachDeviceFlags:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of one device
+ * @flags: bitwise-OR of virDomainDeviceModifyFlags
+ *
+ * Attach a virtual device to a domain, using the flags parameter
+ * to control how the device is attached.  VIR_DOMAIN_AFFECT_CURRENT
+ * specifies that the device allocation is made based on current domain
+ * state.  VIR_DOMAIN_AFFECT_LIVE specifies that the device shall be
+ * allocated to the active domain instance only and is not added to the
+ * persisted domain configuration.  VIR_DOMAIN_AFFECT_CONFIG
+ * specifies that the device shall be allocated to the persisted domain
+ * configuration only.  Note that the target hypervisor must return an
+ * error if unable to satisfy flags.  E.g. the hypervisor driver will
+ * return failure if LIVE is specified but it only supports modifying the
+ * persisted device allocation.
+ *
+ * For compatibility, this method can also be used to change the media
+ * in an existing CDROM/Floppy device, however, applications are
+ * recommended to use the virDomainUpdateDeviceFlag method instead.
+ *
+ * Be aware that hotplug changes might not persist across a domain going
+ * into S4 state (also known as hibernation) unless you also modify the
+ * persistent domain definition.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainAttachDeviceFlags(virDomainPtr domain,
+                           const char *xml, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "xml=%s, flags=%x", xml, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(xml, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainAttachDeviceFlags) {
+        int ret;
+        ret = conn->driver->domainAttachDeviceFlags(domain, xml, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainDetachDevice:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of one device
+ *
+ * Destroy a virtual device attachment to backend.  This function,
+ * having hot-unplug semantics, is only allowed on an active domain.
+ *
+ * Be aware that hotplug changes might not persist across a domain going
+ * into S4 state (also known as hibernation) unless you also modify the
+ * persistent domain definition.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainDetachDevice(virDomainPtr domain, const char *xml)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "xml=%s", xml);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(xml, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainDetachDevice) {
+        int ret;
+        ret = conn->driver->domainDetachDevice(domain, xml);
+         if (ret < 0)
+             goto error;
+         return ret;
+     }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainDetachDeviceFlags:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of one device
+ * @flags: bitwise-OR of virDomainDeviceModifyFlags
+ *
+ * Detach a virtual device from a domain, using the flags parameter
+ * to control how the device is detached.  VIR_DOMAIN_AFFECT_CURRENT
+ * specifies that the device allocation is removed based on current domain
+ * state.  VIR_DOMAIN_AFFECT_LIVE specifies that the device shall be
+ * deallocated from the active domain instance only and is not from the
+ * persisted domain configuration.  VIR_DOMAIN_AFFECT_CONFIG
+ * specifies that the device shall be deallocated from the persisted domain
+ * configuration only.  Note that the target hypervisor must return an
+ * error if unable to satisfy flags.  E.g. the hypervisor driver will
+ * return failure if LIVE is specified but it only supports removing the
+ * persisted device allocation.
+ *
+ * Some hypervisors may prevent this operation if there is a current
+ * block copy operation on the device being detached; in that case,
+ * use virDomainBlockJobAbort() to stop the block copy first.
+ *
+ * Beware that depending on the hypervisor and device type, detaching a device
+ * from a running domain may be asynchronous. That is, calling
+ * virDomainDetachDeviceFlags may just request device removal while the device
+ * is actually removed later (in cooperation with a guest OS). Previously,
+ * this fact was ignored and the device could have been removed from domain
+ * configuration before it was actually removed by the hypervisor causing
+ * various failures on subsequent operations. To check whether the device was
+ * successfully removed, either recheck domain configuration using
+ * virDomainGetXMLDesc() or add handler for VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED
+ * event. In case the device is already gone when virDomainDetachDeviceFlags
+ * returns, the event is delivered before this API call ends. To help existing
+ * clients work better in most cases, this API will try to transform an
+ * asynchronous device removal that finishes shortly after the request into
+ * a synchronous removal. In other words, this API may wait a bit for the
+ * removal to complete in case it was not synchronous.
+ *
+ * Be aware that hotplug changes might not persist across a domain going
+ * into S4 state (also known as hibernation) unless you also modify the
+ * persistent domain definition.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainDetachDeviceFlags(virDomainPtr domain,
+                           const char *xml, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "xml=%s, flags=%x", xml, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(xml, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainDetachDeviceFlags) {
+        int ret;
+        ret = conn->driver->domainDetachDeviceFlags(domain, xml, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainUpdateDeviceFlags:
+ * @domain: pointer to domain object
+ * @xml: pointer to XML description of one device
+ * @flags: bitwise-OR of virDomainDeviceModifyFlags
+ *
+ * Change a virtual device on a domain, using the flags parameter
+ * to control how the device is changed.  VIR_DOMAIN_AFFECT_CURRENT
+ * specifies that the device change is made based on current domain
+ * state.  VIR_DOMAIN_AFFECT_LIVE specifies that the device shall be
+ * changed on the active domain instance only and is not added to the
+ * persisted domain configuration. VIR_DOMAIN_AFFECT_CONFIG
+ * specifies that the device shall be changed on the persisted domain
+ * configuration only.  Note that the target hypervisor must return an
+ * error if unable to satisfy flags.  E.g. the hypervisor driver will
+ * return failure if LIVE is specified but it only supports modifying the
+ * persisted device allocation.
+ *
+ * This method is used for actions such changing CDROM/Floppy device
+ * media, altering the graphics configuration such as password,
+ * reconfiguring the NIC device backend connectivity, etc.
+ *
+ * Returns 0 in case of success, -1 in case of failure.
+ */
+int
+virDomainUpdateDeviceFlags(virDomainPtr domain,
+                           const char *xml, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "xml=%s, flags=%x", xml, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(xml, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainUpdateDeviceFlags) {
+        int ret;
+        ret = conn->driver->domainUpdateDeviceFlags(domain, xml, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virConnectDomainEventRegister:
+ * @conn: pointer to the connection
+ * @cb: callback to the function handling domain events
+ * @opaque: opaque data to pass on to the callback
+ * @freecb: optional function to deallocate opaque when not used anymore
+ *
+ * Adds a callback to receive notifications of domain lifecycle events
+ * occurring on a connection.  This function requires that an event loop
+ * has been previously registered with virEventRegisterImpl() or
+ * virEventRegisterDefaultImpl().
+ *
+ * Use of this method is no longer recommended. Instead applications
+ * should try virConnectDomainEventRegisterAny() which has a more flexible
+ * API contract.
+ *
+ * The virDomainPtr object handle passed into the callback upon delivery
+ * of an event is only valid for the duration of execution of the callback.
+ * If the callback wishes to keep the domain object after the callback returns,
+ * it shall take a reference to it, by calling virDomainRef.
+ * The reference can be released once the object is no longer required
+ * by calling virDomainFree.
+ *
+ * Returns 0 on success, -1 on failure.  Older versions of some hypervisors
+ * sometimes returned a positive number on success, but without any reliable
+ * semantics on what that number represents.
+ */
+int
+virConnectDomainEventRegister(virConnectPtr conn,
+                              virConnectDomainEventCallback cb,
+                              void *opaque,
+                              virFreeCallback freecb)
+{
+    VIR_DEBUG("conn=%p, cb=%p, opaque=%p, freecb=%p", conn, cb, opaque, freecb);
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(cb, error);
+
+    if (conn->driver && conn->driver->connectDomainEventRegister) {
+        int ret;
+        ret = conn->driver->connectDomainEventRegister(conn, cb, opaque, freecb);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virConnectDomainEventDeregister:
+ * @conn: pointer to the connection
+ * @cb: callback to the function handling domain events
+ *
+ * Removes a callback previously registered with the
+ * virConnectDomainEventRegister() function.
+ *
+ * Use of this method is no longer recommended. Instead applications
+ * should try virConnectDomainEventDeregisterAny() which has a more flexible
+ * API contract
+ *
+ * Returns 0 on success, -1 on failure.  Older versions of some hypervisors
+ * sometimes returned a positive number on success, but without any reliable
+ * semantics on what that number represents.
+ */
+int
+virConnectDomainEventDeregister(virConnectPtr conn,
+                                virConnectDomainEventCallback cb)
+{
+    VIR_DEBUG("conn=%p, cb=%p", conn, cb);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(cb, error);
+
+    if (conn->driver && conn->driver->connectDomainEventDeregister) {
+        int ret;
+        ret = conn->driver->connectDomainEventDeregister(conn, cb);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainIsActive:
+ * @dom: pointer to the domain object
+ *
+ * Determine if the domain is currently running
+ *
+ * Returns 1 if running, 0 if inactive, -1 on error
+ */
+int
+virDomainIsActive(virDomainPtr dom)
+{
+    VIR_DEBUG("dom=%p", dom);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    if (dom->conn->driver->domainIsActive) {
+        int ret;
+        ret = dom->conn->driver->domainIsActive(dom);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainIsPersistent:
+ * @dom: pointer to the domain object
+ *
+ * Determine if the domain has a persistent configuration
+ * which means it will still exist after shutting down
+ *
+ * Returns 1 if persistent, 0 if transient, -1 on error
+ */
+int
+virDomainIsPersistent(virDomainPtr dom)
+{
+    VIR_DOMAIN_DEBUG(dom);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    if (dom->conn->driver->domainIsPersistent) {
+        int ret;
+        ret = dom->conn->driver->domainIsPersistent(dom);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainIsUpdated:
+ * @dom: pointer to the domain object
+ *
+ * Determine if the domain has been updated.
+ *
+ * Returns 1 if updated, 0 if not, -1 on error
+ */
+int
+virDomainIsUpdated(virDomainPtr dom)
+{
+    VIR_DOMAIN_DEBUG(dom);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    if (dom->conn->driver->domainIsUpdated) {
+        int ret;
+        ret = dom->conn->driver->domainIsUpdated(dom);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetJobInfo:
+ * @domain: a domain object
+ * @info: pointer to a virDomainJobInfo structure allocated by the user
+ *
+ * Extract information about progress of a background job on a domain.
+ * Will return an error if the domain is not active.
+ *
+ * This function returns a limited amount of information in comparison
+ * to virDomainGetJobStats().
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainGetJobInfo(virDomainPtr domain, virDomainJobInfoPtr info)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "info=%p", info);
+
+    virResetLastError();
+
+    if (info)
+        memset(info, 0, sizeof(*info));
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(info, error);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetJobInfo) {
+        int ret;
+        ret = conn->driver->domainGetJobInfo(domain, info);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetJobStats:
+ * @domain: a domain object
+ * @type: where to store the job type (one of virDomainJobType)
+ * @params: where to store job statistics
+ * @nparams: number of items in @params
+ * @flags: bitwise-OR of virDomainGetJobStatsFlags
+ *
+ * Extract information about progress of a background job on a domain.
+ * Will return an error if the domain is not active. The function returns
+ * a superset of progress information provided by virDomainGetJobInfo.
+ * Possible fields returned in @params are defined by VIR_DOMAIN_JOB_*
+ * macros and new fields will likely be introduced in the future so callers
+ * may receive fields that they do not understand in case they talk to a
+ * newer server.
+ *
+ * When @flags contains VIR_DOMAIN_JOB_STATS_COMPLETED, the function will
+ * return statistics about a recently completed job. Specifically, this
+ * flag may be used to query statistics of a completed incoming migration.
+ * Statistics of a completed job are automatically destroyed once read or
+ * when libvirtd is restarted. Note that time information returned for
+ * completed migrations may be completely irrelevant unless both source and
+ * destination hosts have synchronized time (i.e., NTP daemon is running on
+ * both of them).
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainGetJobStats(virDomainPtr domain,
+                     int *type,
+                     virTypedParameterPtr *params,
+                     int *nparams,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "type=%p, params=%p, nparams=%p, flags=%x",
+                     type, params, nparams, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    virCheckNonNullArgGoto(type, error);
+    virCheckNonNullArgGoto(params, error);
+    virCheckNonNullArgGoto(nparams, error);
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetJobStats) {
+        int ret;
+        ret = conn->driver->domainGetJobStats(domain, type, params,
+                                              nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainAbortJob:
+ * @domain: a domain object
+ *
+ * Requests that the current background job be aborted at the
+ * soonest opportunity.
+ *
+ * Returns 0 in case of success and -1 in case of failure.
+ */
+int
+virDomainAbortJob(virDomainPtr domain)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainAbortJob) {
+        int ret;
+        ret = conn->driver->domainAbortJob(domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMigrateSetMaxDowntime:
+ * @domain: a domain object
+ * @downtime: maximum tolerable downtime for live migration, in milliseconds
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Sets maximum tolerable time for which the domain is allowed to be paused
+ * at the end of live migration. It's supposed to be called while the domain is
+ * being live-migrated as a reaction to migration progress.
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainMigrateSetMaxDowntime(virDomainPtr domain,
+                               unsigned long long downtime,
+                               unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "downtime=%llu, flags=%x", downtime, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigrateSetMaxDowntime) {
+        if (conn->driver->domainMigrateSetMaxDowntime(domain, downtime, flags) < 0)
+            goto error;
+        return 0;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMigrateGetCompressionCache:
+ * @domain: a domain object
+ * @cacheSize: return value of current size of the cache (in bytes)
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Gets current size of the cache (in bytes) used for compressing repeatedly
+ * transferred memory pages during live migration.
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainMigrateGetCompressionCache(virDomainPtr domain,
+                                    unsigned long long *cacheSize,
+                                    unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "cacheSize=%p, flags=%x", cacheSize, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(cacheSize, error);
+
+    if (conn->driver->domainMigrateGetCompressionCache) {
+        if (conn->driver->domainMigrateGetCompressionCache(domain, cacheSize,
+                                                           flags) < 0)
+            goto error;
+        return 0;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMigrateSetCompressionCache:
+ * @domain: a domain object
+ * @cacheSize: size of the cache (in bytes) used for compression
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Sets size of the cache (in bytes) used for compressing repeatedly
+ * transferred memory pages during live migration. It's supposed to be called
+ * while the domain is being live-migrated as a reaction to migration progress
+ * and increasing number of compression cache misses obtained from
+ * virDomainGetJobStats.
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainMigrateSetCompressionCache(virDomainPtr domain,
+                                    unsigned long long cacheSize,
+                                    unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "cacheSize=%llu, flags=%x", cacheSize, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigrateSetCompressionCache) {
+        if (conn->driver->domainMigrateSetCompressionCache(domain, cacheSize,
+                                                           flags) < 0)
+            goto error;
+        return 0;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMigrateSetMaxSpeed:
+ * @domain: a domain object
+ * @bandwidth: migration bandwidth limit in MiB/s
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * The maximum bandwidth (in MiB/s) that will be used to do migration
+ * can be specified with the bandwidth parameter. Not all hypervisors
+ * will support a bandwidth cap
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainMigrateSetMaxSpeed(virDomainPtr domain,
+                            unsigned long bandwidth,
+                            unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "bandwidth=%lu, flags=%x", bandwidth, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigrateSetMaxSpeed) {
+        if (conn->driver->domainMigrateSetMaxSpeed(domain, bandwidth, flags) < 0)
+            goto error;
+        return 0;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainMigrateGetMaxSpeed:
+ * @domain: a domain object
+ * @bandwidth: return value of current migration bandwidth limit in MiB/s
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Get the current maximum bandwidth (in MiB/s) that will be used if the
+ * domain is migrated.  Not all hypervisors will support a bandwidth limit.
+ *
+ * Returns 0 in case of success, -1 otherwise.
+ */
+int
+virDomainMigrateGetMaxSpeed(virDomainPtr domain,
+                            unsigned long *bandwidth,
+                            unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "bandwidth = %p, flags=%x", bandwidth, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    virCheckNonNullArgGoto(bandwidth, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainMigrateGetMaxSpeed) {
+        if (conn->driver->domainMigrateGetMaxSpeed(domain, bandwidth, flags) < 0)
+            goto error;
+        return 0;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virConnectDomainEventRegisterAny:
+ * @conn: pointer to the connection
+ * @dom: pointer to the domain
+ * @eventID: the event type to receive
+ * @cb: callback to the function handling domain events
+ * @opaque: opaque data to pass on to the callback
+ * @freecb: optional function to deallocate opaque when not used anymore
+ *
+ * Adds a callback to receive notifications of arbitrary domain events
+ * occurring on a domain.  This function requires that an event loop
+ * has been previously registered with virEventRegisterImpl() or
+ * virEventRegisterDefaultImpl().
+ *
+ * If @dom is NULL, then events will be monitored for any domain. If @dom
+ * is non-NULL, then only the specific domain will be monitored.
+ *
+ * Most types of event have a callback providing a custom set of parameters
+ * for the event. When registering an event, it is thus necessary to use
+ * the VIR_DOMAIN_EVENT_CALLBACK() macro to cast the supplied function pointer
+ * to match the signature of this method.
+ *
+ * The virDomainPtr object handle passed into the callback upon delivery
+ * of an event is only valid for the duration of execution of the callback.
+ * If the callback wishes to keep the domain object after the callback returns,
+ * it shall take a reference to it, by calling virDomainRef().
+ * The reference can be released once the object is no longer required
+ * by calling virDomainFree().
+ *
+ * The return value from this method is a positive integer identifier
+ * for the callback. To unregister a callback, this callback ID should
+ * be passed to the virConnectDomainEventDeregisterAny() method.
+ *
+ * Returns a callback identifier on success, -1 on failure.
+ */
+int
+virConnectDomainEventRegisterAny(virConnectPtr conn,
+                                 virDomainPtr dom,
+                                 int eventID,
+                                 virConnectDomainEventGenericCallback cb,
+                                 void *opaque,
+                                 virFreeCallback freecb)
+{
+    VIR_DOMAIN_DEBUG(dom, "conn=%p, eventID=%d, cb=%p, opaque=%p, freecb=%p",
+                     conn, eventID, cb, opaque, freecb);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    if (dom) {
+        virCheckDomainGoto(dom, error);
+        if (dom->conn != conn) {
+            virReportInvalidArg(dom,
+                                _("domain '%s' in %s must match connection"),
+                                dom->name, __FUNCTION__);
+            goto error;
+        }
+    }
+    virCheckNonNullArgGoto(cb, error);
+    virCheckNonNegativeArgGoto(eventID, error);
+    if (eventID >= VIR_DOMAIN_EVENT_ID_LAST) {
+        virReportInvalidArg(eventID,
+                            _("eventID in %s must be less than %d"),
+                            __FUNCTION__, VIR_DOMAIN_EVENT_ID_LAST);
+        goto error;
+    }
+
+    if (conn->driver && conn->driver->connectDomainEventRegisterAny) {
+        int ret;
+        ret = conn->driver->connectDomainEventRegisterAny(conn, dom, eventID, cb, opaque, freecb);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virConnectDomainEventDeregisterAny:
+ * @conn: pointer to the connection
+ * @callbackID: the callback identifier
+ *
+ * Removes an event callback. The callbackID parameter should be the
+ * value obtained from a previous virConnectDomainEventRegisterAny() method.
+ *
+ * Returns 0 on success, -1 on failure.  Older versions of some hypervisors
+ * sometimes returned a positive number on success, but without any reliable
+ * semantics on what that number represents. */
+int
+virConnectDomainEventDeregisterAny(virConnectPtr conn,
+                                   int callbackID)
+{
+    VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNegativeArgGoto(callbackID, error);
+
+    if (conn->driver && conn->driver->connectDomainEventDeregisterAny) {
+        int ret;
+        ret = conn->driver->connectDomainEventDeregisterAny(conn, callbackID);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainManagedSave:
+ * @dom: pointer to the domain
+ * @flags: bitwise-OR of virDomainSaveRestoreFlags
+ *
+ * This method will suspend a domain and save its memory contents to
+ * a file on disk. After the call, if successful, the domain is not
+ * listed as running anymore.
+ * The difference from virDomainSave() is that libvirt is keeping track of
+ * the saved state itself, and will reuse it once the domain is being
+ * restarted (automatically or via an explicit libvirt call).
+ * As a result any running domain is sure to not have a managed saved image.
+ * This also implies that managed save only works on persistent domains,
+ * since the domain must still exist in order to use virDomainCreate() to
+ * restart it.
+ *
+ * If @flags includes VIR_DOMAIN_SAVE_BYPASS_CACHE, then libvirt will
+ * attempt to bypass the file system cache while creating the file, or
+ * fail if it cannot do so for the given system; this can allow less
+ * pressure on file system cache, but also risks slowing saves to NFS.
+ *
+ * Normally, the managed saved state will remember whether the domain
+ * was running or paused, and start will resume to the same state.
+ * Specifying VIR_DOMAIN_SAVE_RUNNING or VIR_DOMAIN_SAVE_PAUSED in
+ * @flags will override the default saved into the file.  These two
+ * flags are mutually exclusive.
+ *
+ * Returns 0 in case of success or -1 in case of failure
+ */
+int
+virDomainManagedSave(virDomainPtr dom, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if ((flags & VIR_DOMAIN_SAVE_RUNNING) && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
+        virReportInvalidArg(flags,
+                            _("running and paused flags in %s are mutually "
+                              "exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainManagedSave) {
+        int ret;
+
+        ret = conn->driver->domainManagedSave(dom, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainHasManagedSaveImage:
+ * @dom: pointer to the domain
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Check if a domain has a managed save image as created by
+ * virDomainManagedSave(). Note that any running domain should not have
+ * such an image, as it should have been removed on restart.
+ *
+ * Returns 0 if no image is present, 1 if an image is present, and
+ *         -1 in case of error
+ */
+int
+virDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    if (conn->driver->domainHasManagedSaveImage) {
+        int ret;
+
+        ret = conn->driver->domainHasManagedSaveImage(dom, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainManagedSaveRemove:
+ * @dom: pointer to the domain
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Remove any managed save image for this domain.
+ *
+ * Returns 0 in case of success, and -1 in case of error
+ */
+int
+virDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn->driver->domainManagedSaveRemove) {
+        int ret;
+
+        ret = conn->driver->domainManagedSaveRemove(dom, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+
+/**
+ * virDomainOpenConsole:
+ * @dom: a domain object
+ * @dev_name: the console, serial or parallel port device alias, or NULL
+ * @st: a stream to associate with the console
+ * @flags: bitwise-OR of virDomainConsoleFlags
+ *
+ * This opens the backend associated with a console, serial or
+ * parallel port device on a guest, if the backend is supported.
+ * If the @dev_name is omitted, then the first console or serial
+ * device is opened. The console is associated with the passed
+ * in @st stream, which should have been opened in non-blocking
+ * mode for bi-directional I/O.
+ *
+ * By default, when @flags is 0, the open will fail if libvirt
+ * detects that the console is already in use by another client;
+ * passing VIR_DOMAIN_CONSOLE_FORCE will cause libvirt to forcefully
+ * remove the other client prior to opening this console.
+ *
+ * If flag VIR_DOMAIN_CONSOLE_SAFE the console is opened only in the
+ * case where the hypervisor driver supports safe (mutually exclusive)
+ * console handling.
+ *
+ * Older servers did not support either flag, and also did not forbid
+ * simultaneous clients on a console, with potentially confusing results.
+ * When passing @flags of 0 in order to support a wider range of server
+ * versions, it is up to the client to ensure mutual exclusion.
+ *
+ * Returns 0 if the console was opened, -1 on error
+ */
+int
+virDomainOpenConsole(virDomainPtr dom,
+                     const char *dev_name,
+                     virStreamPtr st,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "dev_name=%s, st=%p, flags=%x",
+                     NULLSTR(dev_name), st, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckStreamGoto(st, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn != st->conn) {
+        virReportInvalidArg(st,
+                            _("stream in %s must match connection of domain '%s'"),
+                            __FUNCTION__, dom->name);
+        goto error;
+    }
+
+    if (conn->driver->domainOpenConsole) {
+        int ret;
+        ret = conn->driver->domainOpenConsole(dom, dev_name, st, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainOpenChannel:
+ * @dom: a domain object
+ * @name: the channel name, or NULL
+ * @st: a stream to associate with the channel
+ * @flags: bitwise-OR of virDomainChannelFlags
+ *
+ * This opens the host interface associated with a channel device on a
+ * guest, if the host interface is supported.  If @name is given, it
+ * can match either the device alias (e.g. "channel0"), or the virtio
+ * target name (e.g. "org.qemu.guest_agent.0").  If @name is omitted,
+ * then the first channel is opened. The channel is associated with
+ * the passed in @st stream, which should have been opened in
+ * non-blocking mode for bi-directional I/O.
+ *
+ * By default, when @flags is 0, the open will fail if libvirt detects
+ * that the channel is already in use by another client; passing
+ * VIR_DOMAIN_CHANNEL_FORCE will cause libvirt to forcefully remove the
+ * other client prior to opening this channel.
+ *
+ * Returns 0 if the channel was opened, -1 on error
+ */
+int
+virDomainOpenChannel(virDomainPtr dom,
+                     const char *name,
+                     virStreamPtr st,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "name=%s, st=%p, flags=%x",
+                     NULLSTR(name), st, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckStreamGoto(st, error);
+    virCheckReadOnlyGoto(conn->flags, error);
+
+    if (conn != st->conn) {
+        virReportInvalidArg(st,
+                            _("stream in %s must match connection of domain '%s'"),
+                            __FUNCTION__, dom->name);
+        goto error;
+    }
+
+    if (conn->driver->domainOpenChannel) {
+        int ret;
+        ret = conn->driver->domainOpenChannel(dom, name, st, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockJobAbort:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @flags: bitwise-OR of virDomainBlockJobAbortFlags
+ *
+ * Cancel the active block job on the given disk.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or (since 0.9.5) the device target shorthand
+ * (the <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * If the current block job for @disk is VIR_DOMAIN_BLOCK_JOB_TYPE_PULL, then
+ * by default, this function performs a synchronous operation and the caller
+ * may assume that the operation has completed when 0 is returned.  However,
+ * BlockJob operations may take a long time to cancel, and during this time
+ * further domain interactions may be unresponsive.  To avoid this problem,
+ * pass VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC in the @flags argument to enable
+ * asynchronous behavior, returning as soon as possible.  When the job has
+ * been canceled, a BlockJob event will be emitted, with status
+ * VIR_DOMAIN_BLOCK_JOB_CANCELED (even if the ABORT_ASYNC flag was not
+ * used); it is also possible to poll virDomainBlockJobInfo() to see if
+ * the job cancellation is still pending.  This type of job can be restarted
+ * to pick up from where it left off.
+ *
+ * If the current block job for @disk is VIR_DOMAIN_BLOCK_JOB_TYPE_COPY, then
+ * the default is to abort the mirroring and revert to the source disk;
+ * likewise, if the current job is VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT,
+ * the default is to abort without changing the active layer of @disk.
+ * Adding @flags of VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT causes this call to
+ * fail with VIR_ERR_BLOCK_COPY_ACTIVE if the copy or commit is not yet
+ * ready; otherwise it will swap the disk over to the new active image
+ * to end the mirroring or active commit.  An event will be issued when the
+ * job is ended, and it is possible to use VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC
+ * to control whether this command waits for the completion of the job.
+ * Restarting a copy or active commit job requires starting over from the
+ * beginning of the first phase.
+ *
+ * Returns -1 in case of failure, 0 when successful.
+ */
+int
+virDomainBlockJobAbort(virDomainPtr dom, const char *disk,
+                       unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, flags=%x", disk, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+
+    if (conn->driver->domainBlockJobAbort) {
+        int ret;
+        ret = conn->driver->domainBlockJobAbort(dom, disk, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetBlockJobInfo:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @info: pointer to a virDomainBlockJobInfo structure
+ * @flags: bitwise-OR of virDomainBlockJobInfoFlags
+ *
+ * Request block job information for the given disk.  If an operation is active
+ * @info will be updated with the current progress.  The units used for the
+ * bandwidth field of @info depends on @flags.  If @flags includes
+ * VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES, bandwidth is in bytes/second
+ * (although this mode can risk failure due to overflow, depending on both
+ * client and server word size); otherwise, the value is rounded up to MiB/s.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or (since 0.9.5) the device target shorthand
+ * (the <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * Returns -1 in case of failure, 0 when nothing found, 1 when info was found.
+ */
+int
+virDomainGetBlockJobInfo(virDomainPtr dom, const char *disk,
+                         virDomainBlockJobInfoPtr info, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, info=%p, flags=%x", disk, info, flags);
+
+    virResetLastError();
+
+    if (info)
+        memset(info, 0, sizeof(*info));
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckNonNullArgGoto(disk, error);
+    virCheckNonNullArgGoto(info, error);
+
+    if (conn->driver->domainGetBlockJobInfo) {
+        int ret;
+        ret = conn->driver->domainGetBlockJobInfo(dom, disk, info, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockJobSetSpeed:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @bandwidth: specify bandwidth limit; flags determine the unit
+ * @flags: bitwise-OR of virDomainBlockJobSetSpeedFlags
+ *
+ * Set the maximimum allowable bandwidth that a block job may consume.  If
+ * bandwidth is 0, the limit will revert to the hypervisor default of
+ * unlimited.
+ *
+ * If @flags contains VIR_DOMAIN_BLOCK_JOB_SPEED_BANDWIDTH_BYTES, @bandwidth
+ * is in bytes/second; otherwise, it is in MiB/second.  Values larger than
+ * 2^52 bytes/sec may be rejected due to overflow considerations based on
+ * the word size of both client and server, and values larger than 2^31
+ * bytes/sec may cause overflow problems if later queried by
+ * virDomainGetBlockJobInfo() without scaling.  Hypervisors may further
+ * restrict the range of valid bandwidth values.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or (since 0.9.5) the device target shorthand
+ * (the <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * Returns -1 in case of failure, 0 when successful.
+ */
+int
+virDomainBlockJobSetSpeed(virDomainPtr dom, const char *disk,
+                          unsigned long bandwidth, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, bandwidth=%lu, flags=%x",
+                     disk, bandwidth, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+
+    if (conn->driver->domainBlockJobSetSpeed) {
+        int ret;
+        ret = conn->driver->domainBlockJobSetSpeed(dom, disk, bandwidth, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockPull:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @bandwidth: (optional) specify bandwidth limit; flags determine the unit
+ * @flags: bitwise-OR of virDomainBlockPullFlags
+ *
+ * Populate a disk image with data from its backing image.  Once all data from
+ * its backing image has been pulled, the disk no longer depends on a backing
+ * image.  This function pulls data for the entire device in the background.
+ * Progress of the operation can be checked with virDomainGetBlockJobInfo() and
+ * the operation can be aborted with virDomainBlockJobAbort().  When finished,
+ * an asynchronous event is raised to indicate the final status.  To move
+ * data in the opposite direction, see virDomainBlockCommit().
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or (since 0.9.5) the device target shorthand
+ * (the <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * The maximum bandwidth that will be used to do the copy can be
+ * specified with the @bandwidth parameter.  If set to 0, there is no
+ * limit.  If @flags includes VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES,
+ * @bandwidth is in bytes/second; otherwise, it is in MiB/second.
+ * Values larger than 2^52 bytes/sec may be rejected due to overflow
+ * considerations based on the word size of both client and server,
+ * and values larger than 2^31 bytes/sec may cause overflow problems
+ * if later queried by virDomainGetBlockJobInfo() without scaling.
+ * Hypervisors may further restrict the range of valid bandwidth
+ * values.  Some hypervisors do not support this feature and will
+ * return an error if bandwidth is not 0; in this case, it might still
+ * be possible for a later call to virDomainBlockJobSetSpeed() to
+ * succeed.  The actual speed can be determined with
+ * virDomainGetBlockJobInfo().
+ *
+ * This is shorthand for virDomainBlockRebase() with a NULL base.
+ *
+ * Returns 0 if the operation has started, -1 on failure.
+ */
+int
+virDomainBlockPull(virDomainPtr dom, const char *disk,
+                   unsigned long bandwidth, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, bandwidth=%lu, flags=%x",
+                     disk, bandwidth, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+
+    if (conn->driver->domainBlockPull) {
+        int ret;
+        ret = conn->driver->domainBlockPull(dom, disk, bandwidth, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockRebase:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @base: path to backing file to keep, or device shorthand,
+ *        or NULL for no backing file
+ * @bandwidth: (optional) specify bandwidth limit; flags determine the unit
+ * @flags: bitwise-OR of virDomainBlockRebaseFlags
+ *
+ * Populate a disk image with data from its backing image chain, and
+ * setting the backing image to @base, or alternatively copy an entire
+ * backing chain to a new file @base.
+ *
+ * When @flags is 0, this starts a pull, where @base must be the absolute
+ * path of one of the backing images further up the chain, or NULL to
+ * convert the disk image so that it has no backing image.  Once all
+ * data from its backing image chain has been pulled, the disk no
+ * longer depends on those intermediate backing images.  This function
+ * pulls data for the entire device in the background.  Progress of
+ * the operation can be checked with virDomainGetBlockJobInfo() with a
+ * job type of VIR_DOMAIN_BLOCK_JOB_TYPE_PULL, and the operation can be
+ * aborted with virDomainBlockJobAbort().  When finished, an asynchronous
+ * event is raised to indicate the final status, and the job no longer
+ * exists.  If the job is aborted, a new one can be started later to
+ * resume from the same point.
+ *
+ * If @flags contains VIR_DOMAIN_BLOCK_REBASE_RELATIVE, the name recorded
+ * into the active disk as the location for @base will be kept relative.
+ * The operation will fail if libvirt can't infer the name.
+ *
+ * When @flags includes VIR_DOMAIN_BLOCK_REBASE_COPY, this starts a copy,
+ * where @base must be the name of a new file to copy the chain to.  By
+ * default, the copy will pull the entire source chain into the destination
+ * file, but if @flags also contains VIR_DOMAIN_BLOCK_REBASE_SHALLOW, then
+ * only the top of the source chain will be copied (the source and
+ * destination have a common backing file).  By default, @base will be
+ * created with the same file format as the source, but this can be altered
+ * by adding VIR_DOMAIN_BLOCK_REBASE_COPY_RAW to force the copy to be raw
+ * (does not make sense with the shallow flag unless the source is also raw),
+ * or by using VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT to reuse an existing file
+ * which was pre-created with the correct format and metadata and sufficient
+ * size to hold the copy. In case the VIR_DOMAIN_BLOCK_REBASE_SHALLOW flag
+ * is used the pre-created file has to exhibit the same guest visible contents
+ * as the backing file of the original image. This allows a management app to
+ * pre-create files with relative backing file names, rather than the default
+ * of absolute backing file names; as a security precaution, you should
+ * generally only use reuse_ext with the shallow flag and a non-raw
+ * destination file.  By default, the copy destination will be treated as
+ * type='file', but using VIR_DOMAIN_BLOCK_REBASE_COPY_DEV treats the
+ * destination as type='block' (affecting how virDomainGetBlockInfo() will
+ * report allocation after pivoting).
+ *
+ * A copy job has two parts; in the first phase, the @bandwidth parameter
+ * affects how fast the source is pulled into the destination, and the job
+ * can only be canceled by reverting to the source file; progress in this
+ * phase can be tracked via the virDomainBlockJobInfo() command, with a
+ * job type of VIR_DOMAIN_BLOCK_JOB_TYPE_COPY.  The job transitions to the
+ * second phase when the job info states cur == end, and remains alive to
+ * mirror all further changes to both source and destination.  The user
+ * must call virDomainBlockJobAbort() to end the mirroring while choosing
+ * whether to revert to source or pivot to the destination.  An event is
+ * issued when the job ends, and depending on the hypervisor, an event may
+ * also be issued when the job transitions from pulling to mirroring.  If
+ * the job is aborted, a new job will have to start over from the beginning
+ * of the first phase.
+ *
+ * Some hypervisors will restrict certain actions, such as virDomainSave()
+ * or virDomainDetachDevice(), while a copy job is active; they may
+ * also restrict a copy job to transient domains.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or the device target shorthand (the
+ * <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * The @base parameter can be either a path to a file within the backing
+ * chain, or the device target shorthand (the <target dev='...'/>
+ * sub-element, such as "vda") followed by an index to the backing chain
+ * enclosed in square brackets. Backing chain indexes can be found by
+ * inspecting //disk//backingStore/@index in the domain XML. Thus, for
+ * example, "vda[3]" refers to the backing store with index equal to "3"
+ * in the chain of disk "vda".
+ *
+ * The maximum bandwidth that will be used to do the copy can be
+ * specified with the @bandwidth parameter.  If set to 0, there is no
+ * limit.  If @flags includes VIR_DOMAIN_BLOCK_REBASE_BANDWIDTH_BYTES,
+ * @bandwidth is in bytes/second; otherwise, it is in MiB/second.
+ * Values larger than 2^52 bytes/sec may be rejected due to overflow
+ * considerations based on the word size of both client and server,
+ * and values larger than 2^31 bytes/sec may cause overflow problems
+ * if later queried by virDomainGetBlockJobInfo() without scaling.
+ * Hypervisors may further restrict the range of valid bandwidth
+ * values.  Some hypervisors do not support this feature and will
+ * return an error if bandwidth is not 0; in this case, it might still
+ * be possible for a later call to virDomainBlockJobSetSpeed() to
+ * succeed.  The actual speed can be determined with
+ * virDomainGetBlockJobInfo().
+ *
+ * When @base is NULL and @flags is 0, this is identical to
+ * virDomainBlockPull().  When @flags contains VIR_DOMAIN_BLOCK_REBASE_COPY,
+ * this command is shorthand for virDomainBlockCopy() where the destination
+ * XML encodes @base as a <disk type='file'>, @bandwidth is properly scaled
+ * and passed as a typed parameter, the shallow and reuse external flags
+ * are preserved, and remaining flags control whether the XML encodes a
+ * destination format of raw instead of leaving the destination identical
+ * to the source format or probed from the reused file.
+ *
+ * Returns 0 if the operation has started, -1 on failure.
+ */
+int
+virDomainBlockRebase(virDomainPtr dom, const char *disk,
+                     const char *base, unsigned long bandwidth,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, base=%s, bandwidth=%lu, flags=%x",
+                     disk, NULLSTR(base), bandwidth, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+
+    if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY) {
+        virCheckNonNullArgGoto(base, error);
+    } else if (flags & (VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
+                        VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
+                        VIR_DOMAIN_BLOCK_REBASE_COPY_RAW |
+                        VIR_DOMAIN_BLOCK_REBASE_COPY_DEV)) {
+        virReportInvalidArg(flags,
+                            _("use of flags in %s requires a copy job"),
+                            __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainBlockRebase) {
+        int ret;
+        ret = conn->driver->domainBlockRebase(dom, disk, base, bandwidth,
+                                              flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockCopy:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @destxml: XML description of the copy destination
+ * @params: Pointer to block copy parameter objects, or NULL
+ * @nparams: Number of block copy parameters (this value can be the same or
+ *           less than the number of parameters supported)
+ * @flags: bitwise-OR of virDomainBlockCopyFlags
+ *
+ * Copy the guest-visible contents of a disk image to a new file described
+ * by @destxml.  The destination XML has a top-level element of <disk>, and
+ * resembles what is used when hot-plugging a disk via virDomainAttachDevice(),
+ * except that only sub-elements related to describing the new host resource
+ * are necessary (sub-elements related to the guest view, such as <target>,
+ * are ignored).  It is strongly recommended to include a <driver type='...'/>
+ * format designation for the destination, to avoid the potential of any
+ * security problem that might be caused by probing a file for its format.
+ *
+ * This command starts a long-running copy.  By default, the copy will pull
+ * the entire source chain into the destination file, but if @flags also
+ * contains VIR_DOMAIN_BLOCK_COPY_SHALLOW, then only the top of the source
+ * chain will be copied (the source and destination have a common backing
+ * file).  The format of the destination file is controlled by the <driver>
+ * sub-element of the XML.  The destination will be created unless the
+ * VIR_DOMAIN_BLOCK_COPY_REUSE_EXT flag is present stating that the file
+ * was pre-created with the correct format and metadata and sufficient
+ * size to hold the copy. In case the VIR_DOMAIN_BLOCK_COPY_SHALLOW flag
+ * is used the pre-created file has to exhibit the same guest visible contents
+ * as the backing file of the original image. This allows a management app to
+ * pre-create files with relative backing file names, rather than the default
+ * of absolute backing file names.
+ *
+ * A copy job has two parts; in the first phase, the source is copied into
+ * the destination, and the job can only be canceled by reverting to the
+ * source file; progress in this phase can be tracked via the
+ * virDomainBlockJobInfo() command, with a job type of
+ * VIR_DOMAIN_BLOCK_JOB_TYPE_COPY.  The job transitions to the second
+ * phase when the job info states cur == end, and remains alive to mirror
+ * all further changes to both source and destination.  The user must
+ * call virDomainBlockJobAbort() to end the mirroring while choosing
+ * whether to revert to source or pivot to the destination.  An event is
+ * issued when the job ends, and depending on the hypervisor, an event may
+ * also be issued when the job transitions from pulling to mirroring.  If
+ * the job is aborted, a new job will have to start over from the beginning
+ * of the first phase.
+ *
+ * Some hypervisors will restrict certain actions, such as virDomainSave()
+ * or virDomainDetachDevice(), while a copy job is active; they may
+ * also restrict a copy job to transient domains.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or the device target shorthand (the
+ * <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * The @params and @nparams arguments can be used to set hypervisor-specific
+ * tuning parameters, such as maximum bandwidth or granularity.  For a
+ * parameter that the hypervisor understands, explicitly specifying 0
+ * behaves the same as omitting the parameter, to use the hypervisor
+ * default; however, omitting a parameter is less likely to fail.
+ *
+ * This command is a superset of the older virDomainBlockRebase() when used
+ * with the VIR_DOMAIN_BLOCK_REBASE_COPY flag, and offers better control
+ * over the destination format, the ability to copy to a destination that
+ * is not a local file, and the possibility of additional tuning parameters.
+ *
+ * Returns 0 if the operation has started, -1 on failure.
+ */
+int
+virDomainBlockCopy(virDomainPtr dom, const char *disk,
+                   const char *destxml,
+                   virTypedParameterPtr params,
+                   int nparams,
+                   unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom,
+                     "disk=%s, destxml=%s, params=%p, nparams=%d, flags=%x",
+                     disk, destxml, params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+    virCheckNonNullArgGoto(destxml, error);
+    virCheckNonNegativeArgGoto(nparams, error);
+    if (nparams)
+        virCheckNonNullArgGoto(params, error);
+
+    if (conn->driver->domainBlockCopy) {
+        int ret;
+        ret = conn->driver->domainBlockCopy(dom, disk, destxml,
+                                            params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainBlockCommit:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @base: path to backing file to merge into, or device shorthand,
+ *        or NULL for default
+ * @top: path to file within backing chain that contains data to be merged,
+ *       or device shorthand, or NULL to merge all possible data
+ * @bandwidth: (optional) specify bandwidth limit; flags determine the unit
+ * @flags: bitwise-OR of virDomainBlockCommitFlags
+ *
+ * Commit changes that were made to temporary top-level files within a disk
+ * image backing file chain into a lower-level base file.  In other words,
+ * take all the difference between @base and @top, and update @base to contain
+ * that difference; after the commit, any portion of the chain that previously
+ * depended on @top will now depend on @base, and all files after @base up
+ * to and including @top will now be invalidated.  A typical use of this
+ * command is to reduce the length of a backing file chain after taking an
+ * external disk snapshot.  To move data in the opposite direction, see
+ * virDomainBlockPull().
+ *
+ * This command starts a long-running commit block job, whose status may
+ * be tracked by virDomainBlockJobInfo() with a job type of
+ * VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT, and the operation can be aborted with
+ * virDomainBlockJobAbort().  When finished, an asynchronous event is
+ * raised to indicate the final status, and the job no longer exists.  If
+ * the job is aborted, it is up to the hypervisor whether starting a new
+ * job will resume from the same point, or start over.
+ *
+ * As a special case, if @top is the active image (or NULL), and @flags
+ * includes VIR_DOMAIN_BLOCK_COMMIT_ACTIVE, the block job will have a type
+ * of VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT, and operates in two phases.
+ * In the first phase, the contents are being committed into @base, and the
+ * job can only be canceled.  The job transitions to the second phase when
+ * the job info states cur == end, and remains alive to keep all further
+ * changes to @top synchronized into @base; an event with status
+ * VIR_DOMAIN_BLOCK_JOB_READY is also issued to mark the job transition.
+ * Once in the second phase, the user must choose whether to cancel the job
+ * (keeping @top as the active image, but now containing only the changes
+ * since the time the job ended) or to pivot the job (adjusting to @base as
+ * the active image, and invalidating @top).
+ *
+ * Be aware that this command may invalidate files even if it is aborted;
+ * the user is cautioned against relying on the contents of invalidated
+ * intermediate files such as @top (when @top is not the active image)
+ * without manually rebasing those files to use a backing file of a
+ * read-only copy of @base prior to the point where the commit operation
+ * was started (and such a rebase cannot be safely done until the commit
+ * has successfully completed).  However, the domain itself will not have
+ * any issues; the active layer remains valid throughout the entire commit
+ * operation.
+ *
+ * Some hypervisors may support a shortcut where if @flags contains
+ * VIR_DOMAIN_BLOCK_COMMIT_DELETE, then this command will unlink all files
+ * that were invalidated, after the commit successfully completes.
+ *
+ * If @flags contains VIR_DOMAIN_BLOCK_COMMIT_RELATIVE, the name recorded
+ * into the overlay of the @top image (if there is such image) as the
+ * path to the new backing file will be kept relative to other images.
+ * The operation will fail if libvirt can't infer the name.
+ *
+ * By default, if @base is NULL, the commit target will be the bottom of
+ * the backing chain; if @flags contains VIR_DOMAIN_BLOCK_COMMIT_SHALLOW,
+ * then the immediate backing file of @top will be used instead.  If @top
+ * is NULL, the active image at the top of the chain will be used.  Some
+ * hypervisors place restrictions on how much can be committed, and might
+ * fail if @base is not the immediate backing file of @top, or if @top is
+ * the active layer in use by a running domain but @flags did not include
+ * VIR_DOMAIN_BLOCK_COMMIT_ACTIVE, or if @top is not the top-most file;
+ * restrictions may differ for online vs. offline domains.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or the device target shorthand (the
+ * <target dev='...'/> sub-element, such as "vda").  Valid names
+ * can be found by calling virDomainGetXMLDesc() and inspecting
+ * elements within //domain/devices/disk.
+ *
+ * The @base and @top parameters can be either paths to files within the
+ * backing chain, or the device target shorthand (the <target dev='...'/>
+ * sub-element, such as "vda") followed by an index to the backing chain
+ * enclosed in square brackets. Backing chain indexes can be found by
+ * inspecting //disk//backingStore/@index in the domain XML. Thus, for
+ * example, "vda[3]" refers to the backing store with index equal to "3"
+ * in the chain of disk "vda".
+ *
+ * The maximum bandwidth that will be used to do the commit can be
+ * specified with the @bandwidth parameter.  If set to 0, there is no
+ * limit.  If @flags includes VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES,
+ * @bandwidth is in bytes/second; otherwise, it is in MiB/second.
+ * Values larger than 2^52 bytes/sec may be rejected due to overflow
+ * considerations based on the word size of both client and server,
+ * and values larger than 2^31 bytes/sec may cause overflow problems
+ * if later queried by virDomainGetBlockJobInfo() without scaling.
+ * Hypervisors may further restrict the range of valid bandwidth
+ * values.  Some hypervisors do not support this feature and will
+ * return an error if bandwidth is not 0; in this case, it might still
+ * be possible for a later call to virDomainBlockJobSetSpeed() to
+ * succeed.  The actual speed can be determined with
+ * virDomainGetBlockJobInfo().
+ *
+ * Returns 0 if the operation has started, -1 on failure.
+ */
+int
+virDomainBlockCommit(virDomainPtr dom, const char *disk,
+                     const char *base, const char *top,
+                     unsigned long bandwidth, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, base=%s, top=%s, bandwidth=%lu, flags=%x",
+                     disk, NULLSTR(base), NULLSTR(top), bandwidth, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+
+    if (conn->driver->domainBlockCommit) {
+        int ret;
+        ret = conn->driver->domainBlockCommit(dom, disk, base, top, bandwidth,
+                                              flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainOpenGraphics:
+ * @dom: pointer to domain object
+ * @idx: index of graphics config to open
+ * @fd: file descriptor to attach graphics to
+ * @flags: bitwise-OR of virDomainOpenGraphicsFlags
+ *
+ * This will attempt to connect the file descriptor @fd, to
+ * the graphics backend of @dom. If @dom has multiple graphics
+ * backends configured, then @idx will determine which one is
+ * opened, starting from @idx 0.
+ *
+ * To disable any authentication, pass the VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH
+ * constant for @flags.
+ *
+ * The caller should use an anonymous socketpair to open
+ * @fd before invocation.
+ *
+ * This method can only be used when connected to a local
+ * libvirt hypervisor, over a UNIX domain socket. Attempts
+ * to use this method over a TCP connection will always fail
+ *
+ * Returns 0 on success, -1 on failure
+ */
+int
+virDomainOpenGraphics(virDomainPtr dom,
+                      unsigned int idx,
+                      int fd,
+                      unsigned int flags)
+{
+    struct stat sb;
+    VIR_DOMAIN_DEBUG(dom, "idx=%u, fd=%d, flags=%x",
+                     idx, fd, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckNonNegativeArgGoto(fd, error);
+
+    if (fstat(fd, &sb) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to access file descriptor %d"), fd);
+        goto error;
+    }
+
+    if (!S_ISSOCK(sb.st_mode)) {
+        virReportInvalidArg(fd,
+                          _("fd %d in %s must be a socket"),
+                            fd, __FUNCTION__);
+        goto error;
+    }
+
+    virCheckReadOnlyGoto(dom->conn->flags, error);
+
+    if (!VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
+                                  VIR_DRV_FEATURE_FD_PASSING)) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("fd passing is not supported by this connection"));
+        goto error;
+    }
+
+    if (dom->conn->driver->domainOpenGraphics) {
+        int ret;
+        ret = dom->conn->driver->domainOpenGraphics(dom, idx, fd, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainOpenGraphicsFD:
+ * @dom: pointer to domain object
+ * @idx: index of graphics config to open
+ * @flags: bitwise-OR of virDomainOpenGraphicsFlags
+ *
+ * This will create a socket pair connected to the graphics backend of @dom.
+ * One end of the socket will be returned on success, and the other end is
+ * handed to the hypervisor.
+ * If @dom has multiple graphics backends configured, then @idx will determine
+ * which one is opened, starting from @idx 0.
+ *
+ * To disable any authentication, pass the VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH
+ * constant for @flags.
+ *
+ * This method can only be used when connected to a local
+ * libvirt hypervisor, over a UNIX domain socket. Attempts
+ * to use this method over a TCP connection will always fail.
+ *
+ * Returns an fd on success, -1 on failure
+ */
+int
+virDomainOpenGraphicsFD(virDomainPtr dom,
+                        unsigned int idx,
+                        unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "idx=%u, flags=%x", idx, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    virCheckReadOnlyGoto(dom->conn->flags, error);
+
+    if (!VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
+                                  VIR_DRV_FEATURE_FD_PASSING)) {
+        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
+                       _("fd passing is not supported by this connection"));
+        goto error;
+    }
+
+    if (dom->conn->driver->domainOpenGraphicsFD) {
+        int ret;
+        ret = dom->conn->driver->domainOpenGraphicsFD(dom, idx, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainSetBlockIoTune:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @params: Pointer to blkio parameter objects
+ * @nparams: Number of blkio parameters (this value can be the same or
+ *           less than the number of parameters supported)
+ * @flags: bitwise-OR of virDomainModificationImpact
+ *
+ * Change all or a subset of the per-device block IO tunables.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or the device target shorthand (the <target
+ * dev='...'/> sub-element, such as "xvda").  Valid names can be found
+ * by calling virDomainGetXMLDesc() and inspecting elements
+ * within //domain/devices/disk.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainSetBlockIoTune(virDomainPtr dom,
+                        const char *disk,
+                        virTypedParameterPtr params,
+                        int nparams,
+                        unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, params=%p, nparams=%d, flags=%x",
+                     disk, params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    conn = dom->conn;
+
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(disk, error);
+    virCheckPositiveArgGoto(nparams, error);
+    virCheckNonNullArgGoto(params, error);
+
+    if (virTypedParameterValidateSet(dom->conn, params, nparams) < 0)
+        goto error;
+
+    if (conn->driver->domainSetBlockIoTune) {
+        int ret;
+        ret = conn->driver->domainSetBlockIoTune(dom, disk, params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetBlockIoTune:
+ * @dom: pointer to domain object
+ * @disk: path to the block device, or device shorthand
+ * @params: Pointer to blkio parameter object
+ *          (return value, allocated by the caller)
+ * @nparams: Pointer to number of blkio parameters
+ * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
+ *
+ * Get all block IO tunable parameters for a given device.  On input,
+ * @nparams gives the size of the @params array; on output, @nparams
+ * gives how many slots were filled with parameter information, which
+ * might be less but will not exceed the input value.
+ *
+ * As a special case, calling with @params as NULL and @nparams as 0
+ * on input will cause @nparams on output to contain the number of
+ * parameters supported by the hypervisor, either for the given @disk
+ * (note that block devices of different types might support different
+ * parameters), or if @disk is NULL, for all possible disks. The
+ * caller should then allocate @params array,
+ * i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
+ * again.  See virDomainGetMemoryParameters() for more details.
+ *
+ * The @disk parameter is either an unambiguous source name of the
+ * block device (the <source file='...'/> sub-element, such as
+ * "/path/to/image"), or the device target shorthand (the <target
+ * dev='...'/> sub-element, such as "xvda").  Valid names can be found
+ * by calling virDomainGetXMLDesc() and inspecting elements
+ * within //domain/devices/disk.  This parameter cannot be NULL
+ * unless @nparams is 0 on input.
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int
+virDomainGetBlockIoTune(virDomainPtr dom,
+                        const char *disk,
+                        virTypedParameterPtr params,
+                        int *nparams,
+                        unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(dom, "disk=%s, params=%p, nparams=%d, flags=%x",
+                     NULLSTR(disk), params, (nparams) ? *nparams : -1, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (*nparams != 0) {
+        virCheckNonNullArgGoto(params, error);
+        virCheckNonNullArgGoto(disk, error);
+    }
+
+    if (VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+    /* At most one of these two flags should be set.  */
+    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
+        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
+        virReportInvalidArg(flags,
+                            _("flags 'affect live' and 'affect config' in %s "
+                              "are mutually exclusive"),
+                            __FUNCTION__);
+        goto error;
+    }
+    conn = dom->conn;
+
+    if (conn->driver->domainGetBlockIoTune) {
+        int ret;
+        ret = conn->driver->domainGetBlockIoTune(dom, disk, params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetCPUStats:
+ * @domain: domain to query
+ * @params: array to populate on output
+ * @nparams: number of parameters per cpu
+ * @start_cpu: which cpu to start with, or -1 for summary
+ * @ncpus: how many cpus to query
+ * @flags: bitwise-OR of virTypedParameterFlags
+ *
+ * Get statistics relating to CPU usage attributable to a single
+ * domain (in contrast to the statistics returned by
+ * virNodeGetCPUStats() for all processes on the host).  @dom
+ * must be running (an inactive domain has no attributable cpu
+ * usage).  On input, @params must contain at least @nparams * @ncpus
+ * entries, allocated by the caller.
+ *
+ * If @start_cpu is -1, then @ncpus must be 1, and the returned
+ * results reflect the statistics attributable to the entire
+ * domain (such as user and system time for the process as a
+ * whole).  Otherwise, @start_cpu represents which cpu to start
+ * with, and @ncpus represents how many consecutive processors to
+ * query, with statistics attributable per processor (such as
+ * per-cpu usage).  If @ncpus is larger than the number of cpus
+ * available to query, then the trailing part of the array will
+ * be unpopulated.
+ *
+ * The remote driver imposes a limit of 128 @ncpus and 16 @nparams;
+ * the number of parameters per cpu should not exceed 16, but if you
+ * have a host with more than 128 CPUs, your program should split
+ * the request into multiple calls.
+ *
+ * As special cases, if @params is NULL and @nparams is 0 and
+ * @ncpus is 1, and the return value will be how many
+ * statistics are available for the given @start_cpu.  This number
+ * may be different for @start_cpu of -1 than for any non-negative
+ * value, but will be the same for all non-negative @start_cpu.
+ * Likewise, if @params is NULL and @nparams is 0 and @ncpus is 0,
+ * the number of cpus available to query is returned.  From the
+ * host perspective, this would typically match the cpus member
+ * of virNodeGetInfo(), but might be less due to host cpu hotplug.
+ *
+ * For now, @flags is unused, and the statistics all relate to the
+ * usage from the host perspective.  It is possible that a future
+ * version will support a flag that queries the cpu usage from the
+ * guest's perspective, where the maximum cpu to query would be
+ * related to virDomainGetVcpusFlags() rather than virNodeGetInfo().
+ * An individual guest vcpu cannot be reliably mapped back to a
+ * specific host cpu unless a single-processor vcpu pinning was used,
+ * but when @start_cpu is -1, any difference in usage between a host
+ * and guest perspective would serve as a measure of hypervisor overhead.
+ *
+ * Typical use sequence is below.
+ *
+ * getting total stats: set start_cpu as -1, ncpus 1
+ * virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0) => nparams
+ * params = calloc(nparams, sizeof(virTypedParameter))
+ * virDomainGetCPUStats(dom, params, nparams, -1, 1, 0) => total stats.
+ *
+ * getting per-cpu stats:
+ * virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0) => ncpus
+ * virDomainGetCPUStats(dom, NULL, 0, 0, 1, 0) => nparams
+ * params = calloc(ncpus * nparams, sizeof(virTypedParameter))
+ * virDomainGetCPUStats(dom, params, nparams, 0, ncpus, 0) => per-cpu stats
+ *
+ * Returns -1 on failure, or the number of statistics that were
+ * populated per cpu on success (this will be less than the total
+ * number of populated @params, unless @ncpus was 1; and may be
+ * less than @nparams).  The populated parameters start at each
+ * stride of @nparams, which means the results may be discontiguous;
+ * any unpopulated parameters will be zeroed on success (this includes
+ * skipped elements if @nparams is too large, and tail elements if
+ * @ncpus is too large).  The caller is responsible for freeing any
+ * returned string parameters.
+ */
+int
+virDomainGetCPUStats(virDomainPtr domain,
+                     virTypedParameterPtr params,
+                     unsigned int nparams,
+                     int start_cpu,
+                     unsigned int ncpus,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain,
+                     "params=%p, nparams=%d, start_cpu=%d, ncpus=%u, flags=%x",
+                     params, nparams, start_cpu, ncpus, flags);
+    virResetLastError();
+
+    virCheckDomainReturn(domain, -1);
+    conn = domain->conn;
+
+    /* Special cases:
+     * start_cpu must be non-negative, or else -1
+     * if start_cpu is -1, ncpus must be 1
+     * params == NULL must match nparams == 0
+     * ncpus must be non-zero unless params == NULL
+     * nparams * ncpus must not overflow (RPC may restrict it even more)
+     */
+    if (start_cpu == -1) {
+        if (ncpus != 1) {
+            virReportInvalidArg(start_cpu,
+                                _("ncpus in %s must be 1 when start_cpu is -1"),
+                                __FUNCTION__);
+            goto error;
+        }
+    } else {
+        virCheckNonNegativeArgGoto(start_cpu, error);
+    }
+    if (nparams)
+        virCheckNonNullArgGoto(params, error);
+    else
+        virCheckNullArgGoto(params, error);
+    if (ncpus == 0)
+        virCheckNullArgGoto(params, error);
+
+    if (nparams && ncpus > UINT_MAX / nparams) {
+        virReportError(VIR_ERR_OVERFLOW, _("input too large: %u * %u"),
+                       nparams, ncpus);
+        goto error;
+    }
+    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+    if (conn->driver->domainGetCPUStats) {
+        int ret;
+
+        ret = conn->driver->domainGetCPUStats(domain, params, nparams,
+                                              start_cpu, ncpus, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetDiskErrors:
+ * @dom: a domain object
+ * @errors: array to populate on output
+ * @maxerrors: size of @errors array
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * The function populates @errors array with all disks that encountered an
+ * I/O error.  Disks with no error will not be returned in the @errors array.
+ * Each disk is identified by its target (the dev attribute of target
+ * subelement in domain XML), such as "vda", and accompanied with the error
+ * that was seen on it.  The caller is also responsible for calling free()
+ * on each disk name returned.
+ *
+ * In a special case when @errors is NULL and @maxerrors is 0, the function
+ * returns preferred size of @errors that the caller should use to get all
+ * disk errors.
+ *
+ * Since calling virDomainGetDiskErrors(dom, NULL, 0, 0) to get preferred size
+ * of @errors array and getting the errors are two separate operations, new
+ * disks may be hotplugged to the domain and new errors may be encountered
+ * between the two calls.  Thus, this function may not return all disk errors
+ * because the supplied array is not large enough.  Such errors may, however,
+ * be detected by listening to domain events.
+ *
+ * Returns number of disks with errors filled in the @errors array or -1 on
+ * error.
+ */
+int
+virDomainGetDiskErrors(virDomainPtr dom,
+                       virDomainDiskErrorPtr errors,
+                       unsigned int maxerrors,
+                       unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "errors=%p, maxerrors=%u, flags=%x",
+                     errors, maxerrors, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    if (maxerrors)
+        virCheckNonNullArgGoto(errors, error);
+    else
+        virCheckNullArgGoto(errors, error);
+
+    if (dom->conn->driver->domainGetDiskErrors) {
+        int ret = dom->conn->driver->domainGetDiskErrors(dom, errors,
+                                                         maxerrors, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+/**
+ * virDomainGetHostname:
+ * @domain: a domain object
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Get the hostname for that domain.
+ *
+ * Dependent on hypervisor used, this may require a guest agent to be
+ * available.
+ *
+ * Returns the hostname which must be freed by the caller, or
+ * NULL if there was an error.
+ */
+char *
+virDomainGetHostname(virDomainPtr domain, unsigned int flags)
+{
+    virConnectPtr conn;
+
+    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(domain, NULL);
+    conn = domain->conn;
+
+    if (conn->driver->domainGetHostname) {
+        char *ret;
+        ret = conn->driver->domainGetHostname(domain, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(domain->conn);
+    return NULL;
+}
+
+
+/**
+ * virDomainFSTrim:
+ * @dom: a domain object
+ * @mountPoint: which mount point to trim
+ * @minimum: Minimum contiguous free range to discard in bytes
+ * @flags: extra flags, not used yet, so callers should always pass 0
+ *
+ * Calls FITRIM within the guest (hence guest agent may be
+ * required depending on hypervisor used). Either call it on each
+ * mounted filesystem (@mountPoint is NULL) or just on specified
+ * @mountPoint. @minimum hints that free ranges smaller than this
+ * may be ignored (this is a hint and the guest may not respect
+ * it).  By increasing this value, the fstrim operation will
+ * complete more quickly for filesystems with badly fragmented
+ * free space, although not all blocks will be discarded.
+ * If @minimum is not zero, the command may fail.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int
+virDomainFSTrim(virDomainPtr dom,
+                const char *mountPoint,
+                unsigned long long minimum,
+                unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "mountPoint=%s, minimum=%llu, flags=%x",
+                     mountPoint, minimum, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckReadOnlyGoto(dom->conn->flags, error);
+
+    if (dom->conn->driver->domainFSTrim) {
+        int ret = dom->conn->driver->domainFSTrim(dom, mountPoint,
+                                                  minimum, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+/**
+ * virDomainFSFreeze:
+ * @dom: a domain object
+ * @mountpoints: list of mount points to be frozen
+ * @nmountpoints: the number of mount points specified in @mountpoints
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Freeze specified filesystems within the guest (hence guest agent
+ * may be required depending on hypervisor used). If @mountpoints is NULL and
+ * @nmountpoints is 0, every mounted filesystem on the guest is frozen.
+ * In some environments (e.g. QEMU guest with guest agent which doesn't
+ * support mountpoints argument), @mountpoints may need to be NULL.
+ *
+ * Returns the number of frozen filesystems on success, -1 otherwise.
+ */
+int
+virDomainFSFreeze(virDomainPtr dom,
+                  const char **mountpoints,
+                  unsigned int nmountpoints,
+                  unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "mountpoints=%p, nmountpoints=%d, flags=%x",
+                     mountpoints, nmountpoints, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckReadOnlyGoto(dom->conn->flags, error);
+    if (nmountpoints)
+        virCheckNonNullArgGoto(mountpoints, error);
+    else
+        virCheckNullArgGoto(mountpoints, error);
+
+    if (dom->conn->driver->domainFSFreeze) {
+        int ret = dom->conn->driver->domainFSFreeze(
+            dom, mountpoints, nmountpoints, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+/**
+ * virDomainFSThaw:
+ * @dom: a domain object
+ * @mountpoints: list of mount points to be thawed
+ * @nmountpoints: the number of mount points specified in @mountpoints
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Thaw specified filesystems within the guest. If @mountpoints is NULL and
+ * @nmountpoints is 0, every mounted filesystem on the guest is thawed.
+ * In some drivers (e.g. QEMU driver), @mountpoints may need to be NULL.
+ *
+ * Returns the number of thawed filesystems on success, -1 otherwise.
+ */
+int
+virDomainFSThaw(virDomainPtr dom,
+                const char **mountpoints,
+                unsigned int nmountpoints,
+                unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckReadOnlyGoto(dom->conn->flags, error);
+    if (nmountpoints)
+        virCheckNonNullArgGoto(mountpoints, error);
+    else
+        virCheckNullArgGoto(mountpoints, error);
+
+    if (dom->conn->driver->domainFSThaw) {
+        int ret = dom->conn->driver->domainFSThaw(
+            dom, mountpoints, nmountpoints, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+/**
+ * virDomainGetTime:
+ * @dom: a domain object
+ * @seconds: domain's time in seconds
+ * @nseconds: the nanoscond part of @seconds
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Extract information about guest time and store it into
+ * @seconds and @nseconds. The @seconds represents the number of
+ * seconds since the UNIX Epoch of 1970-01-01 00:00:00 in UTC.
+ *
+ * Please note that some hypervisors may require guest agent to
+ * be configured and running in order to run this API.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int
+virDomainGetTime(virDomainPtr dom,
+                 long long *seconds,
+                 unsigned int *nseconds,
+                 unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "seconds=%p, nseconds=%p, flags=%x",
+                     seconds, nseconds, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    if (dom->conn->driver->domainGetTime) {
+        int ret = dom->conn->driver->domainGetTime(dom, seconds,
+                                                   nseconds, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+/**
+ * virDomainSetTime:
+ * @dom: a domain object
+ * @seconds: time to set
+ * @nseconds: the nanosecond part of @seconds
+ * @flags: bitwise-OR of virDomainSetTimeFlags
+ *
+ * When a domain is suspended or restored from a file the
+ * domain's OS has no idea that there was a big gap in the time.
+ * Depending on how long the gap was, NTP might not be able to
+ * resynchronize the guest.
+ *
+ * This API tries to set guest time to the given value. The time
+ * to set (@seconds and @nseconds) should be in seconds relative
+ * to the Epoch of 1970-01-01 00:00:00 in UTC.
+ *
+ * Please note that some hypervisors may require guest agent to
+ * be configured and running in order to be able to run this API.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int
+virDomainSetTime(virDomainPtr dom,
+                 long long seconds,
+                 unsigned int nseconds,
+                 unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "seconds=%lld, nseconds=%u, flags=%x",
+                     seconds, nseconds, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckReadOnlyGoto(dom->conn->flags, error);
+
+    if (dom->conn->driver->domainSetTime) {
+        int ret = dom->conn->driver->domainSetTime(dom, seconds,
+                                                   nseconds, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+
+
+/**
+ * virConnectGetDomainCapabilities:
+ * @conn: pointer to the hypervisor connection
+ * @emulatorbin: path to emulator
+ * @arch: domain architecture
+ * @machine: machine type
+ * @virttype: virtualization type
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Prior creating a domain (for instance via virDomainCreateXML
+ * or virDomainDefineXML) it may be suitable to know what the
+ * underlying emulator and/or libvirt is capable of. For
+ * instance, if host, libvirt and qemu is capable of VFIO
+ * passthrough and so on.
+ *
+ * Returns NULL in case of error or an XML string
+ * defining the capabilities.
+ */
+char *
+virConnectGetDomainCapabilities(virConnectPtr conn,
+                                const char *emulatorbin,
+                                const char *arch,
+                                const char *machine,
+                                const char *virttype,
+                                unsigned int flags)
+{
+    VIR_DEBUG("conn=%p, emulatorbin=%s, arch=%s, "
+              "machine=%s, virttype=%s, flags=%x",
+              conn, NULLSTR(emulatorbin), NULLSTR(arch),
+              NULLSTR(machine), NULLSTR(virttype), flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, NULL);
+
+    if (conn->driver->connectGetDomainCapabilities) {
+        char *ret;
+        ret = conn->driver->connectGetDomainCapabilities(conn, emulatorbin,
+                                                         arch, machine,
+                                                         virttype, flags);
+        if (!ret)
+            goto error;
+        VIR_DEBUG("conn=%p, ret=%s", conn, ret);
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return NULL;
+}
+
+
+/**
+ * virConnectGetAllDomainStats:
+ * @conn: pointer to the hypervisor connection
+ * @stats: stats to return, binary-OR of virDomainStatsTypes
+ * @retStats: Pointer that will be filled with the array of returned stats
+ * @flags: extra flags; binary-OR of virConnectGetAllDomainStatsFlags
+ *
+ * Query statistics for all domains on a given connection.
+ *
+ * Report statistics of various parameters for a running VM according to @stats
+ * field. The statistics are returned as an array of structures for each queried
+ * domain. The structure contains an array of typed parameters containing the
+ * individual statistics. The typed parameter name for each statistic field
+ * consists of a dot-separated string containing name of the requested group
+ * followed by a group specific description of the statistic value.
+ *
+ * The statistic groups are enabled using the @stats parameter which is a
+ * binary-OR of enum virDomainStatsTypes. The following groups are available
+ * (although not necessarily implemented for each hypervisor):
+ *
+ * VIR_DOMAIN_STATS_STATE: Return domain state and reason for entering that
+ * state. The typed parameter keys are in this format:
+ * "state.state" - state of the VM, returned as int from virDomainState enum
+ * "state.reason" - reason for entering given state, returned as int from
+ *                  virDomain*Reason enum corresponding to given state.
+ *
+ * VIR_DOMAIN_STATS_CPU_TOTAL: Return CPU statistics and usage information.
+ * The typed parameter keys are in this format:
+ * "cpu.time" - total cpu time spent for this domain in nanoseconds
+ *              as unsigned long long.
+ * "cpu.user" - user cpu time spent in nanoseconds as unsigned long long.
+ * "cpu.system" - system cpu time spent in nanoseconds as unsigned long long.
+ *
+ * VIR_DOMAIN_STATS_BALLOON: Return memory balloon device information.
+ * The typed parameter keys are in this format:
+ * "balloon.current" - the memory in kiB currently used
+ *                     as unsigned long long.
+ * "balloon.maximum" - the maximum memory in kiB allowed
+ *                     as unsigned long long.
+ *
+ * VIR_DOMAIN_STATS_VCPU: Return virtual CPU statistics.
+ * Due to VCPU hotplug, the vcpu.<num>.* array could be sparse.
+ * The actual size of the array corresponds to "vcpu.current".
+ * The array size will never exceed "vcpu.maximum".
+ * The typed parameter keys are in this format:
+ * "vcpu.current" - current number of online virtual CPUs as unsigned int.
+ * "vcpu.maximum" - maximum number of online virtual CPUs as unsigned int.
+ * "vcpu.<num>.state" - state of the virtual CPU <num>, as int
+ *                      from virVcpuState enum.
+ * "vcpu.<num>.time" - virtual cpu time spent by virtual CPU <num>
+ *                     as unsigned long long.
+ *
+ * VIR_DOMAIN_STATS_INTERFACE: Return network interface statistics.
+ * The typed parameter keys are in this format:
+ * "net.count" - number of network interfaces on this domain
+ *               as unsigned int.
+ * "net.<num>.name" - name of the interface <num> as string.
+ * "net.<num>.rx.bytes" - bytes received as unsigned long long.
+ * "net.<num>.rx.pkts" - packets received as unsigned long long.
+ * "net.<num>.rx.errs" - receive errors as unsigned long long.
+ * "net.<num>.rx.drop" - receive packets dropped as unsigned long long.
+ * "net.<num>.tx.bytes" - bytes transmitted as unsigned long long.
+ * "net.<num>.tx.pkts" - packets transmitted as unsigned long long.
+ * "net.<num>.tx.errs" - transmission errors as unsigned long long.
+ * "net.<num>.tx.drop" - transmit packets dropped as unsigned long long.
+ *
+ * VIR_DOMAIN_STATS_BLOCK: Return block devices statistics.
+ * The typed parameter keys are in this format:
+ * "block.count" - number of block devices on this domain
+ *                 as unsigned int.
+ * "block.<num>.name" - name of the block device <num> as string.
+ *                      matches the target name (vda/sda/hda) of the
+ *                      block device.
+ * "block.<num>.rd.reqs" - number of read requests as unsigned long long.
+ * "block.<num>.rd.bytes" - number of read bytes as unsigned long long.
+ * "block.<num>.rd.times" - total time (ns) spent on reads as
+ *                          unsigned long long.
+ * "block.<num>.wr.reqs" - number of write requests as unsigned long long.
+ * "block.<num>.wr.bytes" - number of written bytes as unsigned long long.
+ * "block.<num>.wr.times" - total time (ns) spent on writes as
+ *                          unsigned long long.
+ * "block.<num>.fl.reqs" - total flush requests as unsigned long long.
+ * "block.<num>.fl.times" - total time (ns) spent on cache flushing as
+ *                          unsigned long long.
+ * "block.<num>.errors" - Xen only: the 'oo_req' value as
+ *                        unsigned long long.
+ * "block.<num>.allocation" - offset of the highest written sector
+ *                            as unsigned long long.
+ * "block.<num>.capacity" - logical size in bytes of the block device backing
+ *                          image as unsigned long long.
+ * "block.<num>.physical" - physical size in bytes of the container of the
+ *                          backing image as unsigned long long.
+ *
+ * Note that entire stats groups or individual stat fields may be missing from
+ * the output in case they are not supported by the given hypervisor, are not
+ * applicable for the current state of the guest domain, or their retrieval
+ * was not successful.
+ *
+ * Using 0 for @stats returns all stats groups supported by the given
+ * hypervisor.
+ *
+ * Specifying VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS as @flags makes
+ * the function return error in case some of the stat types in @stats were
+ * not recognized by the daemon.
+ *
+ * Similarly to virConnectListAllDomains, @flags can contain various flags to
+ * filter the list of domains to provide stats for.
+ *
+ * VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE selects online domains while
+ * VIR_CONNECT_GET_ALL_DOMAINS_STATS_INACTIVE selects offline ones.
+ *
+ * VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT and
+ * VIR_CONNECT_GET_ALL_DOMAINS_STATS_TRANSIENT allow to filter the list
+ * according to their persistence.
+ *
+ * To filter the list of VMs by domain state @flags can contain
+ * VIR_CONNECT_GET_ALL_DOMAINS_STATS_RUNNING,
+ * VIR_CONNECT_GET_ALL_DOMAINS_STATS_PAUSED,
+ * VIR_CONNECT_GET_ALL_DOMAINS_STATS_SHUTOFF and/or
+ * VIR_CONNECT_GET_ALL_DOMAINS_STATS_OTHER for all other states.
+ *
+ * Returns the count of returned statistics structures on success, -1 on error.
+ * The requested data are returned in the @retStats parameter. The returned
+ * array should be freed by the caller. See virDomainStatsRecordListFree.
+ */
+int
+virConnectGetAllDomainStats(virConnectPtr conn,
+                            unsigned int stats,
+                            virDomainStatsRecordPtr **retStats,
+                            unsigned int flags)
+{
+    int ret = -1;
+
+    VIR_DEBUG("conn=%p, stats=0x%x, retStats=%p, flags=0x%x",
+              conn, stats, retStats, flags);
+
+    virResetLastError();
+
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(retStats, cleanup);
+
+    if (!conn->driver->connectGetAllDomainStats) {
+        virReportUnsupportedError();
+        goto cleanup;
+    }
+
+    ret = conn->driver->connectGetAllDomainStats(conn, NULL, 0, stats,
+                                                 retStats, flags);
+
+ cleanup:
+    if (ret < 0)
+        virDispatchError(conn);
+
+    return ret;
+}
+
+
+/**
+ * virDomainListGetStats:
+ * @doms: NULL terminated array of domains
+ * @stats: stats to return, binary-OR of virDomainStatsTypes
+ * @retStats: Pointer that will be filled with the array of returned stats
+ * @flags: extra flags; binary-OR of virConnectGetAllDomainStatsFlags
+ *
+ * Query statistics for domains provided by @doms. Note that all domains in
+ * @doms must share the same connection.
+ *
+ * Report statistics of various parameters for a running VM according to @stats
+ * field. The statistics are returned as an array of structures for each queried
+ * domain. The structure contains an array of typed parameters containing the
+ * individual statistics. The typed parameter name for each statistic field
+ * consists of a dot-separated string containing name of the requested group
+ * followed by a group specific description of the statistic value.
+ *
+ * The statistic groups are enabled using the @stats parameter which is a
+ * binary-OR of enum virDomainStatsTypes. The stats groups are documented
+ * in virConnectGetAllDomainStats.
+ *
+ * Using 0 for @stats returns all stats groups supported by the given
+ * hypervisor.
+ *
+ * Specifying VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS as @flags makes
+ * the function return error in case some of the stat types in @stats were
+ * not recognized by the daemon.
+ *
+ * Note that any of the domain list filtering flags in @flags will be rejected
+ * by this function.
+ *
+ * Returns the count of returned statistics structures on success, -1 on error.
+ * The requested data are returned in the @retStats parameter. The returned
+ * array should be freed by the caller. See virDomainStatsRecordListFree.
+ * Note that the count of returned stats may be less than the domain count
+ * provided via @doms.
+ */
+int
+virDomainListGetStats(virDomainPtr *doms,
+                      unsigned int stats,
+                      virDomainStatsRecordPtr **retStats,
+                      unsigned int flags)
+{
+    virConnectPtr conn = NULL;
+    virDomainPtr *nextdom = doms;
+    unsigned int ndoms = 0;
+    int ret = -1;
+
+    VIR_DEBUG("doms=%p, stats=0x%x, retStats=%p, flags=0x%x",
+              doms, stats, retStats, flags);
+
+    virResetLastError();
+
+    virCheckNonNullArgGoto(doms, cleanup);
+    virCheckNonNullArgGoto(retStats, cleanup);
+
+    if (!*doms) {
+        virReportError(VIR_ERR_INVALID_ARG,
+                       _("doms array in %s must contain at least one domain"),
+                       __FUNCTION__);
+        goto cleanup;
+    }
+
+    conn = doms[0]->conn;
+    virCheckConnectReturn(conn, -1);
+
+    if (!conn->driver->connectGetAllDomainStats) {
+        virReportUnsupportedError();
+        goto cleanup;
+    }
+
+    while (*nextdom) {
+        virDomainPtr dom = *nextdom;
+
+        virCheckDomainGoto(dom, cleanup);
+
+        if (dom->conn != conn) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("domains in 'doms' array must belong to a "
+                             "single connection in %s"), __FUNCTION__);
+            goto cleanup;
+        }
+
+        ndoms++;
+        nextdom++;
+    }
+
+    ret = conn->driver->connectGetAllDomainStats(conn, doms, ndoms,
+                                                 stats, retStats, flags);
+
+ cleanup:
+    if (ret < 0)
+        virDispatchError(conn);
+    return ret;
+}
+
+
+/**
+ * virDomainStatsRecordListFree:
+ * @stats: NULL terminated array of virDomainStatsRecords to free
+ *
+ * Convenience function to free a list of domain stats returned by
+ * virDomainListGetStats and virConnectGetAllDomainStats.
+ */
+void
+virDomainStatsRecordListFree(virDomainStatsRecordPtr *stats)
+{
+    virDomainStatsRecordPtr *next;
+
+    if (!stats)
+        return;
+
+    for (next = stats; *next; next++) {
+        virTypedParamsFree((*next)->params, (*next)->nparams);
+        virDomainFree((*next)->dom);
+        VIR_FREE(*next);
+    }
+
+    VIR_FREE(stats);
+}
diff --git a/src/libvirt.c b/src/libvirt.c
index 6fa360b..ceee342 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -52,7 +52,6 @@
 #include "viruuid.h"
 #include "viralloc.h"
 #include "configmake.h"
-#include "intprops.h"
 #include "virconf.h"
 #if WITH_GNUTLS
 # if WITH_GNUTLS_GCRYPT
@@ -1500,6 +1499,48 @@ virConnectSupportsFeature(virConnectPtr conn, int feature)
 }
 
 
+/* Helper function called to validate incoming client array on any
+ * interface that sets typed parameters in the hypervisor.  */
+int
+virTypedParameterValidateSet(virConnectPtr conn,
+                             virTypedParameterPtr params,
+                             int nparams)
+{
+    bool string_okay;
+    size_t i;
+
+    string_okay = VIR_DRV_SUPPORTS_FEATURE(conn->driver,
+                                           conn,
+                                           VIR_DRV_FEATURE_TYPED_PARAM_STRING);
+    for (i = 0; i < nparams; i++) {
+        if (strnlen(params[i].field, VIR_TYPED_PARAM_FIELD_LENGTH) ==
+            VIR_TYPED_PARAM_FIELD_LENGTH) {
+            virReportInvalidArg(params,
+                                _("string parameter name '%.*s' too long"),
+                                VIR_TYPED_PARAM_FIELD_LENGTH,
+                                params[i].field);
+            return -1;
+        }
+        if (params[i].type == VIR_TYPED_PARAM_STRING) {
+            if (string_okay) {
+                if (!params[i].value.s) {
+                    virReportInvalidArg(params,
+                                        _("NULL string parameter '%s'"),
+                                        params[i].field);
+                    return -1;
+                }
+            } else {
+                virReportInvalidArg(params,
+                                    _("string parameter '%s' unsupported"),
+                                    params[i].field);
+                return -1;
+            }
+        }
+    }
+    return 0;
+}
+
+
 /**
  * virConnectGetType:
  * @conn: pointer to the hypervisor connection
@@ -1755,41 +1796,34 @@ virConnectGetMaxVcpus(virConnectPtr conn,
 
 
 /**
- * virConnectListDomains:
+ * virNodeGetInfo:
  * @conn: pointer to the hypervisor connection
- * @ids: array to collect the list of IDs of active domains
- * @maxids: size of @ids
- *
- * Collect the list of active domains, and store their IDs in array @ids
+ * @info: pointer to a virNodeInfo structure allocated by the user
  *
- * For inactive domains, see virConnectListDefinedDomains().  For more
- * control over the results, see virConnectListAllDomains().
+ * Extract hardware information about the node.
  *
- * Returns the number of domains found or -1 in case of error.  Note that
- * this command is inherently racy; a domain can be started between a
- * call to virConnectNumOfDomains() and this call; you are only guaranteed
- * that all currently active domains were listed if the return is less
- * than @maxids.
+ * Returns 0 in case of success and -1 in case of failure.
  */
 int
-virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
+virNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
 {
-    VIR_DEBUG("conn=%p, ids=%p, maxids=%d", conn, ids, maxids);
+    VIR_DEBUG("conn=%p, info=%p", conn, info);
 
     virResetLastError();
 
     virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(ids, error);
-    virCheckNonNegativeArgGoto(maxids, error);
+    virCheckNonNullArgGoto(info, error);
 
-    if (conn->driver->connectListDomains) {
-        int ret = conn->driver->connectListDomains(conn, ids, maxids);
+    if (conn->driver->nodeGetInfo) {
+        int ret;
+        ret = conn->driver->nodeGetInfo(conn, info);
         if (ret < 0)
             goto error;
         return ret;
     }
 
     virReportUnsupportedError();
+
  error:
     virDispatchError(conn);
     return -1;
@@ -1797,238 +1831,294 @@ virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
 
 
 /**
- * virConnectNumOfDomains:
+ * virConnectGetCapabilities:
  * @conn: pointer to the hypervisor connection
  *
- * Provides the number of active domains.
+ * Provides capabilities of the hypervisor / driver.
  *
- * Returns the number of domain found or -1 in case of error
+ * Returns NULL in case of error, or an XML string
+ * defining the capabilities.
+ * The client must free the returned string after use.
  */
-int
-virConnectNumOfDomains(virConnectPtr conn)
+char *
+virConnectGetCapabilities(virConnectPtr conn)
 {
     VIR_DEBUG("conn=%p", conn);
 
     virResetLastError();
 
-    virCheckConnectReturn(conn, -1);
+    virCheckConnectReturn(conn, NULL);
 
-    if (conn->driver->connectNumOfDomains) {
-        int ret = conn->driver->connectNumOfDomains(conn);
-        if (ret < 0)
+    if (conn->driver->connectGetCapabilities) {
+        char *ret;
+        ret = conn->driver->connectGetCapabilities(conn);
+        if (!ret)
             goto error;
+        VIR_DEBUG("conn=%p ret=%s", conn, ret);
         return ret;
     }
 
     virReportUnsupportedError();
+
  error:
     virDispatchError(conn);
-    return -1;
+    return NULL;
 }
 
 
 /**
- * virDomainGetConnect:
- * @dom: pointer to a domain
+ * virNodeGetCPUStats:
+ * @conn: pointer to the hypervisor connection.
+ * @cpuNum: number of node cpu. (VIR_NODE_CPU_STATS_ALL_CPUS means total cpu
+ *          statistics)
+ * @params: pointer to node cpu time parameter objects
+ * @nparams: number of node cpu time parameter (this value should be same or
+ *          less than the number of parameters supported)
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * This function provides individual cpu statistics of the node.
+ * If you want to get total cpu statistics of the node, you must specify
+ * VIR_NODE_CPU_STATS_ALL_CPUS to @cpuNum.
+ * The @params array will be filled with the values equal to the number of
+ * parameters suggested by @nparams
+ *
+ * As the value of @nparams is dynamic, call the API setting @nparams to 0 and
+ * @params as NULL, the API returns the number of parameters supported by the
+ * HV by updating @nparams on SUCCESS. The caller should then allocate @params
+ * array, i.e. (sizeof(@virNodeCPUStats) * @nparams) bytes and call
+ * the API again.
+ *
+ * Here is a sample code snippet:
+ *
+ *   if (virNodeGetCPUStats(conn, cpuNum, NULL, &nparams, 0) == 0 &&
+ *       nparams != 0) {
+ *       if ((params = malloc(sizeof(virNodeCPUStats) * nparams)) == NULL)
+ *           goto error;
+ *       memset(params, 0, sizeof(virNodeCPUStats) * nparams);
+ *       if (virNodeGetCPUStats(conn, cpuNum, params, &nparams, 0))
+ *           goto error;
+ *   }
  *
- * Provides the connection pointer associated with a domain.  The
- * reference counter on the connection is not increased by this
- * call.
+ * This function doesn't require privileged access to the hypervisor.
+ * This function expects the caller to allocate the @params.
+ *
+ * CPU time Statistics:
  *
- * WARNING: When writing libvirt bindings in other languages, do
- * not use this function.  Instead, store the connection and
- * the domain object together.
+ * VIR_NODE_CPU_STATS_KERNEL:
+ *     The cumulative CPU time which spends by kernel,
+ *     when the node booting up.(nanoseconds)
+ * VIR_NODE_CPU_STATS_USER:
+ *     The cumulative CPU time which spends by user processes,
+ *     when the node booting up.(nanoseconds)
+ * VIR_NODE_CPU_STATS_IDLE:
+ *     The cumulative idle CPU time, when the node booting up.(nanoseconds)
+ * VIR_NODE_CPU_STATS_IOWAIT:
+ *     The cumulative I/O wait CPU time, when the node booting up.(nanoseconds)
+ * VIR_NODE_CPU_STATS_UTILIZATION:
+ *     The CPU utilization. The usage value is in percent and 100%
+ *     represents all CPUs on the server.
  *
- * Returns the virConnectPtr or NULL in case of failure.
+ * Returns -1 in case of error, 0 in case of success.
  */
-virConnectPtr
-virDomainGetConnect(virDomainPtr dom)
+int
+virNodeGetCPUStats(virConnectPtr conn,
+                   int cpuNum,
+                   virNodeCPUStatsPtr params,
+                   int *nparams, unsigned int flags)
 {
-    VIR_DOMAIN_DEBUG(dom);
+    VIR_DEBUG("conn=%p, cpuNum=%d, params=%p, nparams=%d, flags=%x",
+              conn, cpuNum, params, nparams ? *nparams : -1, flags);
 
     virResetLastError();
 
-    virCheckDomainReturn(dom, NULL);
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (cpuNum < 0 && cpuNum != VIR_NODE_CPU_STATS_ALL_CPUS) {
+        virReportInvalidArg(cpuNum,
+                            _("cpuNum in %s only accepts %d as a negative "
+                              "value"),
+                            __FUNCTION__, VIR_NODE_CPU_STATS_ALL_CPUS);
+        goto error;
+    }
+
+    if (conn->driver->nodeGetCPUStats) {
+        int ret;
+        ret = conn->driver->nodeGetCPUStats(conn, cpuNum, params, nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+    virReportUnsupportedError();
 
-    return dom->conn;
+ error:
+    virDispatchError(conn);
+    return -1;
 }
 
 
 /**
- * virDomainCreateXML:
- * @conn: pointer to the hypervisor connection
- * @xmlDesc: string containing an XML description of the domain
- * @flags: bitwise-OR of supported virDomainCreateFlags
+ * virNodeGetMemoryStats:
+ * @conn: pointer to the hypervisor connection.
+ * @cellNum: number of node cell. (VIR_NODE_MEMORY_STATS_ALL_CELLS means total
+ *           cell statistics)
+ * @params: pointer to node memory stats objects
+ * @nparams: number of node memory stats (this value should be same or
+ *          less than the number of stats supported)
+ * @flags: extra flags; not used yet, so callers should always pass 0
  *
- * Launch a new guest domain, based on an XML description similar
- * to the one returned by virDomainGetXMLDesc()
- * This function may require privileged access to the hypervisor.
- * The domain is not persistent, so its definition will disappear when it
- * is destroyed, or if the host is restarted (see virDomainDefineXML() to
- * define persistent domains).
+ * This function provides memory stats of the node.
+ * If you want to get total memory statistics of the node, you must specify
+ * VIR_NODE_MEMORY_STATS_ALL_CELLS to @cellNum.
+ * The @params array will be filled with the values equal to the number of
+ * stats suggested by @nparams
+ *
+ * As the value of @nparams is dynamic, call the API setting @nparams to 0 and
+ * @params as NULL, the API returns the number of parameters supported by the
+ * HV by updating @nparams on SUCCESS. The caller should then allocate @params
+ * array, i.e. (sizeof(@virNodeMemoryStats) * @nparams) bytes and call
+ * the API again.
+ *
+ * Here is the sample code snippet:
+ *
+ *   if (virNodeGetMemoryStats(conn, cellNum, NULL, &nparams, 0) == 0 &&
+ *       nparams != 0) {
+ *       if ((params = malloc(sizeof(virNodeMemoryStats) * nparams)) == NULL)
+ *           goto error;
+ *       memset(params, cellNum, 0, sizeof(virNodeMemoryStats) * nparams);
+ *       if (virNodeGetMemoryStats(conn, params, &nparams, 0))
+ *           goto error;
+ *   }
  *
- * If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain
- * will be started, but its CPUs will remain paused. The CPUs
- * can later be manually started using virDomainResume.
+ * This function doesn't require privileged access to the hypervisor.
+ * This function expects the caller to allocate the @params.
  *
- * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
- * domain will be automatically destroyed when the virConnectPtr
- * object is finally released. This will also happen if the
- * client application crashes / loses its connection to the
- * libvirtd daemon. Any domains marked for auto destroy will
- * block attempts at migration, save-to-file, or snapshots.
+ * Memory Stats:
  *
- * virDomainFree should be used to free the resources after the
- * domain object is no longer needed.
+ * VIR_NODE_MEMORY_STATS_TOTAL:
+ *     The total memory usage.(KB)
+ * VIR_NODE_MEMORY_STATS_FREE:
+ *     The free memory usage.(KB)
+ *     On linux, this usage includes buffers and cached.
+ * VIR_NODE_MEMORY_STATS_BUFFERS:
+ *     The buffers memory usage.(KB)
+ * VIR_NODE_MEMORY_STATS_CACHED:
+ *     The cached memory usage.(KB)
  *
- * Returns a new domain object or NULL in case of failure
+ * Returns -1 in case of error, 0 in case of success.
  */
-virDomainPtr
-virDomainCreateXML(virConnectPtr conn, const char *xmlDesc,
-                   unsigned int flags)
+int
+virNodeGetMemoryStats(virConnectPtr conn,
+                      int cellNum,
+                      virNodeMemoryStatsPtr params,
+                      int *nparams, unsigned int flags)
 {
-    VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, xmlDesc, flags);
+    VIR_DEBUG("conn=%p, cellNum=%d, params=%p, nparams=%d, flags=%x",
+              conn, cellNum, params, nparams ? *nparams : -1, flags);
 
     virResetLastError();
 
-    virCheckConnectReturn(conn, NULL);
-    virCheckNonNullArgGoto(xmlDesc, error);
-    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (cellNum < 0 && cellNum != VIR_NODE_MEMORY_STATS_ALL_CELLS) {
+        virReportInvalidArg(cpuNum,
+                            _("cellNum in %s only accepts %d as a negative "
+                              "value"),
+                            __FUNCTION__, VIR_NODE_MEMORY_STATS_ALL_CELLS);
+        goto error;
+    }
 
-    if (conn->driver->domainCreateXML) {
-        virDomainPtr ret;
-        ret = conn->driver->domainCreateXML(conn, xmlDesc, flags);
-        if (!ret)
+    if (conn->driver->nodeGetMemoryStats) {
+        int ret;
+        ret = conn->driver->nodeGetMemoryStats(conn, cellNum, params, nparams, flags);
+        if (ret < 0)
             goto error;
         return ret;
     }
-
     virReportUnsupportedError();
+
  error:
     virDispatchError(conn);
-    return NULL;
+    return -1;
 }
 
 
 /**
- * virDomainCreateXMLWithFiles:
+ * virNodeGetFreeMemory:
  * @conn: pointer to the hypervisor connection
- * @xmlDesc: string containing an XML description of the domain
- * @nfiles: number of file descriptors passed
- * @files: list of file descriptors passed
- * @flags: bitwise-OR of supported virDomainCreateFlags
  *
- * Launch a new guest domain, based on an XML description similar
- * to the one returned by virDomainGetXMLDesc()
- * This function may require privileged access to the hypervisor.
- * The domain is not persistent, so its definition will disappear when it
- * is destroyed, or if the host is restarted (see virDomainDefineXML() to
- * define persistent domains).
- *
- * @files provides an array of file descriptors which will be
- * made available to the 'init' process of the guest. The file
- * handles exposed to the guest will be renumbered to start
- * from 3 (ie immediately following stderr). This is only
- * supported for guests which use container based virtualization
- * technology.
- *
- * If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain
- * will be started, but its CPUs will remain paused. The CPUs
- * can later be manually started using virDomainResume.
- *
- * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
- * domain will be automatically destroyed when the virConnectPtr
- * object is finally released. This will also happen if the
- * client application crashes / loses its connection to the
- * libvirtd daemon. Any domains marked for auto destroy will
- * block attempts at migration, save-to-file, or snapshots.
- *
- * virDomainFree should be used to free the resources after the
- * domain object is no longer needed.
- *
- * Returns a new domain object or NULL in case of failure
+ * provides the free memory available on the Node
+ * Note: most libvirt APIs provide memory sizes in kibibytes, but in this
+ * function the returned value is in bytes. Divide by 1024 as necessary.
+ *
+ * Returns the available free memory in bytes or 0 in case of error
  */
-virDomainPtr
-virDomainCreateXMLWithFiles(virConnectPtr conn, const char *xmlDesc,
-                            unsigned int nfiles,
-                            int *files,
-                            unsigned int flags)
+unsigned long long
+virNodeGetFreeMemory(virConnectPtr conn)
 {
-    VIR_DEBUG("conn=%p, xmlDesc=%s, nfiles=%u, files=%p, flags=%x",
-              conn, xmlDesc, nfiles, files, flags);
+    VIR_DEBUG("conn=%p", conn);
 
     virResetLastError();
 
-    virCheckConnectReturn(conn, NULL);
-    virCheckNonNullArgGoto(xmlDesc, error);
-    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckConnectReturn(conn, 0);
 
-    if (conn->driver->domainCreateXMLWithFiles) {
-        virDomainPtr ret;
-        ret = conn->driver->domainCreateXMLWithFiles(conn, xmlDesc,
-                                                     nfiles, files,
-                                                     flags);
-        if (!ret)
+    if (conn->driver->nodeGetFreeMemory) {
+        unsigned long long ret;
+        ret = conn->driver->nodeGetFreeMemory(conn);
+        if (ret == 0)
             goto error;
         return ret;
     }
 
     virReportUnsupportedError();
+
  error:
     virDispatchError(conn);
-    return NULL;
+    return 0;
 }
 
 
 /**
- * virDomainCreateLinux:
+ * virNodeSuspendForDuration:
  * @conn: pointer to the hypervisor connection
- * @xmlDesc: string containing an XML description of the domain
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Deprecated after 0.4.6.
- * Renamed to virDomainCreateXML() providing identical functionality.
- * This existing name will left indefinitely for API compatibility.
- *
- * Returns a new domain object or NULL in case of failure
- */
-virDomainPtr
-virDomainCreateLinux(virConnectPtr conn, const char *xmlDesc,
-                     unsigned int flags)
-{
-    return virDomainCreateXML(conn, xmlDesc, flags);
-}
-
-
-/**
- * virDomainLookupByID:
- * @conn: pointer to the hypervisor connection
- * @id: the domain ID number
- *
- * Try to find a domain based on the hypervisor ID number
- * Note that this won't work for inactive domains which have an ID of -1,
- * in that case a lookup based on the Name or UUId need to be done instead.
+ * @target: the state to which the host must be suspended to,
+ *         such as: VIR_NODE_SUSPEND_TARGET_MEM (Suspend-to-RAM)
+ *                  VIR_NODE_SUSPEND_TARGET_DISK (Suspend-to-Disk)
+ *                  VIR_NODE_SUSPEND_TARGET_HYBRID (Hybrid-Suspend,
+ *                  which is a combination of the former modes).
+ * @duration: the time duration in seconds for which the host
+ *            has to be suspended
+ * @flags: extra flags; not used yet, so callers should always pass 0
  *
- * virDomainFree should be used to free the resources after the
- * domain object is no longer needed.
+ * Attempt to suspend the node (host machine) for the given duration of
+ * time in the specified state (Suspend-to-RAM, Suspend-to-Disk or
+ * Hybrid-Suspend). Schedule the node's Real-Time-Clock interrupt to
+ * resume the node after the duration is complete.
  *
- * Returns a new domain object or NULL in case of failure.  If the
- * domain cannot be found, then VIR_ERR_NO_DOMAIN error is raised.
+ * Returns 0 on success (i.e., the node will be suspended after a short
+ * delay), -1 on failure (the operation is not supported, or an attempted
+ * suspend is already underway).
  */
-virDomainPtr
-virDomainLookupByID(virConnectPtr conn, int id)
+int
+virNodeSuspendForDuration(virConnectPtr conn,
+                          unsigned int target,
+                          unsigned long long duration,
+                          unsigned int flags)
 {
-    VIR_DEBUG("conn=%p, id=%d", conn, id);
+    VIR_DEBUG("conn=%p, target=%d, duration=%lld, flags=%x",
+              conn, target, duration, flags);
 
     virResetLastError();
 
-    virCheckConnectReturn(conn, NULL);
-    virCheckNonNegativeArgGoto(id, error);
+    virCheckConnectReturn(conn, -1);
+    virCheckReadOnlyGoto(conn->flags, error);
 
-    if (conn->driver->domainLookupByID) {
-        virDomainPtr ret;
-        ret = conn->driver->domainLookupByID(conn, id);
-        if (!ret)
+    if (conn->driver->nodeSuspendForDuration) {
+        int ret;
+        ret = conn->driver->nodeSuspendForDuration(conn, target,
+                                                   duration, flags);
+        if (ret < 0)
             goto error;
         return ret;
     }
@@ -2037,37 +2127,58 @@ virDomainLookupByID(virConnectPtr conn, int id)
 
  error:
     virDispatchError(conn);
-    return NULL;
+    return -1;
 }
 
 
-/**
- * virDomainLookupByUUID:
+/*
+ * virNodeGetMemoryParameters:
  * @conn: pointer to the hypervisor connection
- * @uuid: the raw UUID for the domain
+ * @params: pointer to memory parameter object
+ *          (return value, allocated by the caller)
+ * @nparams: pointer to number of memory parameters; input and output
+ * @flags: extra flags; not used yet, so callers should always pass 0
  *
- * Try to lookup a domain on the given hypervisor based on its UUID.
+ * Get all node memory parameters (parameters unsupported by OS will be
+ * omitted).  On input, @nparams gives the size of the @params array;
+ * on output, @nparams gives how many slots were filled with parameter
+ * information, which might be less but will not exceed the input value.
  *
- * virDomainFree should be used to free the resources after the
- * domain object is no longer needed.
+ * As a special case, calling with @params as NULL and @nparams as 0 on
+ * input will cause @nparams on output to contain the number of parameters
+ * supported by the hypervisor. The caller should then allocate @params
+ * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
+ * again.  See virDomainGetMemoryParameters() for an equivalent usage
+ * example.
  *
- * Returns a new domain object or NULL in case of failure.  If the
- * domain cannot be found, then VIR_ERR_NO_DOMAIN error is raised.
+ * Returns 0 in case of success, and -1 in case of failure.
  */
-virDomainPtr
-virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+int
+virNodeGetMemoryParameters(virConnectPtr conn,
+                           virTypedParameterPtr params,
+                           int *nparams,
+                           unsigned int flags)
 {
-    VIR_UUID_DEBUG(conn, uuid);
+    VIR_DEBUG("conn=%p, params=%p, nparams=%p, flags=%x",
+              conn, params, nparams, flags);
 
     virResetLastError();
 
-    virCheckConnectReturn(conn, NULL);
-    virCheckNonNullArgGoto(uuid, error);
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(nparams, error);
+    virCheckNonNegativeArgGoto(*nparams, error);
+    if (*nparams != 0)
+        virCheckNonNullArgGoto(params, error);
 
-    if (conn->driver->domainLookupByUUID) {
-        virDomainPtr ret;
-        ret = conn->driver->domainLookupByUUID(conn, uuid);
-        if (!ret)
+    if (VIR_DRV_SUPPORTS_FEATURE(conn->driver, conn,
+                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+        flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+    if (conn->driver->nodeGetMemoryParameters) {
+        int ret;
+        ret = conn->driver->nodeGetMemoryParameters(conn, params,
+                                                    nparams, flags);
+        if (ret < 0)
             goto error;
         return ret;
     }
@@ -2076,129 +2187,139 @@ virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
 
  error:
     virDispatchError(conn);
-    return NULL;
+    return -1;
 }
 
 
-/**
- * virDomainLookupByUUIDString:
+/*
+ * virNodeSetMemoryParameters:
  * @conn: pointer to the hypervisor connection
- * @uuidstr: the string UUID for the domain
+ * @params: pointer to scheduler parameter objects
+ * @nparams: number of scheduler parameter objects
+ *          (this value can be the same or less than the returned
+ *           value nparams of virDomainGetSchedulerType)
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Change all or a subset of the node memory tunables. The function
+ * fails if not all of the tunables are supported.
  *
- * Try to lookup a domain on the given hypervisor based on its UUID.
+ * Note that it's not recommended to use this function while the
+ * outside tuning program is running (such as ksmtuned under Linux),
+ * as they could change the tunables in parallel, which could cause
+ * conflicts.
  *
- * virDomainFree should be used to free the resources after the
- * domain object is no longer needed.
+ * This function may require privileged access to the hypervisor.
  *
- * Returns a new domain object or NULL in case of failure.  If the
- * domain cannot be found, then VIR_ERR_NO_DOMAIN error is raised.
+ * Returns 0 in case of success, -1 in case of failure.
  */
-virDomainPtr
-virDomainLookupByUUIDString(virConnectPtr conn, const char *uuidstr)
+int
+virNodeSetMemoryParameters(virConnectPtr conn,
+                           virTypedParameterPtr params,
+                           int nparams,
+                           unsigned int flags)
 {
-    unsigned char uuid[VIR_UUID_BUFLEN];
-    VIR_DEBUG("conn=%p, uuidstr=%s", conn, NULLSTR(uuidstr));
+    VIR_DEBUG("conn=%p, params=%p, nparams=%d, flags=%x",
+              conn, params, nparams, flags);
+    VIR_TYPED_PARAMS_DEBUG(params, nparams);
 
     virResetLastError();
 
-    virCheckConnectReturn(conn, NULL);
-    virCheckNonNullArgGoto(uuidstr, error);
+    virCheckConnectReturn(conn, -1);
+    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckNonNullArgGoto(params, error);
+    virCheckNonNegativeArgGoto(nparams, error);
 
-    if (virUUIDParse(uuidstr, uuid) < 0) {
-        virReportInvalidArg(uuidstr,
-                            _("uuidstr in %s must be a valid UUID"),
-                            __FUNCTION__);
+    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
         goto error;
+
+    if (conn->driver->nodeSetMemoryParameters) {
+        int ret;
+        ret = conn->driver->nodeSetMemoryParameters(conn, params,
+                                                          nparams, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
     }
 
-    return virDomainLookupByUUID(conn, &uuid[0]);
+    virReportUnsupportedError();
 
  error:
     virDispatchError(conn);
-    return NULL;
+    return -1;
 }
 
 
 /**
- * virDomainLookupByName:
- * @conn: pointer to the hypervisor connection
- * @name: name for the domain
- *
- * Try to lookup a domain on the given hypervisor based on its name.
+ * virNodeGetSecurityModel:
+ * @conn: a connection object
+ * @secmodel: pointer to a virSecurityModel structure
  *
- * virDomainFree should be used to free the resources after the
- * domain object is no longer needed.
+ * Extract the security model of a hypervisor. The 'model' field
+ * in the @secmodel argument may be initialized to the empty
+ * string if the driver has not activated a security model.
  *
- * Returns a new domain object or NULL in case of failure.  If the
- * domain cannot be found, then VIR_ERR_NO_DOMAIN error is raised.
+ * Returns 0 in case of success, -1 in case of failure
  */
-virDomainPtr
-virDomainLookupByName(virConnectPtr conn, const char *name)
+int
+virNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel)
 {
-    VIR_DEBUG("conn=%p, name=%s", conn, name);
+    VIR_DEBUG("conn=%p secmodel=%p", conn, secmodel);
 
     virResetLastError();
 
-    virCheckConnectReturn(conn, NULL);
-    virCheckNonNullArgGoto(name, error);
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(secmodel, error);
 
-    if (conn->driver->domainLookupByName) {
-        virDomainPtr dom;
-        dom = conn->driver->domainLookupByName(conn, name);
-        if (!dom)
+    if (conn->driver->nodeGetSecurityModel) {
+        int ret;
+        ret = conn->driver->nodeGetSecurityModel(conn, secmodel);
+        if (ret < 0)
             goto error;
-        return dom;
+        return ret;
     }
 
     virReportUnsupportedError();
 
  error:
     virDispatchError(conn);
-    return NULL;
+    return -1;
 }
 
 
 /**
- * virDomainDestroy:
- * @domain: a domain object
- *
- * Destroy the domain object. The running instance is shutdown if not down
- * already and all resources used by it are given back to the hypervisor. This
- * does not free the associated virDomainPtr object.
- * This function may require privileged access.
- *
- * virDomainDestroy first requests that a guest terminate
- * (e.g. SIGTERM), then waits for it to comply. After a reasonable
- * timeout, if the guest still exists, virDomainDestroy will
- * forcefully terminate the guest (e.g. SIGKILL) if necessary (which
- * may produce undesirable results, for example unflushed disk cache
- * in the guest). To avoid this possibility, it's recommended to
- * instead call virDomainDestroyFlags, sending the
- * VIR_DOMAIN_DESTROY_GRACEFUL flag.
- *
- * If the domain is transient and has any snapshot metadata (see
- * virDomainSnapshotNum()), then that metadata will automatically
- * be deleted when the domain quits.
+ * virNodeGetCellsFreeMemory:
+ * @conn: pointer to the hypervisor connection
+ * @freeMems: pointer to the array of unsigned long long
+ * @startCell: index of first cell to return freeMems info on.
+ * @maxCells: Maximum number of cells for which freeMems information can
+ *            be returned.
  *
- * Returns 0 in case of success and -1 in case of failure.
+ * This call returns the amount of free memory in one or more NUMA cells.
+ * The @freeMems array must be allocated by the caller and will be filled
+ * with the amount of free memory in bytes for each cell requested,
+ * starting with startCell (in freeMems[0]), up to either
+ * (startCell + maxCells), or the number of additional cells in the node,
+ * whichever is smaller.
+ *
+ * Returns the number of entries filled in freeMems, or -1 in case of error.
  */
 int
-virDomainDestroy(virDomainPtr domain)
+virNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems,
+                          int startCell, int maxCells)
 {
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
+    VIR_DEBUG("conn=%p, freeMems=%p, startCell=%d, maxCells=%d",
+          conn, freeMems, startCell, maxCells);
 
     virResetLastError();
 
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(freeMems, error);
+    virCheckPositiveArgGoto(maxCells, error);
+    virCheckNonNegativeArgGoto(startCell, error);
 
-    if (conn->driver->domainDestroy) {
+    if (conn->driver->nodeGetCellsFreeMemory) {
         int ret;
-        ret = conn->driver->domainDestroy(domain);
+        ret = conn->driver->nodeGetCellsFreeMemory(conn, freeMems, startCell, maxCells);
         if (ret < 0)
             goto error;
         return ret;
@@ -2213,59 +2334,30 @@ virDomainDestroy(virDomainPtr domain)
 
 
 /**
- * virDomainDestroyFlags:
- * @domain: a domain object
- * @flags: bitwise-OR of virDomainDestroyFlagsValues
- *
- * Destroy the domain object. The running instance is shutdown if not down
- * already and all resources used by it are given back to the hypervisor.
- * This does not free the associated virDomainPtr object.
- * This function may require privileged access.
- *
- * Calling this function with no @flags set (equal to zero) is
- * equivalent to calling virDomainDestroy, and after a reasonable
- * timeout will forcefully terminate the guest (e.g. SIGKILL) if
- * necessary (which may produce undesirable results, for example
- * unflushed disk cache in the guest). Including
- * VIR_DOMAIN_DESTROY_GRACEFUL in the flags will prevent the forceful
- * termination of the guest, and virDomainDestroyFlags will instead
- * return an error if the guest doesn't terminate by the end of the
- * timeout; at that time, the management application can decide if
- * calling again without VIR_DOMAIN_DESTROY_GRACEFUL is appropriate.
- *
- * Another alternative which may produce cleaner results for the
- * guest's disks is to use virDomainShutdown() instead, but that
- * depends on guest support (some hypervisor/guest combinations may
- * ignore the shutdown request).
+ * virConnectIsEncrypted:
+ * @conn: pointer to the connection object
  *
+ * Determine if the connection to the hypervisor is encrypted
  *
- * Returns 0 in case of success and -1 in case of failure.
+ * Returns 1 if encrypted, 0 if not encrypted, -1 on error
  */
 int
-virDomainDestroyFlags(virDomainPtr domain,
-                      unsigned int flags)
+virConnectIsEncrypted(virConnectPtr conn)
 {
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
+    VIR_DEBUG("conn=%p", conn);
 
     virResetLastError();
 
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainDestroyFlags) {
+    virCheckConnectReturn(conn, -1);
+    if (conn->driver->connectIsEncrypted) {
         int ret;
-        ret = conn->driver->domainDestroyFlags(domain, flags);
+        ret = conn->driver->connectIsEncrypted(conn);
         if (ret < 0)
             goto error;
         return ret;
     }
 
     virReportUnsupportedError();
-
  error:
     virDispatchError(conn);
     return -1;
@@ -2273,238 +2365,120 @@ virDomainDestroyFlags(virDomainPtr domain,
 
 
 /**
- * virDomainFree:
- * @domain: a domain object
+ * virConnectIsSecure:
+ * @conn: pointer to the connection object
  *
- * Free the domain object. The running instance is kept alive.
- * The data structure is freed and should not be used thereafter.
+ * Determine if the connection to the hypervisor is secure
  *
- * Returns 0 in case of success and -1 in case of failure.
+ * A connection will be classed as secure if it is either
+ * encrypted, or running over a channel which is not exposed
+ * to eavesdropping (eg a UNIX domain socket, or pipe)
+ *
+ * Returns 1 if secure, 0 if not secure, -1 on error
  */
 int
-virDomainFree(virDomainPtr domain)
+virConnectIsSecure(virConnectPtr conn)
 {
-    VIR_DOMAIN_DEBUG(domain);
+    VIR_DEBUG("conn=%p", conn);
 
     virResetLastError();
 
-    virCheckDomainReturn(domain, -1);
+    virCheckConnectReturn(conn, -1);
+    if (conn->driver->connectIsSecure) {
+        int ret;
+        ret = conn->driver->connectIsSecure(conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
 
-    virObjectUnref(domain);
-    return 0;
+    virReportUnsupportedError();
+ error:
+    virDispatchError(conn);
+    return -1;
 }
 
 
 /**
- * virDomainRef:
- * @domain: the domain to hold a reference on
- *
- * Increment the reference count on the domain. For each
- * additional call to this method, there shall be a corresponding
- * call to virDomainFree to release the reference count, once
- * the caller no longer needs the reference to this object.
+ * virConnectCompareCPU:
+ * @conn: virConnect connection
+ * @xmlDesc: XML describing the CPU to compare with host CPU
+ * @flags: bitwise-OR of virConnectCompareCPUFlags
  *
- * This method is typically useful for applications where multiple
- * threads are using a connection, and it is required that the
- * connection remain open until all threads have finished using
- * it. ie, each new thread using a domain would increment
- * the reference count.
+ * Compares the given CPU description with the host CPU
  *
- * Returns 0 in case of success and -1 in case of failure.
+ * Returns comparison result according to enum virCPUCompareResult. If
+ * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlDesc CPU is
+ * incompatible with host CPU, this function will return VIR_CPU_COMPARE_ERROR
+ * (instead of VIR_CPU_COMPARE_INCOMPATIBLE) and the error will use the
+ * VIR_ERR_CPU_INCOMPATIBLE code with a message providing more details about
+ * the incompatibility.
  */
 int
-virDomainRef(virDomainPtr domain)
+virConnectCompareCPU(virConnectPtr conn,
+                     const char *xmlDesc,
+                     unsigned int flags)
 {
-    VIR_DOMAIN_DEBUG(domain, "refs=%d", domain ? domain->object.u.s.refs : 0);
+    VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, xmlDesc, flags);
 
     virResetLastError();
 
-    virCheckDomainReturn(domain, -1);
+    virCheckConnectReturn(conn, VIR_CPU_COMPARE_ERROR);
+    virCheckNonNullArgGoto(xmlDesc, error);
+
+    if (conn->driver->connectCompareCPU) {
+        int ret;
 
-    virObjectRef(domain);
-    return 0;
+        ret = conn->driver->connectCompareCPU(conn, xmlDesc, flags);
+        if (ret == VIR_CPU_COMPARE_ERROR)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(conn);
+    return VIR_CPU_COMPARE_ERROR;
 }
 
 
 /**
- * virDomainSuspend:
- * @domain: a domain object
+ * virConnectGetCPUModelNames:
  *
- * Suspends an active domain, the process is frozen without further access
- * to CPU resources and I/O but the memory used by the domain at the
- * hypervisor level will stay allocated. Use virDomainResume() to reactivate
- * the domain.
- * This function may require privileged access.
- * Moreover, suspend may not be supported if domain is in some
- * special state like VIR_DOMAIN_PMSUSPENDED.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainSuspend(virDomainPtr domain)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainSuspend) {
-        int ret;
-        ret = conn->driver->domainSuspend(domain);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainResume:
- * @domain: a domain object
+ * @conn: virConnect connection
+ * @arch: Architecture
+ * @models: Pointer to a variable to store the NULL-terminated array of the
+ *          CPU models supported for the specified architecture.  Each element
+ *          and the array itself must be freed by the caller with free.  Pass
+ *          NULL if only the list length is needed.
+ * @flags: extra flags; not used yet, so callers should always pass 0.
  *
- * Resume a suspended domain, the process is restarted from the state where
- * it was frozen by calling virDomainSuspend().
- * This function may require privileged access
- * Moreover, resume may not be supported if domain is in some
- * special state like VIR_DOMAIN_PMSUSPENDED.
+ * Get the list of supported CPU models for a specific architecture.
  *
- * Returns 0 in case of success and -1 in case of failure.
+ * Returns -1 on error, number of elements in @models on success.
  */
 int
-virDomainResume(virDomainPtr domain)
+virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char ***models,
+                           unsigned int flags)
 {
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
+    VIR_DEBUG("conn=%p, arch=%s, models=%p, flags=%x",
+              conn, arch, models, flags);
     virResetLastError();
 
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
+    if (models)
+        *models = NULL;
 
-    virCheckReadOnlyGoto(conn->flags, error);
+    virCheckConnectReturn(conn, -1);
+    virCheckNonNullArgGoto(arch, error);
 
-    if (conn->driver->domainResume) {
+    if (conn->driver->connectGetCPUModelNames) {
         int ret;
-        ret = conn->driver->domainResume(domain);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainPMSuspendForDuration:
- * @dom: a domain object
- * @target: a value from virNodeSuspendTarget
- * @duration: duration in seconds to suspend, or 0 for indefinite
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Attempt to have the guest enter the given @target power management
- * suspension level.  If @duration is non-zero, also schedule the guest to
- * resume normal operation after that many seconds, if nothing else has
- * resumed it earlier.  Some hypervisors require that @duration be 0, for
- * an indefinite suspension.
- *
- * Dependent on hypervisor used, this may require a
- * guest agent to be available, e.g. QEMU.
- *
- * Beware that at least for QEMU, the domain's process will be terminated
- * when VIR_NODE_SUSPEND_TARGET_DISK is used and a new process will be
- * launched when libvirt is asked to wake up the domain. As a result of
- * this, any runtime changes, such as device hotplug or memory settings,
- * are lost unless such changes were made with VIR_DOMAIN_AFFECT_CONFIG
- * flag.
- *
- * Returns: 0 on success,
- *          -1 on failure.
- */
-int
-virDomainPMSuspendForDuration(virDomainPtr dom,
-                              unsigned int target,
-                              unsigned long long duration,
-                              unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "target=%u duration=%llu flags=%x",
-                     target, duration, flags);
-
-    virResetLastError();
 
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainPMSuspendForDuration) {
-        int ret;
-        ret = conn->driver->domainPMSuspendForDuration(dom, target,
-                                                       duration, flags);
+        ret = conn->driver->connectGetCPUModelNames(conn, arch, models, flags);
         if (ret < 0)
             goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainPMWakeup:
- * @dom: a domain object
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Inject a wakeup into the guest that previously used
- * virDomainPMSuspendForDuration, rather than waiting for the
- * previously requested duration (if any) to elapse.
- *
- * Returns: 0 on success,
- *          -1 on failure.
- */
-int
-virDomainPMWakeup(virDomainPtr dom,
-                  unsigned int flags)
-{
-    virConnectPtr conn;
 
-    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainPMWakeup) {
-        int ret;
-        ret = conn->driver->domainPMWakeup(dom, flags);
-        if (ret < 0)
-            goto error;
         return ret;
     }
 
@@ -2517,10843 +2491,101 @@ virDomainPMWakeup(virDomainPtr dom,
 
 
 /**
- * virDomainSave:
- * @domain: a domain object
- * @to: path for the output file
+ * virConnectBaselineCPU:
  *
- * This method will suspend a domain and save its memory contents to
- * a file on disk. After the call, if successful, the domain is not
- * listed as running anymore (this ends the life of a transient domain).
- * Use virDomainRestore() to restore a domain after saving.
+ * @conn: virConnect connection
+ * @xmlCPUs: array of XML descriptions of host CPUs
+ * @ncpus: number of CPUs in xmlCPUs
+ * @flags: bitwise-OR of virConnectBaselineCPUFlags
  *
- * See virDomainSaveFlags() for more control.  Also, a save file can
- * be inspected or modified slightly with virDomainSaveImageGetXMLDesc()
- * and virDomainSaveImageDefineXML().
+ * Computes the most feature-rich CPU which is compatible with all given
+ * host CPUs.
  *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainSave(virDomainPtr domain, const char *to)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "to=%s", to);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(to, error);
-
-    if (conn->driver->domainSave) {
-        int ret;
-        char *absolute_to;
-
-        /* We must absolutize the file path as the save is done out of process */
-        if (virFileAbsPath(to, &absolute_to) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("could not build absolute output file path"));
-            goto error;
-        }
-
-        ret = conn->driver->domainSave(domain, absolute_to);
-
-        VIR_FREE(absolute_to);
-
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSaveFlags:
- * @domain: a domain object
- * @to: path for the output file
- * @dxml: (optional) XML config for adjusting guest xml used on restore
- * @flags: bitwise-OR of virDomainSaveRestoreFlags
- *
- * This method will suspend a domain and save its memory contents to
- * a file on disk. After the call, if successful, the domain is not
- * listed as running anymore (this ends the life of a transient domain).
- * Use virDomainRestore() to restore a domain after saving.
- *
- * If the hypervisor supports it, @dxml can be used to alter
- * host-specific portions of the domain XML that will be used when
- * restoring an image.  For example, it is possible to alter the
- * backing filename that is associated with a disk device, in order to
- * prepare for file renaming done as part of backing up the disk
- * device while the domain is stopped.
- *
- * If @flags includes VIR_DOMAIN_SAVE_BYPASS_CACHE, then libvirt will
- * attempt to bypass the file system cache while creating the file, or
- * fail if it cannot do so for the given system; this can allow less
- * pressure on file system cache, but also risks slowing saves to NFS.
- *
- * Normally, the saved state file will remember whether the domain was
- * running or paused, and restore defaults to the same state.
- * Specifying VIR_DOMAIN_SAVE_RUNNING or VIR_DOMAIN_SAVE_PAUSED in
- * @flags will override what state gets saved into the file.  These
- * two flags are mutually exclusive.
- *
- * A save file can be inspected or modified slightly with
- * virDomainSaveImageGetXMLDesc() and virDomainSaveImageDefineXML().
- *
- * Some hypervisors may prevent this operation if there is a current
- * block copy operation; in that case, use virDomainBlockJobAbort()
- * to stop the block copy first.
+ * If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt
+ * will explicitly list all CPU features that are part of the host CPU,
+ * without this flag features that are part of the CPU model will not be
+ * listed.
  *
- * Returns 0 in case of success and -1 in case of failure.
+ * Returns XML description of the computed CPU (caller frees) or NULL on error.
  */
-int
-virDomainSaveFlags(virDomainPtr domain, const char *to,
-                   const char *dxml, unsigned int flags)
+char *
+virConnectBaselineCPU(virConnectPtr conn,
+                      const char **xmlCPUs,
+                      unsigned int ncpus,
+                      unsigned int flags)
 {
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "to=%s, dxml=%s, flags=%x",
-                     to, NULLSTR(dxml), flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(to, error);
+    size_t i;
 
-    if ((flags & VIR_DOMAIN_SAVE_RUNNING) && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
-        virReportInvalidArg(flags, "%s",
-                            _("running and paused flags are mutually "
-                              "exclusive"));
-        goto error;
+    VIR_DEBUG("conn=%p, xmlCPUs=%p, ncpus=%u, flags=%x",
+              conn, xmlCPUs, ncpus, flags);
+    if (xmlCPUs) {
+        for (i = 0; i < ncpus; i++)
+            VIR_DEBUG("xmlCPUs[%zu]=%s", i, NULLSTR(xmlCPUs[i]));
     }
 
-    if (conn->driver->domainSaveFlags) {
-        int ret;
-        char *absolute_to;
-
-        /* We must absolutize the file path as the save is done out of process */
-        if (virFileAbsPath(to, &absolute_to) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("could not build absolute output file path"));
-            goto error;
-        }
+    virResetLastError();
 
-        ret = conn->driver->domainSaveFlags(domain, absolute_to, dxml, flags);
+    virCheckConnectReturn(conn, NULL);
+    virCheckNonNullArgGoto(xmlCPUs, error);
 
-        VIR_FREE(absolute_to);
+    if (conn->driver->connectBaselineCPU) {
+        char *cpu;
 
-        if (ret < 0)
+        cpu = conn->driver->connectBaselineCPU(conn, xmlCPUs, ncpus, flags);
+        if (!cpu)
             goto error;
-        return ret;
+        return cpu;
     }
 
     virReportUnsupportedError();
 
  error:
-    virDispatchError(domain->conn);
-    return -1;
+    virDispatchError(conn);
+    return NULL;
 }
 
 
 /**
- * virDomainRestore:
- * @conn: pointer to the hypervisor connection
- * @from: path to the input file
+ * virConnectSetKeepAlive:
+ * @conn: pointer to a hypervisor connection
+ * @interval: number of seconds of inactivity before a keepalive message is sent
+ * @count: number of messages that can be sent in a row
  *
- * This method will restore a domain saved to disk by virDomainSave().
+ * Start sending keepalive messages after @interval seconds of inactivity and
+ * consider the connection to be broken when no response is received after
+ * @count keepalive messages sent in a row.  In other words, sending count + 1
+ * keepalive message results in closing the connection.  When @interval is
+ * <= 0, no keepalive messages will be sent.  When @count is 0, the connection
+ * will be automatically closed after @interval seconds of inactivity without
+ * sending any keepalive messages.
  *
- * See virDomainRestoreFlags() for more control.
+ * Note: The client has to implement and run an event loop with
+ * virEventRegisterImpl() or virEventRegisterDefaultImpl() to be able to
+ * use keepalive messages.  Failure to do so may result in connections
+ * being closed unexpectedly.
  *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainRestore(virConnectPtr conn, const char *from)
-{
-    VIR_DEBUG("conn=%p, from=%s", conn, from);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(from, error);
-
-    if (conn->driver->domainRestore) {
-        int ret;
-        char *absolute_from;
-
-        /* We must absolutize the file path as the restore is done out of process */
-        if (virFileAbsPath(from, &absolute_from) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("could not build absolute input file path"));
-            goto error;
-        }
-
-        ret = conn->driver->domainRestore(conn, absolute_from);
-
-        VIR_FREE(absolute_from);
-
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainRestoreFlags:
- * @conn: pointer to the hypervisor connection
- * @from: path to the input file
- * @dxml: (optional) XML config for adjusting guest xml used on restore
- * @flags: bitwise-OR of virDomainSaveRestoreFlags
- *
- * This method will restore a domain saved to disk by virDomainSave().
- *
- * If the hypervisor supports it, @dxml can be used to alter
- * host-specific portions of the domain XML that will be used when
- * restoring an image.  For example, it is possible to alter the
- * backing filename that is associated with a disk device, in order to
- * prepare for file renaming done as part of backing up the disk
- * device while the domain is stopped.
- *
- * If @flags includes VIR_DOMAIN_SAVE_BYPASS_CACHE, then libvirt will
- * attempt to bypass the file system cache while restoring the file, or
- * fail if it cannot do so for the given system; this can allow less
- * pressure on file system cache, but also risks slowing restores from NFS.
- *
- * Normally, the saved state file will remember whether the domain was
- * running or paused, and restore defaults to the same state.
- * Specifying VIR_DOMAIN_SAVE_RUNNING or VIR_DOMAIN_SAVE_PAUSED in
- * @flags will override the default read from the file.  These two
- * flags are mutually exclusive.
+ * Note: This API function controls only keepalive messages sent by the client.
+ * If the server is configured to use keepalive you still need to run the event
+ * loop to respond to them, even if you disable keepalives by this function.
  *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainRestoreFlags(virConnectPtr conn, const char *from, const char *dxml,
-                      unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, from=%s, dxml=%s, flags=%x",
-              conn, from, NULLSTR(dxml), flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(from, error);
-
-    if ((flags & VIR_DOMAIN_SAVE_RUNNING) && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
-        virReportInvalidArg(flags, "%s",
-                            _("running and paused flags are mutually "
-                              "exclusive"));
-        goto error;
-    }
-
-    if (conn->driver->domainRestoreFlags) {
-        int ret;
-        char *absolute_from;
-
-        /* We must absolutize the file path as the restore is done out of process */
-        if (virFileAbsPath(from, &absolute_from) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("could not build absolute input file path"));
-            goto error;
-        }
-
-        ret = conn->driver->domainRestoreFlags(conn, absolute_from, dxml,
-                                               flags);
-
-        VIR_FREE(absolute_from);
-
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainSaveImageGetXMLDesc:
- * @conn: pointer to the hypervisor connection
- * @file: path to saved state file
- * @flags: bitwise-OR of subset of virDomainXMLFlags
- *
- * This method will extract the XML describing the domain at the time
- * a saved state file was created.  @file must be a file created
- * previously by virDomainSave() or virDomainSaveFlags().
- *
- * No security-sensitive data will be included unless @flags contains
- * VIR_DOMAIN_XML_SECURE; this flag is rejected on read-only
- * connections.  For this API, @flags should not contain either
- * VIR_DOMAIN_XML_INACTIVE or VIR_DOMAIN_XML_UPDATE_CPU.
- *
- * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of
- * error.  The caller must free() the returned value.
- */
-char *
-virDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *file,
-                             unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, file=%s, flags=%x",
-              conn, file, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, NULL);
-    virCheckNonNullArgGoto(file, error);
-
-    if ((conn->flags & VIR_CONNECT_RO) && (flags & VIR_DOMAIN_XML_SECURE)) {
-        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
-                       _("virDomainSaveImageGetXMLDesc with secure flag"));
-        goto error;
-    }
-
-    if (conn->driver->domainSaveImageGetXMLDesc) {
-        char *ret;
-        char *absolute_file;
-
-        /* We must absolutize the file path as the read is done out of process */
-        if (virFileAbsPath(file, &absolute_file) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("could not build absolute input file path"));
-            goto error;
-        }
-
-        ret = conn->driver->domainSaveImageGetXMLDesc(conn, absolute_file,
-                                                      flags);
-
-        VIR_FREE(absolute_file);
-
-        if (!ret)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return NULL;
-}
-
-
-/**
- * virDomainSaveImageDefineXML:
- * @conn: pointer to the hypervisor connection
- * @file: path to saved state file
- * @dxml: XML config for adjusting guest xml used on restore
- * @flags: bitwise-OR of virDomainSaveRestoreFlags
- *
- * This updates the definition of a domain stored in a saved state
- * file.  @file must be a file created previously by virDomainSave()
- * or virDomainSaveFlags().
- *
- * @dxml can be used to alter host-specific portions of the domain XML
- * that will be used when restoring an image.  For example, it is
- * possible to alter the backing filename that is associated with a
- * disk device, to match renaming done as part of backing up the disk
- * device while the domain is stopped.
- *
- * Normally, the saved state file will remember whether the domain was
- * running or paused, and restore defaults to the same state.
- * Specifying VIR_DOMAIN_SAVE_RUNNING or VIR_DOMAIN_SAVE_PAUSED in
- * @flags will override the default saved into the file; omitting both
- * leaves the file's default unchanged.  These two flags are mutually
- * exclusive.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainSaveImageDefineXML(virConnectPtr conn, const char *file,
-                            const char *dxml, unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, file=%s, dxml=%s, flags=%x",
-              conn, file, dxml, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(file, error);
-    virCheckNonNullArgGoto(dxml, error);
-
-    if ((flags & VIR_DOMAIN_SAVE_RUNNING) && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
-        virReportInvalidArg(flags, "%s",
-                            _("running and paused flags are mutually "
-                              "exclusive"));
-        goto error;
-    }
-
-    if (conn->driver->domainSaveImageDefineXML) {
-        int ret;
-        char *absolute_file;
-
-        /* We must absolutize the file path as the read is done out of process */
-        if (virFileAbsPath(file, &absolute_file) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("could not build absolute input file path"));
-            goto error;
-        }
-
-        ret = conn->driver->domainSaveImageDefineXML(conn, absolute_file,
-                                                     dxml, flags);
-
-        VIR_FREE(absolute_file);
-
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainCoreDump:
- * @domain: a domain object
- * @to: path for the core file
- * @flags: bitwise-OR of virDomainCoreDumpFlags
- *
- * This method will dump the core of a domain on a given file for analysis.
- * Note that for remote Xen Daemon the file path will be interpreted in
- * the remote host. Hypervisors may require  the user to manually ensure
- * proper permissions on the file named by @to.
- *
- * If @flags includes VIR_DUMP_CRASH, then leave the guest shut off with
- * a crashed state after the dump completes.  If @flags includes
- * VIR_DUMP_LIVE, then make the core dump while continuing to allow
- * the guest to run; otherwise, the guest is suspended during the dump.
- * VIR_DUMP_RESET flag forces reset of the guest after dump.
- * The above three flags are mutually exclusive.
- *
- * Additionally, if @flags includes VIR_DUMP_BYPASS_CACHE, then libvirt
- * will attempt to bypass the file system cache while creating the file,
- * or fail if it cannot do so for the given system; this can allow less
- * pressure on file system cache, but also risks slowing saves to NFS.
- *
- * For more control over the output format, see virDomainCoreDumpWithFormat().
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainCoreDump(virDomainPtr domain, const char *to, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "to=%s, flags=%x", to, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(to, error);
-
-    if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_LIVE)) {
-        virReportInvalidArg(flags, "%s",
-                            _("crash and live flags are mutually exclusive"));
-        goto error;
-    }
-
-    if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_RESET)) {
-        virReportInvalidArg(flags, "%s",
-                         _("crash and reset flags are mutually exclusive"));
-        goto error;
-    }
-
-    if ((flags & VIR_DUMP_LIVE) && (flags & VIR_DUMP_RESET)) {
-        virReportInvalidArg(flags, "%s",
-                            _("live and reset flags are mutually exclusive"));
-        goto error;
-    }
-
-    if (conn->driver->domainCoreDump) {
-        int ret;
-        char *absolute_to;
-
-        /* We must absolutize the file path as the save is done out of process */
-        if (virFileAbsPath(to, &absolute_to) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("could not build absolute core file path"));
-            goto error;
-        }
-
-        ret = conn->driver->domainCoreDump(domain, absolute_to, flags);
-
-        VIR_FREE(absolute_to);
-
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-/**
- * virDomainCoreDumpWithFormat:
- * @domain: a domain object
- * @to: path for the core file
- * @dumpformat: format of domain memory's dump
- * @flags: bitwise-OR of virDomainCoreDumpFlags
- *
- * This method will dump the core of a domain on a given file for analysis.
- * Note that for remote Xen Daemon the file path will be interpreted in
- * the remote host. Hypervisors may require  the user to manually ensure
- * proper permissions on the file named by @to.
- *
- * @dumpformat controls which format the dump will have; use of
- * VIR_DOMAIN_CORE_DUMP_FORMAT_RAW mirrors what virDomainCoreDump() will
- * perform.  Not all hypervisors are able to support all formats.
- *
- * If @flags includes VIR_DUMP_CRASH, then leave the guest shut off with
- * a crashed state after the dump completes.  If @flags includes
- * VIR_DUMP_LIVE, then make the core dump while continuing to allow
- * the guest to run; otherwise, the guest is suspended during the dump.
- * VIR_DUMP_RESET flag forces reset of the guest after dump.
- * The above three flags are mutually exclusive.
- *
- * Additionally, if @flags includes VIR_DUMP_BYPASS_CACHE, then libvirt
- * will attempt to bypass the file system cache while creating the file,
- * or fail if it cannot do so for the given system; this can allow less
- * pressure on file system cache, but also risks slowing saves to NFS.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainCoreDumpWithFormat(virDomainPtr domain, const char *to,
-                            unsigned int dumpformat, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "to=%s, dumpformat=%u, flags=%x",
-                     to, dumpformat, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(to, error);
-
-    if (dumpformat >= VIR_DOMAIN_CORE_DUMP_FORMAT_LAST) {
-        virReportInvalidArg(flags, _("dumpformat '%d' is not supported"),
-                            dumpformat);
-        goto error;
-    }
-
-    if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_LIVE)) {
-        virReportInvalidArg(flags, "%s",
-                            _("crash and live flags are mutually exclusive"));
-        goto error;
-    }
-
-    if ((flags & VIR_DUMP_CRASH) && (flags & VIR_DUMP_RESET)) {
-        virReportInvalidArg(flags, "%s",
-                            _("crash and reset flags are mutually exclusive"));
-        goto error;
-    }
-
-    if ((flags & VIR_DUMP_LIVE) && (flags & VIR_DUMP_RESET)) {
-        virReportInvalidArg(flags, "%s",
-                            _("live and reset flags are mutually exclusive"));
-        goto error;
-    }
-
-    if (conn->driver->domainCoreDumpWithFormat) {
-        int ret;
-        char *absolute_to;
-
-        /* We must absolutize the file path as the save is done out of process */
-        if (virFileAbsPath(to, &absolute_to) < 0) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("could not build absolute core file path"));
-            goto error;
-        }
-
-        ret = conn->driver->domainCoreDumpWithFormat(domain, absolute_to,
-                                                     dumpformat, flags);
-
-        VIR_FREE(absolute_to);
-
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainScreenshot:
- * @domain: a domain object
- * @stream: stream to use as output
- * @screen: monitor ID to take screenshot from
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Take a screenshot of current domain console as a stream. The image format
- * is hypervisor specific. Moreover, some hypervisors supports multiple
- * displays per domain. These can be distinguished by @screen argument.
- *
- * This call sets up a stream; subsequent use of stream API is necessary
- * to transfer actual data, determine how much data is successfully
- * transferred, and detect any errors.
- *
- * The screen ID is the sequential number of screen. In case of multiple
- * graphics cards, heads are enumerated before devices, e.g. having
- * two graphics cards, both with four heads, screen ID 5 addresses
- * the second head on the second card.
- *
- * Returns a string representing the mime-type of the image format, or
- * NULL upon error. The caller must free() the returned value.
- */
-char *
-virDomainScreenshot(virDomainPtr domain,
-                    virStreamPtr stream,
-                    unsigned int screen,
-                    unsigned int flags)
-{
-    VIR_DOMAIN_DEBUG(domain, "stream=%p, flags=%x", stream, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-    virCheckStreamGoto(stream, error);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-
-    if (domain->conn != stream->conn) {
-        virReportInvalidArg(stream,
-                            _("stream in %s must match connection of domain '%s'"),
-                            __FUNCTION__, domain->name);
-        goto error;
-    }
-
-    if (domain->conn->driver->domainScreenshot) {
-        char *ret;
-        ret = domain->conn->driver->domainScreenshot(domain, stream,
-                                                     screen, flags);
-
-        if (ret == NULL)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virDomainShutdown:
- * @domain: a domain object
- *
- * Shutdown a domain, the domain object is still usable thereafter, but
- * the domain OS is being stopped. Note that the guest OS may ignore the
- * request. Additionally, the hypervisor may check and support the domain
- * 'on_poweroff' XML setting resulting in a domain that reboots instead of
- * shutting down. For guests that react to a shutdown request, the differences
- * from virDomainDestroy() are that the guests disk storage will be in a
- * stable state rather than having the (virtual) power cord pulled, and
- * this command returns as soon as the shutdown request is issued rather
- * than blocking until the guest is no longer running.
- *
- * If the domain is transient and has any snapshot metadata (see
- * virDomainSnapshotNum()), then that metadata will automatically
- * be deleted when the domain quits.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainShutdown(virDomainPtr domain)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainShutdown) {
-        int ret;
-        ret = conn->driver->domainShutdown(domain);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainShutdownFlags:
- * @domain: a domain object
- * @flags: bitwise-OR of virDomainShutdownFlagValues
- *
- * Shutdown a domain, the domain object is still usable thereafter but
- * the domain OS is being stopped. Note that the guest OS may ignore the
- * request. Additionally, the hypervisor may check and support the domain
- * 'on_poweroff' XML setting resulting in a domain that reboots instead of
- * shutting down. For guests that react to a shutdown request, the differences
- * from virDomainDestroy() are that the guest's disk storage will be in a
- * stable state rather than having the (virtual) power cord pulled, and
- * this command returns as soon as the shutdown request is issued rather
- * than blocking until the guest is no longer running.
- *
- * If the domain is transient and has any snapshot metadata (see
- * virDomainSnapshotNum()), then that metadata will automatically
- * be deleted when the domain quits.
- *
- * If @flags is set to zero, then the hypervisor will choose the
- * method of shutdown it considers best. To have greater control
- * pass one or more of the virDomainShutdownFlagValues. The order
- * in which the hypervisor tries each shutdown method is undefined,
- * and a hypervisor is not required to support all methods.
- *
- * To use guest agent (VIR_DOMAIN_SHUTDOWN_GUEST_AGENT) the domain XML
- * must have <channel> configured.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainShutdownFlags(virDomainPtr domain, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainShutdownFlags) {
-        int ret;
-        ret = conn->driver->domainShutdownFlags(domain, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainReboot:
- * @domain: a domain object
- * @flags: bitwise-OR of virDomainRebootFlagValues
- *
- * Reboot a domain, the domain object is still usable thereafter, but
- * the domain OS is being stopped for a restart.
- * Note that the guest OS may ignore the request.
- * Additionally, the hypervisor may check and support the domain
- * 'on_reboot' XML setting resulting in a domain that shuts down instead
- * of rebooting.
- *
- * If @flags is set to zero, then the hypervisor will choose the
- * method of shutdown it considers best. To have greater control
- * pass one or more of the virDomainRebootFlagValues. The order
- * in which the hypervisor tries each shutdown method is undefined,
- * and a hypervisor is not required to support all methods.
- *
- * To use guest agent (VIR_DOMAIN_REBOOT_GUEST_AGENT) the domain XML
- * must have <channel> configured.
- *
- * Due to implementation limitations in some drivers (the qemu driver,
- * for instance) it is not advised to migrate or save a guest that is
- * rebooting as a result of this API. Migrating such a guest can lead
- * to a plain shutdown on the destination.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainReboot(virDomainPtr domain, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainReboot) {
-        int ret;
-        ret = conn->driver->domainReboot(domain, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainReset:
- * @domain: a domain object
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Reset a domain immediately without any guest OS shutdown.
- * Reset emulates the power reset button on a machine, where all
- * hardware sees the RST line set and reinitializes internal state.
- *
- * Note that there is a risk of data loss caused by reset without any
- * guest OS shutdown.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainReset(virDomainPtr domain, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainReset) {
-        int ret;
-        ret = conn->driver->domainReset(domain, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetName:
- * @domain: a domain object
- *
- * Get the public name for that domain
- *
- * Returns a pointer to the name or NULL, the string need not be deallocated
- * its lifetime will be the same as the domain object.
- */
-const char *
-virDomainGetName(virDomainPtr domain)
-{
-    VIR_DEBUG("domain=%p", domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-
-    return domain->name;
-}
-
-
-/**
- * virDomainGetUUID:
- * @domain: a domain object
- * @uuid: pointer to a VIR_UUID_BUFLEN bytes array
- *
- * Get the UUID for a domain
- *
- * Returns -1 in case of error, 0 in case of success
- */
-int
-virDomainGetUUID(virDomainPtr domain, unsigned char *uuid)
-{
-    VIR_DOMAIN_DEBUG(domain, "uuid=%p", uuid);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(uuid, error);
-
-    memcpy(uuid, &domain->uuid[0], VIR_UUID_BUFLEN);
-
-    return 0;
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetUUIDString:
- * @domain: a domain object
- * @buf: pointer to a VIR_UUID_STRING_BUFLEN bytes array
- *
- * Get the UUID for a domain as string. For more information about
- * UUID see RFC4122.
- *
- * Returns -1 in case of error, 0 in case of success
- */
-int
-virDomainGetUUIDString(virDomainPtr domain, char *buf)
-{
-    VIR_DOMAIN_DEBUG(domain, "buf=%p", buf);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(buf, error);
-
-    virUUIDFormat(domain->uuid, buf);
-    return 0;
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetID:
- * @domain: a domain object
- *
- * Get the hypervisor ID number for the domain
- *
- * Returns the domain ID number or (unsigned int) -1 in case of error
- */
-unsigned int
-virDomainGetID(virDomainPtr domain)
-{
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, (unsigned int)-1);
-
-    return domain->id;
-}
-
-
-/**
- * virDomainGetOSType:
- * @domain: a domain object
- *
- * Get the type of domain operation system.
- *
- * Returns the new string or NULL in case of error, the string must be
- *         freed by the caller.
- */
-char *
-virDomainGetOSType(virDomainPtr domain)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-    conn = domain->conn;
-
-    if (conn->driver->domainGetOSType) {
-        char *ret;
-        ret = conn->driver->domainGetOSType(domain);
-        if (!ret)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virDomainGetMaxMemory:
- * @domain: a domain object or NULL
- *
- * Retrieve the maximum amount of physical memory allocated to a
- * domain. If domain is NULL, then this get the amount of memory reserved
- * to Domain0 i.e. the domain where the application runs.
- *
- * Returns the memory size in kibibytes (blocks of 1024 bytes), or 0 in
- * case of error.
- */
-unsigned long
-virDomainGetMaxMemory(virDomainPtr domain)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, 0);
-    conn = domain->conn;
-
-    if (conn->driver->domainGetMaxMemory) {
-        unsigned long long ret;
-        ret = conn->driver->domainGetMaxMemory(domain);
-        if (ret == 0)
-            goto error;
-        if ((unsigned long) ret != ret) {
-            virReportError(VIR_ERR_OVERFLOW, _("result too large: %llu"),
-                           ret);
-            goto error;
-        }
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return 0;
-}
-
-
-/**
- * virDomainSetMaxMemory:
- * @domain: a domain object or NULL
- * @memory: the memory size in kibibytes (blocks of 1024 bytes)
- *
- * Dynamically change the maximum amount of physical memory allocated to a
- * domain. If domain is NULL, then this change the amount of memory reserved
- * to Domain0 i.e. the domain where the application runs.
- * This function may require privileged access to the hypervisor.
- *
- * This command is hypervisor-specific for whether active, persistent,
- * or both configurations are changed; for more control, use
- * virDomainSetMemoryFlags().
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "memory=%lu", memory);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonZeroArgGoto(memory, error);
-
-    if (conn->driver->domainSetMaxMemory) {
-        int ret;
-        ret = conn->driver->domainSetMaxMemory(domain, memory);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetMemory:
- * @domain: a domain object or NULL
- * @memory: the memory size in kibibytes (blocks of 1024 bytes)
- *
- * Dynamically change the target amount of physical memory allocated to a
- * domain. If domain is NULL, then this change the amount of memory reserved
- * to Domain0 i.e. the domain where the application runs.
- * This function may require privileged access to the hypervisor.
- *
- * This command only changes the runtime configuration of the domain,
- * so can only be called on an active domain.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainSetMemory(virDomainPtr domain, unsigned long memory)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "memory=%lu", memory);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonZeroArgGoto(memory, error);
-
-    if (conn->driver->domainSetMemory) {
-        int ret;
-        ret = conn->driver->domainSetMemory(domain, memory);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetMemoryFlags:
- * @domain: a domain object or NULL
- * @memory: the memory size in kibibytes (blocks of 1024 bytes)
- * @flags: bitwise-OR of virDomainMemoryModFlags
- *
- * Dynamically change the target amount of physical memory allocated to a
- * domain. If domain is NULL, then this change the amount of memory reserved
- * to Domain0 i.e. the domain where the application runs.
- * This function may require privileged access to the hypervisor.
- *
- * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG.
- * Both flags may be set. If VIR_DOMAIN_AFFECT_LIVE is set, the change affects
- * a running domain and will fail if domain is not active.
- * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state,
- * and will fail for transient domains. If neither flag is specified
- * (that is, @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain
- * modifies persistent setup, while an active domain is hypervisor-dependent
- * on whether just live or both live and persistent state is changed.
- * If VIR_DOMAIN_MEM_MAXIMUM is set, the change affects domain's maximum memory
- * size rather than current memory size.
- * Not all hypervisors can support all flag combinations.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainSetMemoryFlags(virDomainPtr domain, unsigned long memory,
-                        unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "memory=%lu, flags=%x", memory, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonZeroArgGoto(memory, error);
-
-    if (conn->driver->domainSetMemoryFlags) {
-        int ret;
-        ret = conn->driver->domainSetMemoryFlags(domain, memory, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetMemoryStatsPeriod:
- * @domain: a domain object or NULL
- * @period: the period in seconds for stats collection
- * @flags: bitwise-OR of virDomainMemoryModFlags
- *
- * Dynamically change the domain memory balloon driver statistics collection
- * period. Use 0 to disable and a positive value to enable.
- *
- * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG.
- * Both flags may be set. If VIR_DOMAIN_AFFECT_LIVE is set, the change affects
- * a running domain and will fail if domain is not active.
- * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state,
- * and will fail for transient domains. If neither flag is specified
- * (that is, @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain
- * modifies persistent setup, while an active domain is hypervisor-dependent
- * on whether just live or both live and persistent state is changed.
- *
- * Not all hypervisors can support all flag combinations.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainSetMemoryStatsPeriod(virDomainPtr domain, int period,
-                              unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "peroid=%d, flags=%x", period, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    /* This must be positive to set the balloon collection period */
-    virCheckNonNegativeArgGoto(period, error);
-
-    if (conn->driver->domainSetMemoryStatsPeriod) {
-        int ret;
-        ret = conn->driver->domainSetMemoryStatsPeriod(domain, period, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/* Helper function called to validate incoming client array on any
- * interface that sets typed parameters in the hypervisor.  */
-static int
-virTypedParameterValidateSet(virConnectPtr conn,
-                             virTypedParameterPtr params,
-                             int nparams)
-{
-    bool string_okay;
-    size_t i;
-
-    string_okay = VIR_DRV_SUPPORTS_FEATURE(conn->driver,
-                                           conn,
-                                           VIR_DRV_FEATURE_TYPED_PARAM_STRING);
-    for (i = 0; i < nparams; i++) {
-        if (strnlen(params[i].field, VIR_TYPED_PARAM_FIELD_LENGTH) ==
-            VIR_TYPED_PARAM_FIELD_LENGTH) {
-            virReportInvalidArg(params,
-                                _("string parameter name '%.*s' too long"),
-                                VIR_TYPED_PARAM_FIELD_LENGTH,
-                                params[i].field);
-            return -1;
-        }
-        if (params[i].type == VIR_TYPED_PARAM_STRING) {
-            if (string_okay) {
-                if (!params[i].value.s) {
-                    virReportInvalidArg(params,
-                                        _("NULL string parameter '%s'"),
-                                        params[i].field);
-                    return -1;
-                }
-            } else {
-                virReportInvalidArg(params,
-                                    _("string parameter '%s' unsupported"),
-                                    params[i].field);
-                return -1;
-            }
-        }
-    }
-    return 0;
-}
-
-
-/**
- * virDomainSetMemoryParameters:
- * @domain: pointer to domain object
- * @params: pointer to memory parameter objects
- * @nparams: number of memory parameter (this value can be the same or
- *          less than the number of parameters supported)
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Change all or a subset of the memory tunables.
- * This function may require privileged access to the hypervisor.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainSetMemoryParameters(virDomainPtr domain,
-                             virTypedParameterPtr params,
-                             int nparams, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
-                     params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(params, error);
-    virCheckPositiveArgGoto(nparams, error);
-
-    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
-        goto error;
-
-    if (conn->driver->domainSetMemoryParameters) {
-        int ret;
-        ret = conn->driver->domainSetMemoryParameters(domain, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetMemoryParameters:
- * @domain: pointer to domain object
- * @params: pointer to memory parameter object
- *          (return value, allocated by the caller)
- * @nparams: pointer to number of memory parameters; input and output
- * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
- *
- * Get all memory parameters.  On input, @nparams gives the size of the
- * @params array; on output, @nparams gives how many slots were filled
- * with parameter information, which might be less but will not exceed
- * the input value.
- *
- * As a special case, calling with @params as NULL and @nparams as 0 on
- * input will cause @nparams on output to contain the number of parameters
- * supported by the hypervisor. The caller should then allocate @params
- * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
- * again.
- *
- * Here is a sample code snippet:
- *
- *   if (virDomainGetMemoryParameters(dom, NULL, &nparams, 0) == 0 &&
- *       nparams != 0) {
- *       if ((params = malloc(sizeof(*params) * nparams)) == NULL)
- *           goto error;
- *       memset(params, 0, sizeof(*params) * nparams);
- *       if (virDomainGetMemoryParameters(dom, params, &nparams, 0))
- *           goto error;
- *   }
- *
- * This function may require privileged access to the hypervisor. This function
- * expects the caller to allocate the @params.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainGetMemoryParameters(virDomainPtr domain,
-                             virTypedParameterPtr params,
-                             int *nparams, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
-                     params, (nparams) ? *nparams : -1, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (*nparams != 0)
-        virCheckNonNullArgGoto(params, error);
-
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-
-    /* At most one of these two flags should be set.  */
-    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
-        virReportInvalidArg(flags,
-                            _("flags 'affect live' and 'affect config' in %s "
-                              "are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainGetMemoryParameters) {
-        int ret;
-        ret = conn->driver->domainGetMemoryParameters(domain, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetNumaParameters:
- * @domain: pointer to domain object
- * @params: pointer to numa parameter objects
- * @nparams: number of numa parameters (this value can be the same or
- *          less than the number of parameters supported)
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Change all or a subset of the numa tunables.
- * This function may require privileged access to the hypervisor.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainSetNumaParameters(virDomainPtr domain,
-                           virTypedParameterPtr params,
-                           int nparams, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
-                     params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-    virCheckNonNullArgGoto(params, error);
-    virCheckPositiveArgGoto(nparams, error);
-    if (virTypedParameterValidateSet(domain->conn, params, nparams) < 0)
-        goto error;
-
-    conn = domain->conn;
-
-    if (conn->driver->domainSetNumaParameters) {
-        int ret;
-        ret = conn->driver->domainSetNumaParameters(domain, params, nparams,
-                                                    flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetNumaParameters:
- * @domain: pointer to domain object
- * @params: pointer to numa parameter object
- *          (return value, allocated by the caller)
- * @nparams: pointer to number of numa parameters
- * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
- *
- * Get all numa parameters.  On input, @nparams gives the size of the
- * @params array; on output, @nparams gives how many slots were filled
- * with parameter information, which might be less but will not exceed
- * the input value.
- *
- * As a special case, calling with @params as NULL and @nparams as 0 on
- * input will cause @nparams on output to contain the number of parameters
- * supported by the hypervisor. The caller should then allocate @params
- * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
- * again.
- *
- * See virDomainGetMemoryParameters() for an equivalent usage example.
- *
- * This function may require privileged access to the hypervisor. This function
- * expects the caller to allocate the @params.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainGetNumaParameters(virDomainPtr domain,
-                           virTypedParameterPtr params,
-                           int *nparams, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
-                     params, (nparams) ? *nparams : -1, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (*nparams != 0)
-        virCheckNonNullArgGoto(params, error);
-
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetNumaParameters) {
-        int ret;
-        ret = conn->driver->domainGetNumaParameters(domain, params, nparams,
-                                                    flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetBlkioParameters:
- * @domain: pointer to domain object
- * @params: pointer to blkio parameter objects
- * @nparams: number of blkio parameters (this value can be the same or
- *          less than the number of parameters supported)
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Change all or a subset of the blkio tunables.
- * This function may require privileged access to the hypervisor.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainSetBlkioParameters(virDomainPtr domain,
-                            virTypedParameterPtr params,
-                            int nparams, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
-                     params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(params, error);
-    virCheckNonNegativeArgGoto(nparams, error);
-
-    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
-        goto error;
-
-    if (conn->driver->domainSetBlkioParameters) {
-        int ret;
-        ret = conn->driver->domainSetBlkioParameters(domain, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetBlkioParameters:
- * @domain: pointer to domain object
- * @params: pointer to blkio parameter object
- *          (return value, allocated by the caller)
- * @nparams: pointer to number of blkio parameters; input and output
- * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
- *
- * Get all blkio parameters.  On input, @nparams gives the size of the
- * @params array; on output, @nparams gives how many slots were filled
- * with parameter information, which might be less but will not exceed
- * the input value.
- *
- * As a special case, calling with @params as NULL and @nparams as 0 on
- * input will cause @nparams on output to contain the number of parameters
- * supported by the hypervisor. The caller should then allocate @params
- * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
- * again.
- *
- * See virDomainGetMemoryParameters() for an equivalent usage example.
- *
- * This function may require privileged access to the hypervisor. This function
- * expects the caller to allocate the @params.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainGetBlkioParameters(virDomainPtr domain,
-                            virTypedParameterPtr params,
-                            int *nparams, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
-                     params, (nparams) ? *nparams : -1, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (*nparams != 0)
-        virCheckNonNullArgGoto(params, error);
-
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-
-    /* At most one of these two flags should be set.  */
-    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
-        virReportInvalidArg(flags,
-                            _("flags 'affect live' and 'affect config' in %s "
-                              "are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainGetBlkioParameters) {
-        int ret;
-        ret = conn->driver->domainGetBlkioParameters(domain, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetInfo:
- * @domain: a domain object
- * @info: pointer to a virDomainInfo structure allocated by the user
- *
- * Extract information about a domain. Note that if the connection
- * used to get the domain is limited only a partial set of the information
- * can be extracted.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "info=%p", info);
-
-    virResetLastError();
-
-    if (info)
-        memset(info, 0, sizeof(*info));
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(info, error);
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetInfo) {
-        int ret;
-        ret = conn->driver->domainGetInfo(domain, info);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetState:
- * @domain: a domain object
- * @state: returned state of the domain (one of virDomainState)
- * @reason: returned reason which led to @state (one of virDomain*Reason
- * corresponding to the current state); it is allowed to be NULL
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Extract domain state. Each state can be accompanied with a reason (if known)
- * which led to the state.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainGetState(virDomainPtr domain,
-                  int *state,
-                  int *reason,
-                  unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "state=%p, reason=%p, flags=%x",
-                     state, reason, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(state, error);
-
-    conn = domain->conn;
-    if (conn->driver->domainGetState) {
-        int ret;
-        ret = conn->driver->domainGetState(domain, state, reason, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetControlInfo:
- * @domain: a domain object
- * @info: pointer to a virDomainControlInfo structure allocated by the user
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Extract details about current state of control interface to a domain.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainGetControlInfo(virDomainPtr domain,
-                        virDomainControlInfoPtr info,
-                        unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "info=%p, flags=%x", info, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(info, error);
-
-    conn = domain->conn;
-    if (conn->driver->domainGetControlInfo) {
-        int ret;
-        ret = conn->driver->domainGetControlInfo(domain, info, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetXMLDesc:
- * @domain: a domain object
- * @flags: bitwise-OR of virDomainXMLFlags
- *
- * Provide an XML description of the domain. The description may be reused
- * later to relaunch the domain with virDomainCreateXML().
- *
- * No security-sensitive data will be included unless @flags contains
- * VIR_DOMAIN_XML_SECURE; this flag is rejected on read-only
- * connections.  If @flags includes VIR_DOMAIN_XML_INACTIVE, then the
- * XML represents the configuration that will be used on the next boot
- * of a persistent domain; otherwise, the configuration represents the
- * currently running domain.  If @flags contains
- * VIR_DOMAIN_XML_UPDATE_CPU, then the portion of the domain XML
- * describing CPU capabilities is modified to match actual
- * capabilities of the host.
- *
- * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
- *         the caller must free() the returned value.
- */
-char *
-virDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-    conn = domain->conn;
-
-    if ((conn->flags & VIR_CONNECT_RO) && (flags & VIR_DOMAIN_XML_SECURE)) {
-        virReportError(VIR_ERR_OPERATION_DENIED, "%s",
-                       _("virDomainGetXMLDesc with secure flag"));
-        goto error;
-    }
-
-    if (conn->driver->domainGetXMLDesc) {
-        char *ret;
-        ret = conn->driver->domainGetXMLDesc(domain, flags);
-        if (!ret)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virConnectDomainXMLFromNative:
- * @conn: a connection object
- * @nativeFormat: configuration format importing from
- * @nativeConfig: the configuration data to import
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Reads native configuration data  describing a domain, and
- * generates libvirt domain XML. The format of the native
- * data is hypervisor dependant.
- *
- * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
- *         the caller must free() the returned value.
- */
-char *
-virConnectDomainXMLFromNative(virConnectPtr conn,
-                              const char *nativeFormat,
-                              const char *nativeConfig,
-                              unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, format=%s, config=%s, flags=%x",
-              conn, nativeFormat, nativeConfig, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, NULL);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    virCheckNonNullArgGoto(nativeFormat, error);
-    virCheckNonNullArgGoto(nativeConfig, error);
-
-    if (conn->driver->connectDomainXMLFromNative) {
-        char *ret;
-        ret = conn->driver->connectDomainXMLFromNative(conn,
-                                                       nativeFormat,
-                                                       nativeConfig,
-                                                       flags);
-        if (!ret)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return NULL;
-}
-
-
-/**
- * virConnectDomainXMLToNative:
- * @conn: a connection object
- * @nativeFormat: configuration format exporting to
- * @domainXml: the domain configuration to export
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Reads a domain XML configuration document, and generates
- * a native configuration file describing the domain.
- * The format of the native data is hypervisor dependant.
- *
- * Returns a 0 terminated UTF-8 encoded native config datafile, or NULL in case of error.
- *         the caller must free() the returned value.
- */
-char *
-virConnectDomainXMLToNative(virConnectPtr conn,
-                            const char *nativeFormat,
-                            const char *domainXml,
-                            unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, format=%s, xml=%s, flags=%x",
-              conn, nativeFormat, domainXml, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, NULL);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    virCheckNonNullArgGoto(nativeFormat, error);
-    virCheckNonNullArgGoto(domainXml, error);
-
-    if (conn->driver->connectDomainXMLToNative) {
-        char *ret;
-        ret = conn->driver->connectDomainXMLToNative(conn,
-                                                     nativeFormat,
-                                                     domainXml,
-                                                     flags);
-        if (!ret)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return NULL;
-}
-
-
-/*
- * Sequence v1:
- *
- *  Dst: Prepare
- *        - Get ready to accept incoming VM
- *        - Generate optional cookie to pass to src
- *
- *  Src: Perform
- *        - Start migration and wait for send completion
- *        - Kill off VM if successful, resume if failed
- *
- *  Dst: Finish
- *        - Wait for recv completion and check status
- *        - Kill off VM if unsuccessful
- *
- */
-static virDomainPtr
-virDomainMigrateVersion1(virDomainPtr domain,
-                         virConnectPtr dconn,
-                         unsigned long flags,
-                         const char *dname,
-                         const char *uri,
-                         unsigned long bandwidth)
-{
-    virDomainPtr ddomain = NULL;
-    char *uri_out = NULL;
-    char *cookie = NULL;
-    int cookielen = 0, ret;
-    virDomainInfo info;
-    unsigned int destflags;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
-                     dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
-
-    ret = virDomainGetInfo(domain, &info);
-    if (ret == 0 && info.state == VIR_DOMAIN_PAUSED)
-        flags |= VIR_MIGRATE_PAUSED;
-
-    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
-                          VIR_MIGRATE_AUTO_CONVERGE);
-
-    /* Prepare the migration.
-     *
-     * The destination host may return a cookie, or leave cookie as
-     * NULL.
-     *
-     * The destination host MUST set uri_out if uri_in is NULL.
-     *
-     * If uri_in is non-NULL, then the destination host may modify
-     * the URI by setting uri_out.  If it does not wish to modify
-     * the URI, it should leave uri_out as NULL.
-     */
-    if (dconn->driver->domainMigratePrepare
-        (dconn, &cookie, &cookielen, uri, &uri_out, destflags, dname,
-         bandwidth) == -1)
-        goto done;
-
-    if (uri == NULL && uri_out == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("domainMigratePrepare did not set uri"));
-        goto done;
-    }
-    if (uri_out)
-        uri = uri_out; /* Did domainMigratePrepare change URI? */
-
-    /* Perform the migration.  The driver isn't supposed to return
-     * until the migration is complete.
-     */
-    if (domain->conn->driver->domainMigratePerform
-        (domain, cookie, cookielen, uri, flags, dname, bandwidth) == -1)
-        goto done;
-
-    /* Get the destination domain and return it or error.
-     * 'domain' no longer actually exists at this point
-     * (or so we hope), but we still use the object in memory
-     * in order to get the name.
-     */
-    dname = dname ? dname : domain->name;
-    if (dconn->driver->domainMigrateFinish)
-        ddomain = dconn->driver->domainMigrateFinish
-            (dconn, dname, cookie, cookielen, uri, destflags);
-    else
-        ddomain = virDomainLookupByName(dconn, dname);
-
- done:
-    VIR_FREE(uri_out);
-    VIR_FREE(cookie);
-    return ddomain;
-}
-
-
-/*
- * Sequence v2:
- *
- *  Src: DumpXML
- *        - Generate XML to pass to dst
- *
- *  Dst: Prepare
- *        - Get ready to accept incoming VM
- *        - Generate optional cookie to pass to src
- *
- *  Src: Perform
- *        - Start migration and wait for send completion
- *        - Kill off VM if successful, resume if failed
- *
- *  Dst: Finish
- *        - Wait for recv completion and check status
- *        - Kill off VM if unsuccessful
- *
- */
-static virDomainPtr
-virDomainMigrateVersion2(virDomainPtr domain,
-                         virConnectPtr dconn,
-                         unsigned long flags,
-                         const char *dname,
-                         const char *uri,
-                         unsigned long bandwidth)
-{
-    virDomainPtr ddomain = NULL;
-    char *uri_out = NULL;
-    char *cookie = NULL;
-    char *dom_xml = NULL;
-    int cookielen = 0, ret;
-    virDomainInfo info;
-    virErrorPtr orig_err = NULL;
-    unsigned int getxml_flags = 0;
-    int cancelled;
-    unsigned long destflags;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
-                     dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
-
-    /* Prepare the migration.
-     *
-     * The destination host may return a cookie, or leave cookie as
-     * NULL.
-     *
-     * The destination host MUST set uri_out if uri_in is NULL.
-     *
-     * If uri_in is non-NULL, then the destination host may modify
-     * the URI by setting uri_out.  If it does not wish to modify
-     * the URI, it should leave uri_out as NULL.
-     */
-
-    /* In version 2 of the protocol, the prepare step is slightly
-     * different.  We fetch the domain XML of the source domain
-     * and pass it to Prepare2.
-     */
-    if (!domain->conn->driver->domainGetXMLDesc) {
-        virReportUnsupportedError();
-        return NULL;
-    }
-
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_XML_MIGRATABLE)) {
-        getxml_flags |= VIR_DOMAIN_XML_MIGRATABLE;
-    } else {
-        getxml_flags |= VIR_DOMAIN_XML_SECURE | VIR_DOMAIN_XML_UPDATE_CPU;
-    }
-
-    dom_xml = domain->conn->driver->domainGetXMLDesc(domain, getxml_flags);
-    if (!dom_xml)
-        return NULL;
-
-    ret = virDomainGetInfo(domain, &info);
-    if (ret == 0 && info.state == VIR_DOMAIN_PAUSED)
-        flags |= VIR_MIGRATE_PAUSED;
-
-    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
-                          VIR_MIGRATE_AUTO_CONVERGE);
-
-    VIR_DEBUG("Prepare2 %p flags=%lx", dconn, destflags);
-    ret = dconn->driver->domainMigratePrepare2
-        (dconn, &cookie, &cookielen, uri, &uri_out, destflags, dname,
-         bandwidth, dom_xml);
-    VIR_FREE(dom_xml);
-    if (ret == -1)
-        goto done;
-
-    if (uri == NULL && uri_out == NULL) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("domainMigratePrepare2 did not set uri"));
-        cancelled = 1;
-        /* Make sure Finish doesn't overwrite the error */
-        orig_err = virSaveLastError();
-        goto finish;
-    }
-    if (uri_out)
-        uri = uri_out; /* Did domainMigratePrepare2 change URI? */
-
-    /* Perform the migration.  The driver isn't supposed to return
-     * until the migration is complete.
-     */
-    VIR_DEBUG("Perform %p", domain->conn);
-    ret = domain->conn->driver->domainMigratePerform
-        (domain, cookie, cookielen, uri, flags, dname, bandwidth);
-
-    /* Perform failed. Make sure Finish doesn't overwrite the error */
-    if (ret < 0)
-        orig_err = virSaveLastError();
-
-    /* If Perform returns < 0, then we need to cancel the VM
-     * startup on the destination
-     */
-    cancelled = ret < 0 ? 1 : 0;
-
- finish:
-    /* In version 2 of the migration protocol, we pass the
-     * status code from the sender to the destination host,
-     * so it can do any cleanup if the migration failed.
-     */
-    dname = dname ? dname : domain->name;
-    VIR_DEBUG("Finish2 %p ret=%d", dconn, ret);
-    ddomain = dconn->driver->domainMigrateFinish2
-        (dconn, dname, cookie, cookielen, uri, destflags, cancelled);
-    if (cancelled && ddomain)
-        VIR_ERROR(_("finish step ignored that migration was cancelled"));
-
- done:
-    if (orig_err) {
-        virSetError(orig_err);
-        virFreeError(orig_err);
-    }
-    VIR_FREE(uri_out);
-    VIR_FREE(cookie);
-    return ddomain;
-}
-
-
-/*
- * Sequence v3:
- *
- *  Src: Begin
- *        - Generate XML to pass to dst
- *        - Generate optional cookie to pass to dst
- *
- *  Dst: Prepare
- *        - Get ready to accept incoming VM
- *        - Generate optional cookie to pass to src
- *
- *  Src: Perform
- *        - Start migration and wait for send completion
- *        - Generate optional cookie to pass to dst
- *
- *  Dst: Finish
- *        - Wait for recv completion and check status
- *        - Kill off VM if failed, resume if success
- *        - Generate optional cookie to pass to src
- *
- *  Src: Confirm
- *        - Kill off VM if success, resume if failed
- *
-  * If useParams is true, params and nparams contain migration parameters and
-  * we know it's safe to call the API which supports extensible parameters.
-  * Otherwise, we have to use xmlin, dname, uri, and bandwidth and pass them
-  * to the old-style APIs.
- */
-static virDomainPtr
-virDomainMigrateVersion3Full(virDomainPtr domain,
-                             virConnectPtr dconn,
-                             const char *xmlin,
-                             const char *dname,
-                             const char *uri,
-                             unsigned long long bandwidth,
-                             virTypedParameterPtr params,
-                             int nparams,
-                             bool useParams,
-                             unsigned int flags)
-{
-    virDomainPtr ddomain = NULL;
-    char *uri_out = NULL;
-    char *cookiein = NULL;
-    char *cookieout = NULL;
-    char *dom_xml = NULL;
-    int cookieinlen = 0;
-    int cookieoutlen = 0;
-    int ret;
-    virDomainInfo info;
-    virErrorPtr orig_err = NULL;
-    int cancelled = 1;
-    unsigned long protection = 0;
-    bool notify_source = true;
-    unsigned int destflags;
-    int state;
-    virTypedParameterPtr tmp;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "dconn=%p, xmlin=%s, dname=%s, uri=%s, bandwidth=%llu, "
-                     "params=%p, nparams=%d, useParams=%d, flags=%x",
-                     dconn, NULLSTR(xmlin), NULLSTR(dname), NULLSTR(uri),
-                     bandwidth, params, nparams, useParams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    if ((!useParams &&
-         (!domain->conn->driver->domainMigrateBegin3 ||
-          !domain->conn->driver->domainMigratePerform3 ||
-          !domain->conn->driver->domainMigrateConfirm3 ||
-          !dconn->driver->domainMigratePrepare3 ||
-          !dconn->driver->domainMigrateFinish3)) ||
-        (useParams &&
-         (!domain->conn->driver->domainMigrateBegin3Params ||
-          !domain->conn->driver->domainMigratePerform3Params ||
-          !domain->conn->driver->domainMigrateConfirm3Params ||
-          !dconn->driver->domainMigratePrepare3Params ||
-          !dconn->driver->domainMigrateFinish3Params))) {
-        virReportUnsupportedError();
-        return NULL;
-    }
-
-    if (virTypedParamsCopy(&tmp, params, nparams) < 0)
-        return NULL;
-    params = tmp;
-
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION))
-        protection = VIR_MIGRATE_CHANGE_PROTECTION;
-
-    VIR_DEBUG("Begin3 %p", domain->conn);
-    if (useParams) {
-        dom_xml = domain->conn->driver->domainMigrateBegin3Params
-            (domain, params, nparams, &cookieout, &cookieoutlen,
-             flags | protection);
-    } else {
-        dom_xml = domain->conn->driver->domainMigrateBegin3
-            (domain, xmlin, &cookieout, &cookieoutlen,
-             flags | protection, dname, bandwidth);
-    }
-    if (!dom_xml)
-        goto done;
-
-    if (useParams) {
-        /* If source is new enough to support extensible migration parameters,
-         * it's certainly new enough to support virDomainGetState. */
-        ret = virDomainGetState(domain, &state, NULL, 0);
-    } else {
-        ret = virDomainGetInfo(domain, &info);
-        state = info.state;
-    }
-    if (ret == 0 && state == VIR_DOMAIN_PAUSED)
-        flags |= VIR_MIGRATE_PAUSED;
-
-    destflags = flags & ~(VIR_MIGRATE_ABORT_ON_ERROR |
-                          VIR_MIGRATE_AUTO_CONVERGE);
-
-    VIR_DEBUG("Prepare3 %p flags=%x", dconn, destflags);
-    cookiein = cookieout;
-    cookieinlen = cookieoutlen;
-    cookieout = NULL;
-    cookieoutlen = 0;
-    if (useParams) {
-        if (virTypedParamsReplaceString(&params, &nparams,
-                                        VIR_MIGRATE_PARAM_DEST_XML,
-                                        dom_xml) < 0)
-            goto done;
-        ret = dconn->driver->domainMigratePrepare3Params
-            (dconn, params, nparams, cookiein, cookieinlen,
-             &cookieout, &cookieoutlen, &uri_out, destflags);
-    } else {
-        ret = dconn->driver->domainMigratePrepare3
-            (dconn, cookiein, cookieinlen, &cookieout, &cookieoutlen,
-             uri, &uri_out, destflags, dname, bandwidth, dom_xml);
-    }
-    if (ret == -1) {
-        if (protection) {
-            /* Begin already started a migration job so we need to cancel it by
-             * calling Confirm while making sure it doesn't overwrite the error
-             */
-            orig_err = virSaveLastError();
-            goto confirm;
-        } else {
-            goto done;
-        }
-    }
-
-    /* Did domainMigratePrepare3 change URI? */
-    if (uri_out) {
-        uri = uri_out;
-        if (useParams &&
-            virTypedParamsReplaceString(&params, &nparams,
-                                        VIR_MIGRATE_PARAM_URI,
-                                        uri_out) < 0) {
-            cancelled = 1;
-            orig_err = virSaveLastError();
-            goto finish;
-        }
-    } else if (!uri &&
-               virTypedParamsGetString(params, nparams,
-                                       VIR_MIGRATE_PARAM_URI, &uri) <= 0) {
-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                       _("domainMigratePrepare3 did not set uri"));
-        cancelled = 1;
-        orig_err = virSaveLastError();
-        goto finish;
-    }
-
-    if (flags & VIR_MIGRATE_OFFLINE) {
-        VIR_DEBUG("Offline migration, skipping Perform phase");
-        VIR_FREE(cookieout);
-        cookieoutlen = 0;
-        cancelled = 0;
-        goto finish;
-    }
-
-    /* Perform the migration.  The driver isn't supposed to return
-     * until the migration is complete. The src VM should remain
-     * running, but in paused state until the destination can
-     * confirm migration completion.
-     */
-    VIR_DEBUG("Perform3 %p uri=%s", domain->conn, uri);
-    VIR_FREE(cookiein);
-    cookiein = cookieout;
-    cookieinlen = cookieoutlen;
-    cookieout = NULL;
-    cookieoutlen = 0;
-    /* dconnuri not relevant in non-P2P modes, so left NULL here */
-    if (useParams) {
-        ret = domain->conn->driver->domainMigratePerform3Params
-            (domain, NULL, params, nparams, cookiein, cookieinlen,
-             &cookieout, &cookieoutlen, flags | protection);
-    } else {
-        ret = domain->conn->driver->domainMigratePerform3
-            (domain, NULL, cookiein, cookieinlen,
-             &cookieout, &cookieoutlen, NULL,
-             uri, flags | protection, dname, bandwidth);
-    }
-
-    /* Perform failed. Make sure Finish doesn't overwrite the error */
-    if (ret < 0) {
-        orig_err = virSaveLastError();
-        /* Perform failed so we don't need to call confirm to let source know
-         * about the failure.
-         */
-        notify_source = false;
-    }
-
-    /* If Perform returns < 0, then we need to cancel the VM
-     * startup on the destination
-     */
-    cancelled = ret < 0 ? 1 : 0;
-
- finish:
-    /*
-     * The status code from the source is passed to the destination.
-     * The dest can cleanup if the source indicated it failed to
-     * send all migration data. Returns NULL for ddomain if
-     * the dest was unable to complete migration.
-     */
-    VIR_DEBUG("Finish3 %p ret=%d", dconn, ret);
-    VIR_FREE(cookiein);
-    cookiein = cookieout;
-    cookieinlen = cookieoutlen;
-    cookieout = NULL;
-    cookieoutlen = 0;
-    if (useParams) {
-        if (virTypedParamsGetString(params, nparams,
-                                    VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 &&
-            virTypedParamsReplaceString(&params, &nparams,
-                                        VIR_MIGRATE_PARAM_DEST_NAME,
-                                        domain->name) < 0) {
-            ddomain = NULL;
-        } else {
-            ddomain = dconn->driver->domainMigrateFinish3Params
-                (dconn, params, nparams, cookiein, cookieinlen,
-                 &cookieout, &cookieoutlen, destflags, cancelled);
-        }
-    } else {
-        dname = dname ? dname : domain->name;
-        ddomain = dconn->driver->domainMigrateFinish3
-            (dconn, dname, cookiein, cookieinlen, &cookieout, &cookieoutlen,
-             NULL, uri, destflags, cancelled);
-    }
-    if (cancelled && ddomain)
-        VIR_ERROR(_("finish step ignored that migration was cancelled"));
-
-    /* If ddomain is NULL, then we were unable to start
-     * the guest on the target, and must restart on the
-     * source. There is a small chance that the ddomain
-     * is NULL due to an RPC failure, in which case
-     * ddomain could in fact be running on the dest.
-     * The lock manager plugins should take care of
-     * safety in this scenario.
-     */
-    cancelled = ddomain == NULL ? 1 : 0;
-
-    /* If finish3 set an error, and we don't have an earlier
-     * one we need to preserve it in case confirm3 overwrites
-     */
-    if (!orig_err)
-        orig_err = virSaveLastError();
-
- confirm:
-    /*
-     * If cancelled, then src VM will be restarted, else it will be killed.
-     * Don't do this if migration failed on source and thus it was already
-     * cancelled there.
-     */
-    if (notify_source) {
-        VIR_DEBUG("Confirm3 %p ret=%d domain=%p", domain->conn, ret, domain);
-        VIR_FREE(cookiein);
-        cookiein = cookieout;
-        cookieinlen = cookieoutlen;
-        cookieout = NULL;
-        cookieoutlen = 0;
-        if (useParams) {
-            ret = domain->conn->driver->domainMigrateConfirm3Params
-                (domain, params, nparams, cookiein, cookieinlen,
-                 flags | protection, cancelled);
-        } else {
-            ret = domain->conn->driver->domainMigrateConfirm3
-                (domain, cookiein, cookieinlen,
-                 flags | protection, cancelled);
-        }
-        /* If Confirm3 returns -1, there's nothing more we can
-         * do, but fortunately worst case is that there is a
-         * domain left in 'paused' state on source.
-         */
-        if (ret < 0) {
-            VIR_WARN("Guest %s probably left in 'paused' state on source",
-                     domain->name);
-        }
-    }
-
- done:
-    if (orig_err) {
-        virSetError(orig_err);
-        virFreeError(orig_err);
-    }
-    VIR_FREE(dom_xml);
-    VIR_FREE(uri_out);
-    VIR_FREE(cookiein);
-    VIR_FREE(cookieout);
-    virTypedParamsFree(params, nparams);
-    return ddomain;
-}
-
-
-static virDomainPtr
-virDomainMigrateVersion3(virDomainPtr domain,
-                         virConnectPtr dconn,
-                         const char *xmlin,
-                         unsigned long flags,
-                         const char *dname,
-                         const char *uri,
-                         unsigned long bandwidth)
-{
-    return virDomainMigrateVersion3Full(domain, dconn, xmlin, dname, uri,
-                                        bandwidth, NULL, 0, false, flags);
-}
-
-
-static virDomainPtr
-virDomainMigrateVersion3Params(virDomainPtr domain,
-                               virConnectPtr dconn,
-                               virTypedParameterPtr params,
-                               int nparams,
-                               unsigned int flags)
-{
-    return virDomainMigrateVersion3Full(domain, dconn, NULL, NULL, NULL, 0,
-                                        params, nparams, true, flags);
-}
-
-
-/*
- * In normal migration, the libvirt client co-ordinates communication
- * between the 2 libvirtd instances on source & dest hosts.
- *
- * In this peer-2-peer migration alternative, the libvirt client
- * only talks to the source libvirtd instance. The source libvirtd
- * then opens its own connection to the destination and co-ordinates
- * migration itself.
- *
- * If useParams is true, params and nparams contain migration parameters and
- * we know it's safe to call the API which supports extensible parameters.
- * Otherwise, we have to use xmlin, dname, uri, and bandwidth and pass them
- * to the old-style APIs.
- */
-static int
-virDomainMigratePeer2PeerFull(virDomainPtr domain,
-                              const char *dconnuri,
-                              const char *xmlin,
-                              const char *dname,
-                              const char *uri,
-                              unsigned long long bandwidth,
-                              virTypedParameterPtr params,
-                              int nparams,
-                              bool useParams,
-                              unsigned int flags)
-{
-    virURIPtr tempuri = NULL;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "dconnuri=%s, xmlin=%s, dname=%s, uri=%s, bandwidth=%llu "
-                     "params=%p, nparams=%d, useParams=%d, flags=%x",
-                     dconnuri, NULLSTR(xmlin), NULLSTR(dname), NULLSTR(uri),
-                     bandwidth, params, nparams, useParams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    if ((useParams && !domain->conn->driver->domainMigratePerform3Params) ||
-        (!useParams &&
-         !domain->conn->driver->domainMigratePerform &&
-         !domain->conn->driver->domainMigratePerform3)) {
-        virReportUnsupportedError();
-        return -1;
-    }
-
-    if (!(tempuri = virURIParse(dconnuri)))
-        return -1;
-    if (!tempuri->server || STRPREFIX(tempuri->server, "localhost")) {
-        virReportInvalidArg(dconnuri,
-                            _("unable to parse server from dconnuri in %s"),
-                            __FUNCTION__);
-        virURIFree(tempuri);
-        return -1;
-    }
-    virURIFree(tempuri);
-
-    if (useParams) {
-        VIR_DEBUG("Using migration protocol 3 with extensible parameters");
-        return domain->conn->driver->domainMigratePerform3Params
-                (domain, dconnuri, params, nparams,
-                 NULL, 0, NULL, NULL, flags);
-    } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                        VIR_DRV_FEATURE_MIGRATION_V3)) {
-        VIR_DEBUG("Using migration protocol 3");
-        return domain->conn->driver->domainMigratePerform3
-                (domain, xmlin, NULL, 0, NULL, NULL, dconnuri,
-                 uri, flags, dname, bandwidth);
-    } else {
-        VIR_DEBUG("Using migration protocol 2");
-        if (xmlin) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("Unable to change target guest XML during "
-                             "migration"));
-            return -1;
-        }
-        if (uri) {
-            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
-                           _("Unable to override peer2peer migration URI"));
-            return -1;
-        }
-        return domain->conn->driver->domainMigratePerform
-                (domain, NULL, 0, dconnuri, flags, dname, bandwidth);
-    }
-}
-
-
-static int
-virDomainMigratePeer2Peer(virDomainPtr domain,
-                          const char *xmlin,
-                          unsigned long flags,
-                          const char *dname,
-                          const char *dconnuri,
-                          const char *uri,
-                          unsigned long bandwidth)
-{
-    return virDomainMigratePeer2PeerFull(domain, dconnuri, xmlin, dname, uri,
-                                         bandwidth, NULL, 0, false, flags);
-}
-
-
-static int
-virDomainMigratePeer2PeerParams(virDomainPtr domain,
-                                const char *dconnuri,
-                                virTypedParameterPtr params,
-                                int nparams,
-                                unsigned int flags)
-{
-    return virDomainMigratePeer2PeerFull(domain, dconnuri, NULL, NULL, NULL, 0,
-                                         params, nparams, true, flags);
-}
-
-
-/*
- * In normal migration, the libvirt client co-ordinates communication
- * between the 2 libvirtd instances on source & dest hosts.
- *
- * Some hypervisors support an alternative, direct migration where
- * there is no requirement for a libvirtd instance on the dest host.
- * In this case
- *
- * eg, XenD can talk direct to XenD, so libvirtd on dest does not
- * need to be involved at all, or even running
- */
-static int
-virDomainMigrateDirect(virDomainPtr domain,
-                       const char *xmlin,
-                       unsigned long flags,
-                       const char *dname,
-                       const char *uri,
-                       unsigned long bandwidth)
-{
-    VIR_DOMAIN_DEBUG(domain,
-                     "xmlin=%s, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
-                     NULLSTR(xmlin), flags, NULLSTR(dname), NULLSTR(uri),
-                     bandwidth);
-
-    if (!domain->conn->driver->domainMigratePerform) {
-        virReportUnsupportedError();
-        return -1;
-    }
-
-    /* Perform the migration.  The driver isn't supposed to return
-     * until the migration is complete.
-     */
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_MIGRATION_V3)) {
-        VIR_DEBUG("Using migration protocol 3");
-        /* dconn URI not relevant in direct migration, since no
-         * target libvirtd is involved */
-        return domain->conn->driver->domainMigratePerform3(domain,
-                                                           xmlin,
-                                                           NULL, /* cookiein */
-                                                           0,    /* cookieinlen */
-                                                           NULL, /* cookieoutlen */
-                                                           NULL, /* cookieoutlen */
-                                                           NULL, /* dconnuri */
-                                                           uri,
-                                                           flags,
-                                                           dname,
-                                                           bandwidth);
-    } else {
-        VIR_DEBUG("Using migration protocol 2");
-        if (xmlin) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("Unable to change target guest XML during migration"));
-            return -1;
-        }
-        return domain->conn->driver->domainMigratePerform(domain,
-                                                          NULL, /* cookie */
-                                                          0,    /* cookielen */
-                                                          uri,
-                                                          flags,
-                                                          dname,
-                                                          bandwidth);
-    }
-}
-
-
-/**
- * virDomainMigrate:
- * @domain: a domain object
- * @dconn: destination host (a connection object)
- * @flags: bitwise-OR of virDomainMigrateFlags
- * @dname: (optional) rename domain to this at destination
- * @uri: (optional) dest hostname/URI as seen from the source host
- * @bandwidth: (optional) specify migration bandwidth limit in MiB/s
- *
- * Migrate the domain object from its current host to the destination
- * host given by dconn (a connection to the destination host).
- *
- * Flags may be one of more of the following:
- *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
- *   VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
- *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
- *   VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
- *                            on the destination host.
- *   VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
- *                               domain on the source host.
- *   VIR_MIGRATE_PAUSED    Leave the domain suspended on the remote side.
- *   VIR_MIGRATE_NON_SHARED_DISK Migration with non-shared storage with full
- *                               disk copy
- *   VIR_MIGRATE_NON_SHARED_INC  Migration with non-shared storage with
- *                               incremental disk copy
- *   VIR_MIGRATE_CHANGE_PROTECTION Protect against domain configuration
- *                                 changes during the migration process (set
- *                                 automatically when supported).
- *   VIR_MIGRATE_UNSAFE    Force migration even if it is considered unsafe.
- *   VIR_MIGRATE_OFFLINE Migrate offline
- *
- * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
- * Applications using the VIR_MIGRATE_PEER2PEER flag will probably
- * prefer to invoke virDomainMigrateToURI, avoiding the need to
- * open connection to the destination host themselves.
- *
- * If a hypervisor supports renaming domains during migration,
- * then you may set the dname parameter to the new name (otherwise
- * it keeps the same name).  If this is not supported by the
- * hypervisor, dname must be NULL or else you will get an error.
- *
- * If the VIR_MIGRATE_PEER2PEER flag is set, the uri parameter
- * must be a valid libvirt connection URI, by which the source
- * libvirt driver can connect to the destination libvirt. If
- * omitted, the dconn connection object will be queried for its
- * current URI.
- *
- * If the VIR_MIGRATE_PEER2PEER flag is NOT set, the URI parameter
- * takes a hypervisor specific format. The hypervisor capabilities
- * XML includes details of the support URI schemes. If omitted
- * the dconn will be asked for a default URI.
- *
- * If you want to copy non-shared storage within migration you
- * can use either VIR_MIGRATE_NON_SHARED_DISK or
- * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
- *
- * In either case it is typically only necessary to specify a
- * URI if the destination host has multiple interfaces and a
- * specific interface is required to transmit migration data.
- *
- * The maximum bandwidth (in MiB/s) that will be used to do migration
- * can be specified with the bandwidth parameter.  If set to 0,
- * libvirt will choose a suitable default.  Some hypervisors do
- * not support this feature and will return an error if bandwidth
- * is not 0.
- *
- * To see which features are supported by the current hypervisor,
- * see virConnectGetCapabilities, /capabilities/host/migration_features.
- *
- * There are many limitations on migration imposed by the underlying
- * technology - for example it may not be possible to migrate between
- * different processors even with the same architecture, or between
- * different types of hypervisor.
- *
- * virDomainFree should be used to free the resources after the
- * returned domain object is no longer needed.
- *
- * Returns the new domain object if the migration was successful,
- *   or NULL in case of error.  Note that the new domain object
- *   exists in the scope of the destination connection (dconn).
- */
-virDomainPtr
-virDomainMigrate(virDomainPtr domain,
-                 virConnectPtr dconn,
-                 unsigned long flags,
-                 const char *dname,
-                 const char *uri,
-                 unsigned long bandwidth)
-{
-    virDomainPtr ddomain = NULL;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
-                     dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
-
-    virResetLastError();
-
-    /* First checkout the source */
-    virCheckDomainReturn(domain, NULL);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-
-    /* Now checkout the destination */
-    virCheckConnectGoto(dconn, error);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
-        flags & VIR_MIGRATE_NON_SHARED_INC) {
-        virReportInvalidArg(flags,
-                            _("flags 'shared disk' and 'shared incremental' "
-                              "in %s are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (flags & VIR_MIGRATE_OFFLINE) {
-        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("offline migration is not supported by "
-                             "the source host"));
-            goto error;
-        }
-        if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("offline migration is not supported by "
-                             "the destination host"));
-            goto error;
-        }
-    }
-
-    if (flags & VIR_MIGRATE_PEER2PEER) {
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_P2P)) {
-            char *dstURI = NULL;
-            if (uri == NULL) {
-                dstURI = virConnectGetURI(dconn);
-                if (!dstURI)
-                    return NULL;
-            }
-
-            VIR_DEBUG("Using peer2peer migration");
-            if (virDomainMigratePeer2Peer(domain, NULL, flags, dname,
-                                          uri ? uri : dstURI, NULL, bandwidth) < 0) {
-                VIR_FREE(dstURI);
-                goto error;
-            }
-            VIR_FREE(dstURI);
-
-            ddomain = virDomainLookupByName(dconn, dname ? dname : domain->name);
-        } else {
-            /* This driver does not support peer to peer migration */
-            virReportUnsupportedError();
-            goto error;
-        }
-    } else {
-        /* Change protection requires support only on source side, and
-         * is only needed in v3 migration, which automatically re-adds
-         * the flag for just the source side.  We mask it out for
-         * non-peer2peer to allow migration from newer source to an
-         * older destination that rejects the flag.  */
-        if (flags & VIR_MIGRATE_CHANGE_PROTECTION &&
-            !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                      VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION)) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("cannot enforce change protection"));
-            goto error;
-        }
-        flags &= ~VIR_MIGRATE_CHANGE_PROTECTION;
-        if (flags & VIR_MIGRATE_TUNNELLED) {
-            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                           _("cannot perform tunnelled migration without using peer2peer flag"));
-            goto error;
-        }
-
-        /* Check that migration is supported by both drivers. */
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_V3) &&
-            VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                     VIR_DRV_FEATURE_MIGRATION_V3)) {
-            VIR_DEBUG("Using migration protocol 3");
-            ddomain = virDomainMigrateVersion3(domain, dconn, NULL,
-                                               flags, dname, uri, bandwidth);
-        } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                            VIR_DRV_FEATURE_MIGRATION_V2) &&
-                   VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                          VIR_DRV_FEATURE_MIGRATION_V2)) {
-            VIR_DEBUG("Using migration protocol 2");
-            ddomain = virDomainMigrateVersion2(domain, dconn, flags,
-                                               dname, uri, bandwidth);
-        } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                            VIR_DRV_FEATURE_MIGRATION_V1) &&
-                   VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                            VIR_DRV_FEATURE_MIGRATION_V1)) {
-            VIR_DEBUG("Using migration protocol 1");
-            ddomain = virDomainMigrateVersion1(domain, dconn, flags,
-                                               dname, uri, bandwidth);
-        } else {
-            /* This driver does not support any migration method */
-            virReportUnsupportedError();
-            goto error;
-        }
-    }
-
-    if (ddomain == NULL)
-        goto error;
-
-    return ddomain;
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virDomainMigrate2:
- * @domain: a domain object
- * @dconn: destination host (a connection object)
- * @flags: bitwise-OR of virDomainMigrateFlags
- * @dxml: (optional) XML config for launching guest on target
- * @dname: (optional) rename domain to this at destination
- * @uri: (optional) dest hostname/URI as seen from the source host
- * @bandwidth: (optional) specify migration bandwidth limit in MiB/s
- *
- * Migrate the domain object from its current host to the destination
- * host given by dconn (a connection to the destination host).
- *
- * Flags may be one of more of the following:
- *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
- *   VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
- *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
- *   VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
- *                            on the destination host.
- *   VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
- *                               domain on the source host.
- *   VIR_MIGRATE_PAUSED    Leave the domain suspended on the remote side.
- *   VIR_MIGRATE_NON_SHARED_DISK Migration with non-shared storage with full
- *                               disk copy
- *   VIR_MIGRATE_NON_SHARED_INC  Migration with non-shared storage with
- *                               incremental disk copy
- *   VIR_MIGRATE_CHANGE_PROTECTION Protect against domain configuration
- *                                 changes during the migration process (set
- *                                 automatically when supported).
- *   VIR_MIGRATE_UNSAFE    Force migration even if it is considered unsafe.
- *   VIR_MIGRATE_OFFLINE Migrate offline
- *
- * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
- * Applications using the VIR_MIGRATE_PEER2PEER flag will probably
- * prefer to invoke virDomainMigrateToURI, avoiding the need to
- * open connection to the destination host themselves.
- *
- * If a hypervisor supports renaming domains during migration,
- * then you may set the dname parameter to the new name (otherwise
- * it keeps the same name).  If this is not supported by the
- * hypervisor, dname must be NULL or else you will get an error.
- *
- * If the VIR_MIGRATE_PEER2PEER flag is set, the uri parameter
- * must be a valid libvirt connection URI, by which the source
- * libvirt driver can connect to the destination libvirt. If
- * omitted, the dconn connection object will be queried for its
- * current URI.
- *
- * If the VIR_MIGRATE_PEER2PEER flag is NOT set, the URI parameter
- * takes a hypervisor specific format. The hypervisor capabilities
- * XML includes details of the support URI schemes. If omitted
- * the dconn will be asked for a default URI.
- *
- * If you want to copy non-shared storage within migration you
- * can use either VIR_MIGRATE_NON_SHARED_DISK or
- * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
- *
- * In either case it is typically only necessary to specify a
- * URI if the destination host has multiple interfaces and a
- * specific interface is required to transmit migration data.
- *
- * The maximum bandwidth (in MiB/s) that will be used to do migration
- * can be specified with the bandwidth parameter.  If set to 0,
- * libvirt will choose a suitable default.  Some hypervisors do
- * not support this feature and will return an error if bandwidth
- * is not 0.
- *
- * To see which features are supported by the current hypervisor,
- * see virConnectGetCapabilities, /capabilities/host/migration_features.
- *
- * There are many limitations on migration imposed by the underlying
- * technology - for example it may not be possible to migrate between
- * different processors even with the same architecture, or between
- * different types of hypervisor.
- *
- * If the hypervisor supports it, @dxml can be used to alter
- * host-specific portions of the domain XML that will be used on
- * the destination.  For example, it is possible to alter the
- * backing filename that is associated with a disk device, in order
- * to account for naming differences between source and destination
- * in accessing the underlying storage.  The migration will fail
- * if @dxml would cause any guest-visible changes.  Pass NULL
- * if no changes are needed to the XML between source and destination.
- * @dxml cannot be used to rename the domain during migration (use
- * @dname for that purpose).  Domain name in @dxml must match the
- * original domain name.
- *
- * virDomainFree should be used to free the resources after the
- * returned domain object is no longer needed.
- *
- * Returns the new domain object if the migration was successful,
- *   or NULL in case of error.  Note that the new domain object
- *   exists in the scope of the destination connection (dconn).
- */
-virDomainPtr
-virDomainMigrate2(virDomainPtr domain,
-                  virConnectPtr dconn,
-                  const char *dxml,
-                  unsigned long flags,
-                  const char *dname,
-                  const char *uri,
-                  unsigned long bandwidth)
-{
-    virDomainPtr ddomain = NULL;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "dconn=%p, flags=%lx, dname=%s, uri=%s, bandwidth=%lu",
-                     dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
-
-    virResetLastError();
-
-    /* First checkout the source */
-    virCheckDomainReturn(domain, NULL);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-
-    /* Now checkout the destination */
-    virCheckConnectGoto(dconn, error);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
-        flags & VIR_MIGRATE_NON_SHARED_INC) {
-        virReportInvalidArg(flags,
-                            _("flags 'shared disk' and 'shared incremental' "
-                              "in %s are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (flags & VIR_MIGRATE_OFFLINE) {
-        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("offline migration is not supported by "
-                             "the source host"));
-            goto error;
-        }
-        if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("offline migration is not supported by "
-                             "the destination host"));
-            goto error;
-        }
-    }
-
-    if (flags & VIR_MIGRATE_PEER2PEER) {
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_P2P)) {
-            char *dstURI = virConnectGetURI(dconn);
-            if (!dstURI)
-                return NULL;
-
-            VIR_DEBUG("Using peer2peer migration");
-            if (virDomainMigratePeer2Peer(domain, dxml, flags, dname,
-                                          dstURI, uri, bandwidth) < 0) {
-                VIR_FREE(dstURI);
-                goto error;
-            }
-            VIR_FREE(dstURI);
-
-            ddomain = virDomainLookupByName(dconn, dname ? dname : domain->name);
-        } else {
-            /* This driver does not support peer to peer migration */
-            virReportUnsupportedError();
-            goto error;
-        }
-    } else {
-        /* Change protection requires support only on source side, and
-         * is only needed in v3 migration, which automatically re-adds
-         * the flag for just the source side.  We mask it out for
-         * non-peer2peer to allow migration from newer source to an
-         * older destination that rejects the flag.  */
-        if (flags & VIR_MIGRATE_CHANGE_PROTECTION &&
-            !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                      VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION)) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("cannot enforce change protection"));
-            goto error;
-        }
-        flags &= ~VIR_MIGRATE_CHANGE_PROTECTION;
-        if (flags & VIR_MIGRATE_TUNNELLED) {
-            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                           _("cannot perform tunnelled migration without using peer2peer flag"));
-            goto error;
-        }
-
-        /* Check that migration is supported by both drivers. */
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_V3) &&
-            VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                     VIR_DRV_FEATURE_MIGRATION_V3)) {
-            VIR_DEBUG("Using migration protocol 3");
-            ddomain = virDomainMigrateVersion3(domain, dconn, dxml,
-                                               flags, dname, uri, bandwidth);
-        } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                            VIR_DRV_FEATURE_MIGRATION_V2) &&
-                   VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                          VIR_DRV_FEATURE_MIGRATION_V2)) {
-            VIR_DEBUG("Using migration protocol 2");
-            if (dxml) {
-                virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                               _("Unable to change target guest XML during migration"));
-                goto error;
-            }
-            ddomain = virDomainMigrateVersion2(domain, dconn, flags,
-                                               dname, uri, bandwidth);
-        } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                            VIR_DRV_FEATURE_MIGRATION_V1) &&
-                   VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                            VIR_DRV_FEATURE_MIGRATION_V1)) {
-            VIR_DEBUG("Using migration protocol 1");
-            if (dxml) {
-                virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                               _("Unable to change target guest XML during migration"));
-                goto error;
-            }
-            ddomain = virDomainMigrateVersion1(domain, dconn, flags,
-                                               dname, uri, bandwidth);
-        } else {
-            /* This driver does not support any migration method */
-            virReportUnsupportedError();
-            goto error;
-        }
-    }
-
-    if (ddomain == NULL)
-        goto error;
-
-    return ddomain;
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virDomainMigrate3:
- * @domain: a domain object
- * @dconn: destination host (a connection object)
- * @params: (optional) migration parameters
- * @nparams: (optional) number of migration parameters in @params
- * @flags: bitwise-OR of virDomainMigrateFlags
- *
- * Migrate the domain object from its current host to the destination host
- * given by dconn (a connection to the destination host).
- *
- * See virDomainMigrateFlags documentation for description of individual flags.
- *
- * VIR_MIGRATE_TUNNELLED and VIR_MIGRATE_PEER2PEER are not supported by this
- * API, use virDomainMigrateToURI3 instead.
- *
- * If you want to copy non-shared storage within migration you
- * can use either VIR_MIGRATE_NON_SHARED_DISK or
- * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
- *
- * There are many limitations on migration imposed by the underlying
- * technology - for example it may not be possible to migrate between
- * different processors even with the same architecture, or between
- * different types of hypervisor.
- *
- * virDomainFree should be used to free the resources after the
- * returned domain object is no longer needed.
- *
- * Returns the new domain object if the migration was successful,
- *   or NULL in case of error.  Note that the new domain object
- *   exists in the scope of the destination connection (dconn).
- */
-virDomainPtr
-virDomainMigrate3(virDomainPtr domain,
-                  virConnectPtr dconn,
-                  virTypedParameterPtr params,
-                  unsigned int nparams,
-                  unsigned int flags)
-{
-    virDomainPtr ddomain = NULL;
-    const char *compatParams[] = { VIR_MIGRATE_PARAM_URI,
-                                   VIR_MIGRATE_PARAM_DEST_NAME,
-                                   VIR_MIGRATE_PARAM_DEST_XML,
-                                   VIR_MIGRATE_PARAM_BANDWIDTH };
-    const char *uri = NULL;
-    const char *dname = NULL;
-    const char *dxml = NULL;
-    unsigned long long bandwidth = 0;
-
-    VIR_DOMAIN_DEBUG(domain, "dconn=%p, params=%p, nparms=%u flags=%x",
-                     dconn, params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    /* First checkout the source */
-    virCheckDomainReturn(domain, NULL);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-
-    /* Now checkout the destination */
-    virCheckConnectGoto(dconn, error);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
-        flags & VIR_MIGRATE_NON_SHARED_INC) {
-        virReportInvalidArg(flags,
-                            _("flags 'shared disk' and 'shared incremental' "
-                              "in %s are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-    if (flags & VIR_MIGRATE_PEER2PEER) {
-        virReportInvalidArg(flags, "%s",
-                            _("use virDomainMigrateToURI3 for peer-to-peer "
-                              "migration"));
-        goto error;
-    }
-    if (flags & VIR_MIGRATE_TUNNELLED) {
-        virReportInvalidArg(flags, "%s",
-                            _("cannot perform tunnelled migration "
-                              "without using peer2peer flag"));
-        goto error;
-    }
-
-    if (flags & VIR_MIGRATE_OFFLINE) {
-        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("offline migration is not supported by "
-                             "the source host"));
-            goto error;
-        }
-        if (!VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                      VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("offline migration is not supported by "
-                             "the destination host"));
-            goto error;
-        }
-    }
-
-    /* Change protection requires support only on source side, and
-     * is only needed in v3 migration, which automatically re-adds
-     * the flag for just the source side.  We mask it out to allow
-     * migration from newer source to an older destination that
-     * rejects the flag.  */
-    if (flags & VIR_MIGRATE_CHANGE_PROTECTION &&
-        !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                  VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION)) {
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                       _("cannot enforce change protection"));
-        goto error;
-    }
-    flags &= ~VIR_MIGRATE_CHANGE_PROTECTION;
-
-    /* Prefer extensible API but fall back to older migration APIs if params
-     * only contains parameters which were supported by the older API. */
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_MIGRATION_PARAMS) &&
-        VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                 VIR_DRV_FEATURE_MIGRATION_PARAMS)) {
-        VIR_DEBUG("Using migration protocol 3 with extensible parameters");
-        ddomain = virDomainMigrateVersion3Params(domain, dconn, params,
-                                                 nparams, flags);
-        goto done;
-    }
-
-    if (!virTypedParamsCheck(params, nparams, compatParams,
-                             ARRAY_CARDINALITY(compatParams))) {
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                       _("Migration APIs with extensible parameters are not "
-                         "supported but extended parameters were passed"));
-        goto error;
-    }
-
-    if (virTypedParamsGetString(params, nparams,
-                                VIR_MIGRATE_PARAM_URI, &uri) < 0 ||
-        virTypedParamsGetString(params, nparams,
-                                VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0 ||
-        virTypedParamsGetString(params, nparams,
-                                VIR_MIGRATE_PARAM_DEST_XML, &dxml) < 0 ||
-        virTypedParamsGetULLong(params, nparams,
-                                VIR_MIGRATE_PARAM_BANDWIDTH, &bandwidth) < 0) {
-        goto error;
-    }
-
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_MIGRATION_V3) &&
-        VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                 VIR_DRV_FEATURE_MIGRATION_V3)) {
-        VIR_DEBUG("Using migration protocol 3");
-        ddomain = virDomainMigrateVersion3(domain, dconn, dxml, flags,
-                                           dname, uri, bandwidth);
-    } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                        VIR_DRV_FEATURE_MIGRATION_V2) &&
-               VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                      VIR_DRV_FEATURE_MIGRATION_V2)) {
-        VIR_DEBUG("Using migration protocol 2");
-        if (dxml) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("Unable to change target guest XML during "
-                             "migration"));
-            goto error;
-        }
-        ddomain = virDomainMigrateVersion2(domain, dconn, flags,
-                                           dname, uri, bandwidth);
-    } else if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                        VIR_DRV_FEATURE_MIGRATION_V1) &&
-               VIR_DRV_SUPPORTS_FEATURE(dconn->driver, dconn,
-                                        VIR_DRV_FEATURE_MIGRATION_V1)) {
-        VIR_DEBUG("Using migration protocol 1");
-        if (dxml) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("Unable to change target guest XML during "
-                             "migration"));
-            goto error;
-        }
-        ddomain = virDomainMigrateVersion1(domain, dconn, flags,
-                                           dname, uri, bandwidth);
-    } else {
-        /* This driver does not support any migration method */
-        virReportUnsupportedError();
-        goto error;
-    }
-
- done:
-    if (ddomain == NULL)
-        goto error;
-
-    return ddomain;
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virDomainMigrateToURI:
- * @domain: a domain object
- * @duri: mandatory URI for the destination host
- * @flags: bitwise-OR of virDomainMigrateFlags
- * @dname: (optional) rename domain to this at destination
- * @bandwidth: (optional) specify migration bandwidth limit in MiB/s
- *
- * Migrate the domain object from its current host to the destination
- * host given by duri.
- *
- * Flags may be one of more of the following:
- *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
- *   VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
- *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
- *   VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
- *                            on the destination host.
- *   VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
- *                               domain on the source host.
- *   VIR_MIGRATE_PAUSED    Leave the domain suspended on the remote side.
- *   VIR_MIGRATE_NON_SHARED_DISK Migration with non-shared storage with full
- *                               disk copy
- *   VIR_MIGRATE_NON_SHARED_INC  Migration with non-shared storage with
- *                               incremental disk copy
- *   VIR_MIGRATE_CHANGE_PROTECTION Protect against domain configuration
- *                                 changes during the migration process (set
- *                                 automatically when supported).
- *   VIR_MIGRATE_UNSAFE    Force migration even if it is considered unsafe.
- *   VIR_MIGRATE_OFFLINE Migrate offline
- *
- * The operation of this API hinges on the VIR_MIGRATE_PEER2PEER flag.
- * If the VIR_MIGRATE_PEER2PEER flag is NOT set, the duri parameter
- * takes a hypervisor specific format. The uri_transports element of the
- * hypervisor capabilities XML includes details of the supported URI
- * schemes. Not all hypervisors will support this mode of migration, so
- * if the VIR_MIGRATE_PEER2PEER flag is not set, then it may be necessary
- * to use the alternative virDomainMigrate API providing and explicit
- * virConnectPtr for the destination host.
- *
- * If the VIR_MIGRATE_PEER2PEER flag IS set, the duri parameter
- * must be a valid libvirt connection URI, by which the source
- * libvirt driver can connect to the destination libvirt.
- *
- * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
- *
- * If you want to copy non-shared storage within migration you
- * can use either VIR_MIGRATE_NON_SHARED_DISK or
- * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
- *
- * If a hypervisor supports renaming domains during migration,
- * the dname parameter specifies the new name for the domain.
- * Setting dname to NULL keeps the domain name the same.  If domain
- * renaming is not supported by the hypervisor, dname must be NULL or
- * else an error will be returned.
- *
- * The maximum bandwidth (in MiB/s) that will be used to do migration
- * can be specified with the bandwidth parameter.  If set to 0,
- * libvirt will choose a suitable default.  Some hypervisors do
- * not support this feature and will return an error if bandwidth
- * is not 0.
- *
- * To see which features are supported by the current hypervisor,
- * see virConnectGetCapabilities, /capabilities/host/migration_features.
- *
- * There are many limitations on migration imposed by the underlying
- * technology - for example it may not be possible to migrate between
- * different processors even with the same architecture, or between
- * different types of hypervisor.
- *
- * Returns 0 if the migration succeeded, -1 upon error.
- */
-int
-virDomainMigrateToURI(virDomainPtr domain,
-                      const char *duri,
-                      unsigned long flags,
-                      const char *dname,
-                      unsigned long bandwidth)
-{
-    VIR_DOMAIN_DEBUG(domain, "duri=%p, flags=%lx, dname=%s, bandwidth=%lu",
-                     NULLSTR(duri), flags, NULLSTR(dname), bandwidth);
-
-    virResetLastError();
-
-    /* First checkout the source */
-    virCheckDomainReturn(domain, -1);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-
-    virCheckNonNullArgGoto(duri, error);
-
-    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
-        flags & VIR_MIGRATE_NON_SHARED_INC) {
-        virReportInvalidArg(flags,
-                            _("flags 'shared disk' and 'shared incremental' "
-                              "in %s are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (flags & VIR_MIGRATE_OFFLINE &&
-        !VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                  VIR_DRV_FEATURE_MIGRATION_OFFLINE)) {
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                       _("offline migration is not supported by "
-                         "the source host"));
-        goto error;
-    }
-
-    if (flags & VIR_MIGRATE_PEER2PEER) {
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_P2P)) {
-            VIR_DEBUG("Using peer2peer migration");
-            if (virDomainMigratePeer2Peer(domain, NULL, flags,
-                                          dname, duri, NULL, bandwidth) < 0)
-                goto error;
-        } else {
-            /* No peer to peer migration supported */
-            virReportUnsupportedError();
-            goto error;
-        }
-    } else {
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_DIRECT)) {
-            VIR_DEBUG("Using direct migration");
-            if (virDomainMigrateDirect(domain, NULL, flags,
-                                       dname, duri, bandwidth) < 0)
-                goto error;
-        } else {
-            /* Cannot do a migration with only the perform step */
-            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                           _("direct migration is not supported by the"
-                             " connection driver"));
-            goto error;
-        }
-    }
-
-    return 0;
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainMigrateToURI2:
- * @domain: a domain object
- * @dconnuri: (optional) URI for target libvirtd if @flags includes VIR_MIGRATE_PEER2PEER
- * @miguri: (optional) URI for invoking the migration, not if @flags includs VIR_MIGRATE_TUNNELLED
- * @dxml: (optional) XML config for launching guest on target
- * @flags: bitwise-OR of virDomainMigrateFlags
- * @dname: (optional) rename domain to this at destination
- * @bandwidth: (optional) specify migration bandwidth limit in MiB/s
- *
- * Migrate the domain object from its current host to the destination
- * host given by duri.
- *
- * Flags may be one of more of the following:
- *   VIR_MIGRATE_LIVE      Do not pause the VM during migration
- *   VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
- *   VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
- *   VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
- *                            on the destination host.
- *   VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
- *                               domain on the source host.
- *   VIR_MIGRATE_PAUSED    Leave the domain suspended on the remote side.
- *   VIR_MIGRATE_NON_SHARED_DISK Migration with non-shared storage with full
- *                               disk copy
- *   VIR_MIGRATE_NON_SHARED_INC  Migration with non-shared storage with
- *                               incremental disk copy
- *   VIR_MIGRATE_CHANGE_PROTECTION Protect against domain configuration
- *                                 changes during the migration process (set
- *                                 automatically when supported).
- *   VIR_MIGRATE_UNSAFE    Force migration even if it is considered unsafe.
- *   VIR_MIGRATE_OFFLINE Migrate offline
- *
- * The operation of this API hinges on the VIR_MIGRATE_PEER2PEER flag.
- *
- * If the VIR_MIGRATE_PEER2PEER flag is set, the @dconnuri parameter
- * must be a valid libvirt connection URI, by which the source
- * libvirt driver can connect to the destination libvirt. If the
- * VIR_MIGRATE_PEER2PEER flag is NOT set, then @dconnuri must be
- * NULL.
- *
- * If the VIR_MIGRATE_TUNNELLED flag is NOT set, then the @miguri
- * parameter allows specification of a URI to use to initiate the
- * VM migration. It takes a hypervisor specific format. The uri_transports
- * element of the hypervisor capabilities XML includes details of the
- * supported URI schemes.
- *
- * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
- *
- * If you want to copy non-shared storage within migration you
- * can use either VIR_MIGRATE_NON_SHARED_DISK or
- * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
- *
- * If a hypervisor supports changing the configuration of the guest
- * during migration, the @dxml parameter specifies the new config
- * for the guest. The configuration must include an identical set
- * of virtual devices, to ensure a stable guest ABI across migration.
- * Only parameters related to host side configuration can be
- * changed in the XML. Hypervisors will validate this and refuse to
- * allow migration if the provided XML would cause a change in the
- * guest ABI,
- *
- * If a hypervisor supports renaming domains during migration,
- * the dname parameter specifies the new name for the domain.
- * Setting dname to NULL keeps the domain name the same.  If domain
- * renaming is not supported by the hypervisor, dname must be NULL or
- * else an error will be returned.
- *
- * The maximum bandwidth (in MiB/s) that will be used to do migration
- * can be specified with the bandwidth parameter.  If set to 0,
- * libvirt will choose a suitable default.  Some hypervisors do
- * not support this feature and will return an error if bandwidth
- * is not 0.
- *
- * To see which features are supported by the current hypervisor,
- * see virConnectGetCapabilities, /capabilities/host/migration_features.
- *
- * There are many limitations on migration imposed by the underlying
- * technology - for example it may not be possible to migrate between
- * different processors even with the same architecture, or between
- * different types of hypervisor.
- *
- * Returns 0 if the migration succeeded, -1 upon error.
- */
-int
-virDomainMigrateToURI2(virDomainPtr domain,
-                       const char *dconnuri,
-                       const char *miguri,
-                       const char *dxml,
-                       unsigned long flags,
-                       const char *dname,
-                       unsigned long bandwidth)
-{
-    VIR_DOMAIN_DEBUG(domain, "dconnuri=%s, miguri=%s, dxml=%s, "
-                     "flags=%lx, dname=%s, bandwidth=%lu",
-                     NULLSTR(dconnuri), NULLSTR(miguri), NULLSTR(dxml),
-                     flags, NULLSTR(dname), bandwidth);
-
-    virResetLastError();
-
-    /* First checkout the source */
-    virCheckDomainReturn(domain, -1);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-
-    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
-        flags & VIR_MIGRATE_NON_SHARED_INC) {
-        virReportInvalidArg(flags,
-                            _("flags 'shared disk' and 'shared incremental' "
-                              "in %s are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (flags & VIR_MIGRATE_PEER2PEER) {
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_P2P)) {
-            VIR_DEBUG("Using peer2peer migration");
-            if (virDomainMigratePeer2Peer(domain, dxml, flags,
-                                          dname, dconnuri, miguri, bandwidth) < 0)
-                goto error;
-        } else {
-            /* No peer to peer migration supported */
-            virReportUnsupportedError();
-            goto error;
-        }
-    } else {
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_DIRECT)) {
-            VIR_DEBUG("Using direct migration");
-            if (virDomainMigrateDirect(domain, dxml, flags,
-                                       dname, miguri, bandwidth) < 0)
-                goto error;
-        } else {
-            /* Cannot do a migration with only the perform step */
-            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                           _("direct migration is not supported by the"
-                             " connection driver"));
-            goto error;
-        }
-    }
-
-    return 0;
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainMigrateToURI3:
- * @domain: a domain object
- * @dconnuri: (optional) URI for target libvirtd if @flags includes VIR_MIGRATE_PEER2PEER
- * @params: (optional) migration parameters
- * @nparams: (optional) number of migration parameters in @params
- * @flags: bitwise-OR of virDomainMigrateFlags
- *
- * Migrate the domain object from its current host to the destination host
- * given by URI.
- *
- * See virDomainMigrateFlags documentation for description of individual flags.
- *
- * The operation of this API hinges on the VIR_MIGRATE_PEER2PEER flag.
- *
- * If the VIR_MIGRATE_PEER2PEER flag is set, the @dconnuri parameter must be a
- * valid libvirt connection URI, by which the source libvirt daemon can connect
- * to the destination libvirt.
- *
- * If the VIR_MIGRATE_PEER2PEER flag is NOT set, then @dconnuri must be NULL
- * and VIR_MIGRATE_PARAM_URI migration parameter must be filled in with
- * hypervisor specific URI used to initiate the migration. This is called
- * "direct" migration.
- *
- * VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
- *
- * If you want to copy non-shared storage within migration you
- * can use either VIR_MIGRATE_NON_SHARED_DISK or
- * VIR_MIGRATE_NON_SHARED_INC as they are mutually exclusive.
- *
- * There are many limitations on migration imposed by the underlying
- * technology - for example it may not be possible to migrate between
- * different processors even with the same architecture, or between
- * different types of hypervisor.
- *
- * Returns 0 if the migration succeeded, -1 upon error.
- */
-int
-virDomainMigrateToURI3(virDomainPtr domain,
-                       const char *dconnuri,
-                       virTypedParameterPtr params,
-                       unsigned int nparams,
-                       unsigned int flags)
-{
-    bool compat;
-    const char *compatParams[] = { VIR_MIGRATE_PARAM_URI,
-                                   VIR_MIGRATE_PARAM_DEST_NAME,
-                                   VIR_MIGRATE_PARAM_DEST_XML,
-                                   VIR_MIGRATE_PARAM_BANDWIDTH };
-    const char *uri = NULL;
-    const char *dname = NULL;
-    const char *dxml = NULL;
-    unsigned long long bandwidth = 0;
-
-    VIR_DOMAIN_DEBUG(domain, "dconnuri=%s, params=%p, nparms=%u flags=%x",
-                     NULLSTR(dconnuri), params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    /* First checkout the source */
-    virCheckDomainReturn(domain, -1);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-
-    if (flags & VIR_MIGRATE_NON_SHARED_DISK &&
-        flags & VIR_MIGRATE_NON_SHARED_INC) {
-        virReportInvalidArg(flags,
-                            _("flags 'shared disk' and 'shared incremental' "
-                              "in %s are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    compat = virTypedParamsCheck(params, nparams, compatParams,
-                                 ARRAY_CARDINALITY(compatParams));
-
-    if (virTypedParamsGetString(params, nparams,
-                                VIR_MIGRATE_PARAM_URI, &uri) < 0 ||
-        virTypedParamsGetString(params, nparams,
-                                VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0 ||
-        virTypedParamsGetString(params, nparams,
-                                VIR_MIGRATE_PARAM_DEST_XML, &dxml) < 0 ||
-        virTypedParamsGetULLong(params, nparams,
-                                VIR_MIGRATE_PARAM_BANDWIDTH, &bandwidth) < 0) {
-        goto error;
-    }
-
-    if (flags & VIR_MIGRATE_PEER2PEER) {
-        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                      VIR_DRV_FEATURE_MIGRATION_P2P)) {
-            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                           _("Peer-to-peer migration is not supported by "
-                             "the connection driver"));
-            goto error;
-        }
-
-        if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                     VIR_DRV_FEATURE_MIGRATION_PARAMS)) {
-            VIR_DEBUG("Using peer2peer migration with extensible parameters");
-            if (virDomainMigratePeer2PeerParams(domain, dconnuri, params,
-                                                nparams, flags) < 0)
-                goto error;
-        } else if (compat) {
-            VIR_DEBUG("Using peer2peer migration");
-            if (virDomainMigratePeer2Peer(domain, dxml, flags, dname,
-                                          dconnuri, uri, bandwidth) < 0)
-                goto error;
-        } else {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("Peer-to-peer migration with extensible "
-                             "parameters is not supported but extended "
-                             "parameters were passed"));
-            goto error;
-        }
-    } else {
-        if (!VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                      VIR_DRV_FEATURE_MIGRATION_DIRECT)) {
-            /* Cannot do a migration with only the perform step */
-            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                           _("Direct migration is not supported by the"
-                             " connection driver"));
-            goto error;
-        }
-
-        if (!compat) {
-            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                           _("Direct migration does not support extensible "
-                             "parameters"));
-            goto error;
-        }
-
-        VIR_DEBUG("Using direct migration");
-        if (virDomainMigrateDirect(domain, dxml, flags,
-                                   dname, uri, bandwidth) < 0)
-            goto error;
-    }
-
-    return 0;
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePrepare(virConnectPtr dconn,
-                        char **cookie,
-                        int *cookielen,
-                        const char *uri_in,
-                        char **uri_out,
-                        unsigned long flags,
-                        const char *dname,
-                        unsigned long bandwidth)
-{
-    VIR_DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p, "
-              "flags=%lx, dname=%s, bandwidth=%lu", dconn, cookie, cookielen,
-              NULLSTR(uri_in), uri_out, flags, NULLSTR(dname), bandwidth);
-
-    virResetLastError();
-
-    virCheckConnectReturn(dconn, -1);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (dconn->driver->domainMigratePrepare) {
-        int ret;
-        ret = dconn->driver->domainMigratePrepare(dconn, cookie, cookielen,
-                                                  uri_in, uri_out,
-                                                  flags, dname, bandwidth);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dconn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePerform(virDomainPtr domain,
-                        const char *cookie,
-                        int cookielen,
-                        const char *uri,
-                        unsigned long flags,
-                        const char *dname,
-                        unsigned long bandwidth)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "cookie=%p, cookielen=%d, uri=%s, flags=%lx, "
-                     "dname=%s, bandwidth=%lu", cookie, cookielen, uri, flags,
-                     NULLSTR(dname), bandwidth);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigratePerform) {
-        int ret;
-        ret = conn->driver->domainMigratePerform(domain, cookie, cookielen,
-                                                 uri,
-                                                 flags, dname, bandwidth);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-virDomainPtr
-virDomainMigrateFinish(virConnectPtr dconn,
-                       const char *dname,
-                       const char *cookie,
-                       int cookielen,
-                       const char *uri,
-                       unsigned long flags)
-{
-    VIR_DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, "
-              "flags=%lx", dconn, NULLSTR(dname), cookie, cookielen,
-              uri, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(dconn, NULL);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (dconn->driver->domainMigrateFinish) {
-        virDomainPtr ret;
-        ret = dconn->driver->domainMigrateFinish(dconn, dname,
-                                                 cookie, cookielen,
-                                                 uri, flags);
-        if (!ret)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dconn);
-    return NULL;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePrepare2(virConnectPtr dconn,
-                         char **cookie,
-                         int *cookielen,
-                         const char *uri_in,
-                         char **uri_out,
-                         unsigned long flags,
-                         const char *dname,
-                         unsigned long bandwidth,
-                         const char *dom_xml)
-{
-    VIR_DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p,"
-              "flags=%lx, dname=%s, bandwidth=%lu, dom_xml=%s", dconn,
-              cookie, cookielen, uri_in, uri_out, flags, NULLSTR(dname),
-              bandwidth, dom_xml);
-
-    virResetLastError();
-
-    virCheckConnectReturn(dconn, -1);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (dconn->driver->domainMigratePrepare2) {
-        int ret;
-        ret = dconn->driver->domainMigratePrepare2(dconn, cookie, cookielen,
-                                                   uri_in, uri_out,
-                                                   flags, dname, bandwidth,
-                                                   dom_xml);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dconn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-virDomainPtr
-virDomainMigrateFinish2(virConnectPtr dconn,
-                        const char *dname,
-                        const char *cookie,
-                        int cookielen,
-                        const char *uri,
-                        unsigned long flags,
-                        int retcode)
-{
-    VIR_DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, "
-              "flags=%lx, retcode=%d", dconn, NULLSTR(dname), cookie,
-              cookielen, uri, flags, retcode);
-
-    virResetLastError();
-
-    virCheckConnectReturn(dconn, NULL);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (dconn->driver->domainMigrateFinish2) {
-        virDomainPtr ret;
-        ret = dconn->driver->domainMigrateFinish2(dconn, dname,
-                                                  cookie, cookielen,
-                                                  uri, flags,
-                                                  retcode);
-        if (!ret && !retcode)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dconn);
-    return NULL;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePrepareTunnel(virConnectPtr conn,
-                              virStreamPtr st,
-                              unsigned long flags,
-                              const char *dname,
-                              unsigned long bandwidth,
-                              const char *dom_xml)
-{
-    VIR_DEBUG("conn=%p, stream=%p, flags=%lx, dname=%s, "
-              "bandwidth=%lu, dom_xml=%s", conn, st, flags,
-              NULLSTR(dname), bandwidth, dom_xml);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn != st->conn) {
-        virReportInvalidArg(conn,
-                            _("conn in %s must match stream connection"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (conn->driver->domainMigratePrepareTunnel) {
-        int rv = conn->driver->domainMigratePrepareTunnel(conn, st,
-                                                          flags, dname,
-                                                          bandwidth, dom_xml);
-        if (rv < 0)
-            goto error;
-        return rv;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-char *
-virDomainMigrateBegin3(virDomainPtr domain,
-                       const char *xmlin,
-                       char **cookieout,
-                       int *cookieoutlen,
-                       unsigned long flags,
-                       const char *dname,
-                       unsigned long bandwidth)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "xmlin=%s cookieout=%p, cookieoutlen=%p, "
-                     "flags=%lx, dname=%s, bandwidth=%lu",
-                     NULLSTR(xmlin), cookieout, cookieoutlen, flags,
-                     NULLSTR(dname), bandwidth);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigrateBegin3) {
-        char *xml;
-        xml = conn->driver->domainMigrateBegin3(domain, xmlin,
-                                                cookieout, cookieoutlen,
-                                                flags, dname, bandwidth);
-        VIR_DEBUG("xml %s", NULLSTR(xml));
-        if (!xml)
-            goto error;
-        return xml;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePrepare3(virConnectPtr dconn,
-                         const char *cookiein,
-                         int cookieinlen,
-                         char **cookieout,
-                         int *cookieoutlen,
-                         const char *uri_in,
-                         char **uri_out,
-                         unsigned long flags,
-                         const char *dname,
-                         unsigned long bandwidth,
-                         const char *dom_xml)
-{
-    VIR_DEBUG("dconn=%p, cookiein=%p, cookieinlen=%d, cookieout=%p, "
-              "cookieoutlen=%p, uri_in=%s, uri_out=%p, flags=%lx, dname=%s, "
-              "bandwidth=%lu, dom_xml=%s",
-              dconn, cookiein, cookieinlen, cookieout, cookieoutlen, uri_in,
-              uri_out, flags, NULLSTR(dname), bandwidth, dom_xml);
-
-    virResetLastError();
-
-    virCheckConnectReturn(dconn, -1);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (dconn->driver->domainMigratePrepare3) {
-        int ret;
-        ret = dconn->driver->domainMigratePrepare3(dconn,
-                                                   cookiein, cookieinlen,
-                                                   cookieout, cookieoutlen,
-                                                   uri_in, uri_out,
-                                                   flags, dname, bandwidth,
-                                                   dom_xml);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dconn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePrepareTunnel3(virConnectPtr conn,
-                               virStreamPtr st,
-                               const char *cookiein,
-                               int cookieinlen,
-                               char **cookieout,
-                               int *cookieoutlen,
-                               unsigned long flags,
-                               const char *dname,
-                               unsigned long bandwidth,
-                               const char *dom_xml)
-{
-    VIR_DEBUG("conn=%p, stream=%p, cookiein=%p, cookieinlen=%d, cookieout=%p, "
-              "cookieoutlen=%p, flags=%lx, dname=%s, bandwidth=%lu, "
-              "dom_xml=%s",
-              conn, st, cookiein, cookieinlen, cookieout, cookieoutlen, flags,
-              NULLSTR(dname), bandwidth, dom_xml);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn != st->conn) {
-        virReportInvalidArg(conn,
-                            _("conn in %s must match stream connection"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (conn->driver->domainMigratePrepareTunnel3) {
-        int rv = conn->driver->domainMigratePrepareTunnel3(conn, st,
-                                                           cookiein, cookieinlen,
-                                                           cookieout, cookieoutlen,
-                                                           flags, dname,
-                                                           bandwidth, dom_xml);
-        if (rv < 0)
-            goto error;
-        return rv;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePerform3(virDomainPtr domain,
-                         const char *xmlin,
-                         const char *cookiein,
-                         int cookieinlen,
-                         char **cookieout,
-                         int *cookieoutlen,
-                         const char *dconnuri,
-                         const char *uri,
-                         unsigned long flags,
-                         const char *dname,
-                         unsigned long bandwidth)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "xmlin=%s cookiein=%p, cookieinlen=%d, "
-                     "cookieout=%p, cookieoutlen=%p, dconnuri=%s, "
-                     "uri=%s, flags=%lx, dname=%s, bandwidth=%lu",
-                     NULLSTR(xmlin), cookiein, cookieinlen,
-                     cookieout, cookieoutlen, NULLSTR(dconnuri),
-                     NULLSTR(uri), flags, NULLSTR(dname), bandwidth);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigratePerform3) {
-        int ret;
-        ret = conn->driver->domainMigratePerform3(domain, xmlin,
-                                                  cookiein, cookieinlen,
-                                                  cookieout, cookieoutlen,
-                                                  dconnuri, uri,
-                                                  flags, dname, bandwidth);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-virDomainPtr
-virDomainMigrateFinish3(virConnectPtr dconn,
-                        const char *dname,
-                        const char *cookiein,
-                        int cookieinlen,
-                        char **cookieout,
-                        int *cookieoutlen,
-                        const char *dconnuri,
-                        const char *uri,
-                        unsigned long flags,
-                        int cancelled)
-{
-    VIR_DEBUG("dconn=%p, dname=%s, cookiein=%p, cookieinlen=%d, cookieout=%p,"
-              "cookieoutlen=%p, dconnuri=%s, uri=%s, flags=%lx, retcode=%d",
-              dconn, NULLSTR(dname), cookiein, cookieinlen, cookieout,
-              cookieoutlen, NULLSTR(dconnuri), NULLSTR(uri), flags, cancelled);
-
-    virResetLastError();
-
-    virCheckConnectReturn(dconn, NULL);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (dconn->driver->domainMigrateFinish3) {
-        virDomainPtr ret;
-        ret = dconn->driver->domainMigrateFinish3(dconn, dname,
-                                                  cookiein, cookieinlen,
-                                                  cookieout, cookieoutlen,
-                                                  dconnuri, uri, flags,
-                                                  cancelled);
-        if (!ret && !cancelled)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dconn);
-    return NULL;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigrateConfirm3(virDomainPtr domain,
-                         const char *cookiein,
-                         int cookieinlen,
-                         unsigned long flags,
-                         int cancelled)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "cookiein=%p, cookieinlen=%d, flags=%lx, cancelled=%d",
-                     cookiein, cookieinlen, flags, cancelled);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigrateConfirm3) {
-        int ret;
-        ret = conn->driver->domainMigrateConfirm3(domain,
-                                                  cookiein, cookieinlen,
-                                                  flags, cancelled);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-char *
-virDomainMigrateBegin3Params(virDomainPtr domain,
-                             virTypedParameterPtr params,
-                             int nparams,
-                             char **cookieout,
-                             int *cookieoutlen,
-                             unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, "
-                     "cookieout=%p, cookieoutlen=%p, flags=%x",
-                     params, nparams, cookieout, cookieoutlen, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigrateBegin3Params) {
-        char *xml;
-        xml = conn->driver->domainMigrateBegin3Params(domain, params, nparams,
-                                                      cookieout, cookieoutlen,
-                                                      flags);
-        VIR_DEBUG("xml %s", NULLSTR(xml));
-        if (!xml)
-            goto error;
-        return xml;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePrepare3Params(virConnectPtr dconn,
-                               virTypedParameterPtr params,
-                               int nparams,
-                               const char *cookiein,
-                               int cookieinlen,
-                               char **cookieout,
-                               int *cookieoutlen,
-                               char **uri_out,
-                               unsigned int flags)
-{
-    VIR_DEBUG("dconn=%p, params=%p, nparams=%d, cookiein=%p, cookieinlen=%d, "
-              "cookieout=%p, cookieoutlen=%p, uri_out=%p, flags=%x",
-              dconn, params, nparams, cookiein, cookieinlen,
-              cookieout, cookieoutlen, uri_out, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckConnectReturn(dconn, -1);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (dconn->driver->domainMigratePrepare3Params) {
-        int ret;
-        ret = dconn->driver->domainMigratePrepare3Params(dconn, params, nparams,
-                                                         cookiein, cookieinlen,
-                                                         cookieout, cookieoutlen,
-                                                         uri_out, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dconn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePrepareTunnel3Params(virConnectPtr conn,
-                                     virStreamPtr st,
-                                     virTypedParameterPtr params,
-                                     int nparams,
-                                     const char *cookiein,
-                                     int cookieinlen,
-                                     char **cookieout,
-                                     int *cookieoutlen,
-                                     unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, stream=%p, params=%p, nparams=%d, cookiein=%p, "
-              "cookieinlen=%d, cookieout=%p, cookieoutlen=%p, flags=%x",
-              conn, st, params, nparams, cookiein, cookieinlen,
-              cookieout, cookieoutlen, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn != st->conn) {
-        virReportInvalidArg(conn,
-                            _("conn in %s must match stream connection"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (conn->driver->domainMigratePrepareTunnel3Params) {
-        int rv;
-        rv = conn->driver->domainMigratePrepareTunnel3Params(
-                conn, st, params, nparams, cookiein, cookieinlen,
-                cookieout, cookieoutlen, flags);
-        if (rv < 0)
-            goto error;
-        return rv;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigratePerform3Params(virDomainPtr domain,
-                               const char *dconnuri,
-                               virTypedParameterPtr params,
-                               int nparams,
-                               const char *cookiein,
-                               int cookieinlen,
-                               char **cookieout,
-                               int *cookieoutlen,
-                               unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "dconnuri=%s, params=%p, nparams=%d, cookiein=%p, "
-                     "cookieinlen=%d, cookieout=%p, cookieoutlen=%p, flags=%x",
-                     NULLSTR(dconnuri), params, nparams, cookiein,
-                     cookieinlen, cookieout, cookieoutlen, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigratePerform3Params) {
-        int ret;
-        ret = conn->driver->domainMigratePerform3Params(
-                domain, dconnuri, params, nparams, cookiein, cookieinlen,
-                cookieout, cookieoutlen, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-virDomainPtr
-virDomainMigrateFinish3Params(virConnectPtr dconn,
-                              virTypedParameterPtr params,
-                              int nparams,
-                              const char *cookiein,
-                              int cookieinlen,
-                              char **cookieout,
-                              int *cookieoutlen,
-                              unsigned int flags,
-                              int cancelled)
-{
-    VIR_DEBUG("dconn=%p, params=%p, nparams=%d, cookiein=%p, cookieinlen=%d, "
-              "cookieout=%p, cookieoutlen=%p, flags=%x, cancelled=%d",
-              dconn, params, nparams, cookiein, cookieinlen, cookieout,
-              cookieoutlen, flags, cancelled);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckConnectReturn(dconn, NULL);
-    virCheckReadOnlyGoto(dconn->flags, error);
-
-    if (dconn->driver->domainMigrateFinish3Params) {
-        virDomainPtr ret;
-        ret = dconn->driver->domainMigrateFinish3Params(
-                dconn, params, nparams, cookiein, cookieinlen,
-                cookieout, cookieoutlen, flags, cancelled);
-        if (!ret && !cancelled)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dconn);
-    return NULL;
-}
-
-
-/*
- * Not for public use.  This function is part of the internal
- * implementation of migration in the remote case.
- */
-int
-virDomainMigrateConfirm3Params(virDomainPtr domain,
-                               virTypedParameterPtr params,
-                               int nparams,
-                               const char *cookiein,
-                               int cookieinlen,
-                               unsigned int flags,
-                               int cancelled)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, cookiein=%p, "
-                     "cookieinlen=%d, flags=%x, cancelled=%d",
-                     params, nparams, cookiein, cookieinlen, flags, cancelled);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigrateConfirm3Params) {
-        int ret;
-        ret = conn->driver->domainMigrateConfirm3Params(
-                domain, params, nparams,
-                cookiein, cookieinlen, flags, cancelled);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virNodeGetInfo:
- * @conn: pointer to the hypervisor connection
- * @info: pointer to a virNodeInfo structure allocated by the user
- *
- * Extract hardware information about the node.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
-{
-    VIR_DEBUG("conn=%p, info=%p", conn, info);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(info, error);
-
-    if (conn->driver->nodeGetInfo) {
-        int ret;
-        ret = conn->driver->nodeGetInfo(conn, info);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectGetCapabilities:
- * @conn: pointer to the hypervisor connection
- *
- * Provides capabilities of the hypervisor / driver.
- *
- * Returns NULL in case of error, or an XML string
- * defining the capabilities.
- * The client must free the returned string after use.
- */
-char *
-virConnectGetCapabilities(virConnectPtr conn)
-{
-    VIR_DEBUG("conn=%p", conn);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, NULL);
-
-    if (conn->driver->connectGetCapabilities) {
-        char *ret;
-        ret = conn->driver->connectGetCapabilities(conn);
-        if (!ret)
-            goto error;
-        VIR_DEBUG("conn=%p ret=%s", conn, ret);
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return NULL;
-}
-
-
-/**
- * virNodeGetCPUStats:
- * @conn: pointer to the hypervisor connection.
- * @cpuNum: number of node cpu. (VIR_NODE_CPU_STATS_ALL_CPUS means total cpu
- *          statistics)
- * @params: pointer to node cpu time parameter objects
- * @nparams: number of node cpu time parameter (this value should be same or
- *          less than the number of parameters supported)
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * This function provides individual cpu statistics of the node.
- * If you want to get total cpu statistics of the node, you must specify
- * VIR_NODE_CPU_STATS_ALL_CPUS to @cpuNum.
- * The @params array will be filled with the values equal to the number of
- * parameters suggested by @nparams
- *
- * As the value of @nparams is dynamic, call the API setting @nparams to 0 and
- * @params as NULL, the API returns the number of parameters supported by the
- * HV by updating @nparams on SUCCESS. The caller should then allocate @params
- * array, i.e. (sizeof(@virNodeCPUStats) * @nparams) bytes and call
- * the API again.
- *
- * Here is a sample code snippet:
- *
- *   if (virNodeGetCPUStats(conn, cpuNum, NULL, &nparams, 0) == 0 &&
- *       nparams != 0) {
- *       if ((params = malloc(sizeof(virNodeCPUStats) * nparams)) == NULL)
- *           goto error;
- *       memset(params, 0, sizeof(virNodeCPUStats) * nparams);
- *       if (virNodeGetCPUStats(conn, cpuNum, params, &nparams, 0))
- *           goto error;
- *   }
- *
- * This function doesn't require privileged access to the hypervisor.
- * This function expects the caller to allocate the @params.
- *
- * CPU time Statistics:
- *
- * VIR_NODE_CPU_STATS_KERNEL:
- *     The cumulative CPU time which spends by kernel,
- *     when the node booting up.(nanoseconds)
- * VIR_NODE_CPU_STATS_USER:
- *     The cumulative CPU time which spends by user processes,
- *     when the node booting up.(nanoseconds)
- * VIR_NODE_CPU_STATS_IDLE:
- *     The cumulative idle CPU time, when the node booting up.(nanoseconds)
- * VIR_NODE_CPU_STATS_IOWAIT:
- *     The cumulative I/O wait CPU time, when the node booting up.(nanoseconds)
- * VIR_NODE_CPU_STATS_UTILIZATION:
- *     The CPU utilization. The usage value is in percent and 100%
- *     represents all CPUs on the server.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virNodeGetCPUStats(virConnectPtr conn,
-                   int cpuNum,
-                   virNodeCPUStatsPtr params,
-                   int *nparams, unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, cpuNum=%d, params=%p, nparams=%d, flags=%x",
-              conn, cpuNum, params, nparams ? *nparams : -1, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (cpuNum < 0 && cpuNum != VIR_NODE_CPU_STATS_ALL_CPUS) {
-        virReportInvalidArg(cpuNum,
-                            _("cpuNum in %s only accepts %d as a negative "
-                              "value"),
-                            __FUNCTION__, VIR_NODE_CPU_STATS_ALL_CPUS);
-        goto error;
-    }
-
-    if (conn->driver->nodeGetCPUStats) {
-        int ret;
-        ret = conn->driver->nodeGetCPUStats(conn, cpuNum, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virNodeGetMemoryStats:
- * @conn: pointer to the hypervisor connection.
- * @cellNum: number of node cell. (VIR_NODE_MEMORY_STATS_ALL_CELLS means total
- *           cell statistics)
- * @params: pointer to node memory stats objects
- * @nparams: number of node memory stats (this value should be same or
- *          less than the number of stats supported)
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * This function provides memory stats of the node.
- * If you want to get total memory statistics of the node, you must specify
- * VIR_NODE_MEMORY_STATS_ALL_CELLS to @cellNum.
- * The @params array will be filled with the values equal to the number of
- * stats suggested by @nparams
- *
- * As the value of @nparams is dynamic, call the API setting @nparams to 0 and
- * @params as NULL, the API returns the number of parameters supported by the
- * HV by updating @nparams on SUCCESS. The caller should then allocate @params
- * array, i.e. (sizeof(@virNodeMemoryStats) * @nparams) bytes and call
- * the API again.
- *
- * Here is the sample code snippet:
- *
- *   if (virNodeGetMemoryStats(conn, cellNum, NULL, &nparams, 0) == 0 &&
- *       nparams != 0) {
- *       if ((params = malloc(sizeof(virNodeMemoryStats) * nparams)) == NULL)
- *           goto error;
- *       memset(params, cellNum, 0, sizeof(virNodeMemoryStats) * nparams);
- *       if (virNodeGetMemoryStats(conn, params, &nparams, 0))
- *           goto error;
- *   }
- *
- * This function doesn't require privileged access to the hypervisor.
- * This function expects the caller to allocate the @params.
- *
- * Memory Stats:
- *
- * VIR_NODE_MEMORY_STATS_TOTAL:
- *     The total memory usage.(KB)
- * VIR_NODE_MEMORY_STATS_FREE:
- *     The free memory usage.(KB)
- *     On linux, this usage includes buffers and cached.
- * VIR_NODE_MEMORY_STATS_BUFFERS:
- *     The buffers memory usage.(KB)
- * VIR_NODE_MEMORY_STATS_CACHED:
- *     The cached memory usage.(KB)
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virNodeGetMemoryStats(virConnectPtr conn,
-                      int cellNum,
-                      virNodeMemoryStatsPtr params,
-                      int *nparams, unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, cellNum=%d, params=%p, nparams=%d, flags=%x",
-              conn, cellNum, params, nparams ? *nparams : -1, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (cellNum < 0 && cellNum != VIR_NODE_MEMORY_STATS_ALL_CELLS) {
-        virReportInvalidArg(cpuNum,
-                            _("cellNum in %s only accepts %d as a negative "
-                              "value"),
-                            __FUNCTION__, VIR_NODE_MEMORY_STATS_ALL_CELLS);
-        goto error;
-    }
-
-    if (conn->driver->nodeGetMemoryStats) {
-        int ret;
-        ret = conn->driver->nodeGetMemoryStats(conn, cellNum, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virNodeGetFreeMemory:
- * @conn: pointer to the hypervisor connection
- *
- * provides the free memory available on the Node
- * Note: most libvirt APIs provide memory sizes in kibibytes, but in this
- * function the returned value is in bytes. Divide by 1024 as necessary.
- *
- * Returns the available free memory in bytes or 0 in case of error
- */
-unsigned long long
-virNodeGetFreeMemory(virConnectPtr conn)
-{
-    VIR_DEBUG("conn=%p", conn);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, 0);
-
-    if (conn->driver->nodeGetFreeMemory) {
-        unsigned long long ret;
-        ret = conn->driver->nodeGetFreeMemory(conn);
-        if (ret == 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return 0;
-}
-
-
-/**
- * virNodeSuspendForDuration:
- * @conn: pointer to the hypervisor connection
- * @target: the state to which the host must be suspended to,
- *         such as: VIR_NODE_SUSPEND_TARGET_MEM (Suspend-to-RAM)
- *                  VIR_NODE_SUSPEND_TARGET_DISK (Suspend-to-Disk)
- *                  VIR_NODE_SUSPEND_TARGET_HYBRID (Hybrid-Suspend,
- *                  which is a combination of the former modes).
- * @duration: the time duration in seconds for which the host
- *            has to be suspended
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Attempt to suspend the node (host machine) for the given duration of
- * time in the specified state (Suspend-to-RAM, Suspend-to-Disk or
- * Hybrid-Suspend). Schedule the node's Real-Time-Clock interrupt to
- * resume the node after the duration is complete.
- *
- * Returns 0 on success (i.e., the node will be suspended after a short
- * delay), -1 on failure (the operation is not supported, or an attempted
- * suspend is already underway).
- */
-int
-virNodeSuspendForDuration(virConnectPtr conn,
-                          unsigned int target,
-                          unsigned long long duration,
-                          unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, target=%d, duration=%lld, flags=%x",
-              conn, target, duration, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->nodeSuspendForDuration) {
-        int ret;
-        ret = conn->driver->nodeSuspendForDuration(conn, target,
-                                                   duration, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/*
- * virNodeGetMemoryParameters:
- * @conn: pointer to the hypervisor connection
- * @params: pointer to memory parameter object
- *          (return value, allocated by the caller)
- * @nparams: pointer to number of memory parameters; input and output
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Get all node memory parameters (parameters unsupported by OS will be
- * omitted).  On input, @nparams gives the size of the @params array;
- * on output, @nparams gives how many slots were filled with parameter
- * information, which might be less but will not exceed the input value.
- *
- * As a special case, calling with @params as NULL and @nparams as 0 on
- * input will cause @nparams on output to contain the number of parameters
- * supported by the hypervisor. The caller should then allocate @params
- * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
- * again.  See virDomainGetMemoryParameters() for an equivalent usage
- * example.
- *
- * Returns 0 in case of success, and -1 in case of failure.
- */
-int
-virNodeGetMemoryParameters(virConnectPtr conn,
-                           virTypedParameterPtr params,
-                           int *nparams,
-                           unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, params=%p, nparams=%p, flags=%x",
-              conn, params, nparams, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (*nparams != 0)
-        virCheckNonNullArgGoto(params, error);
-
-    if (VIR_DRV_SUPPORTS_FEATURE(conn->driver, conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-
-    if (conn->driver->nodeGetMemoryParameters) {
-        int ret;
-        ret = conn->driver->nodeGetMemoryParameters(conn, params,
-                                                    nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/*
- * virNodeSetMemoryParameters:
- * @conn: pointer to the hypervisor connection
- * @params: pointer to scheduler parameter objects
- * @nparams: number of scheduler parameter objects
- *          (this value can be the same or less than the returned
- *           value nparams of virDomainGetSchedulerType)
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Change all or a subset of the node memory tunables. The function
- * fails if not all of the tunables are supported.
- *
- * Note that it's not recommended to use this function while the
- * outside tuning program is running (such as ksmtuned under Linux),
- * as they could change the tunables in parallel, which could cause
- * conflicts.
- *
- * This function may require privileged access to the hypervisor.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virNodeSetMemoryParameters(virConnectPtr conn,
-                           virTypedParameterPtr params,
-                           int nparams,
-                           unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, params=%p, nparams=%d, flags=%x",
-              conn, params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(params, error);
-    virCheckNonNegativeArgGoto(nparams, error);
-
-    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
-        goto error;
-
-    if (conn->driver->nodeSetMemoryParameters) {
-        int ret;
-        ret = conn->driver->nodeSetMemoryParameters(conn, params,
-                                                          nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetSchedulerType:
- * @domain: pointer to domain object
- * @nparams: pointer to number of scheduler parameters, can be NULL
- *           (return value)
- *
- * Get the scheduler type and the number of scheduler parameters.
- *
- * Returns NULL in case of error. The caller must free the returned string.
- */
-char *
-virDomainGetSchedulerType(virDomainPtr domain, int *nparams)
-{
-    virConnectPtr conn;
-    char *schedtype;
-
-    VIR_DOMAIN_DEBUG(domain, "nparams=%p", nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-    conn = domain->conn;
-
-    if (conn->driver->domainGetSchedulerType) {
-        schedtype = conn->driver->domainGetSchedulerType(domain, nparams);
-        if (!schedtype)
-            goto error;
-        return schedtype;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virDomainGetSchedulerParameters:
- * @domain: pointer to domain object
- * @params: pointer to scheduler parameter objects
- *          (return value)
- * @nparams: pointer to number of scheduler parameter objects
- *          (this value should generally be as large as the returned value
- *           nparams of virDomainGetSchedulerType()); input and output
- *
- * Get all scheduler parameters.  On input, @nparams gives the size of the
- * @params array; on output, @nparams gives how many slots were filled
- * with parameter information, which might be less but will not exceed
- * the input value.  @nparams cannot be 0.
- *
- * It is hypervisor specific whether this returns the live or
- * persistent state; for more control, use
- * virDomainGetSchedulerParametersFlags().
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainGetSchedulerParameters(virDomainPtr domain,
-                                virTypedParameterPtr params, int *nparams)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%p", params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-
-    virCheckNonNullArgGoto(params, error);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckPositiveArgGoto(*nparams, error);
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetSchedulerParameters) {
-        int ret;
-        ret = conn->driver->domainGetSchedulerParameters(domain, params, nparams);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetSchedulerParametersFlags:
- * @domain: pointer to domain object
- * @params: pointer to scheduler parameter object
- *          (return value)
- * @nparams: pointer to number of scheduler parameter
- *          (this value should be same than the returned value
- *           nparams of virDomainGetSchedulerType()); input and output
- * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
- *
- * Get all scheduler parameters.  On input, @nparams gives the size of the
- * @params array; on output, @nparams gives how many slots were filled
- * with parameter information, which might be less but will not exceed
- * the input value.  @nparams cannot be 0.
- *
- * The value of @flags can be exactly VIR_DOMAIN_AFFECT_CURRENT,
- * VIR_DOMAIN_AFFECT_LIVE, or VIR_DOMAIN_AFFECT_CONFIG.
- *
- * Here is a sample code snippet:
- *
- *   char *ret = virDomainGetSchedulerType(dom, &nparams);
- *   if (ret && nparams != 0) {
- *       if ((params = malloc(sizeof(*params) * nparams)) == NULL)
- *           goto error;
- *       memset(params, 0, sizeof(*params) * nparams);
- *       if (virDomainGetSchedulerParametersFlags(dom, params, &nparams, 0))
- *           goto error;
- *   }
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainGetSchedulerParametersFlags(virDomainPtr domain,
-                                     virTypedParameterPtr params, int *nparams,
-                                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%p, flags=%x",
-                     params, nparams, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-
-    virCheckNonNullArgGoto(params, error);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckPositiveArgGoto(*nparams, error);
-
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-
-    /* At most one of these two flags should be set.  */
-    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
-        virReportInvalidArg(flags,
-                            _("flags 'affect live' and 'affect config' in %s "
-                              "are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainGetSchedulerParametersFlags) {
-        int ret;
-        ret = conn->driver->domainGetSchedulerParametersFlags(domain, params,
-                                                              nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetSchedulerParameters:
- * @domain: pointer to domain object
- * @params: pointer to scheduler parameter objects
- * @nparams: number of scheduler parameter objects
- *          (this value can be the same or less than the returned value
- *           nparams of virDomainGetSchedulerType)
- *
- * Change all or a subset or the scheduler parameters.  It is
- * hypervisor-specific whether this sets live, persistent, or both
- * settings; for more control, use
- * virDomainSetSchedulerParametersFlags.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainSetSchedulerParameters(virDomainPtr domain,
-                                virTypedParameterPtr params, int nparams)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d", params, nparams);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(params, error);
-    virCheckNonNegativeArgGoto(nparams, error);
-
-    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
-        goto error;
-
-    if (conn->driver->domainSetSchedulerParameters) {
-        int ret;
-        ret = conn->driver->domainSetSchedulerParameters(domain, params, nparams);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetSchedulerParametersFlags:
- * @domain: pointer to domain object
- * @params: pointer to scheduler parameter objects
- * @nparams: number of scheduler parameter objects
- *          (this value can be the same or less than the returned value
- *           nparams of virDomainGetSchedulerType)
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Change a subset or all scheduler parameters.  The value of @flags
- * should be either VIR_DOMAIN_AFFECT_CURRENT, or a bitwise-or of
- * values from VIR_DOMAIN_AFFECT_LIVE and
- * VIR_DOMAIN_AFFECT_CURRENT, although hypervisors vary in which
- * flags are supported.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainSetSchedulerParametersFlags(virDomainPtr domain,
-                                     virTypedParameterPtr params,
-                                     int nparams,
-                                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "params=%p, nparams=%d, flags=%x",
-                     params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(params, error);
-    virCheckNonNegativeArgGoto(nparams, error);
-
-    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
-        goto error;
-
-    if (conn->driver->domainSetSchedulerParametersFlags) {
-        int ret;
-        ret = conn->driver->domainSetSchedulerParametersFlags(domain,
-                                                              params,
-                                                              nparams,
-                                                              flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockStats:
- * @dom: pointer to the domain object
- * @disk: path to the block device, or device shorthand
- * @stats: block device stats (returned)
- * @size: size of stats structure
- *
- * This function returns block device (disk) stats for block
- * devices attached to the domain.
- *
- * The @disk parameter is either the device target shorthand (the
- * <target dev='...'/> sub-element, such as "vda"), or (since 0.9.8)
- * an unambiguous source name of the block device (the <source
- * file='...'/> sub-element, such as "/path/to/image").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk. Some drivers might also
- * accept the empty string for the @disk parameter, and then yield
- * summary stats for the entire domain.
- *
- * Domains may have more than one block device.  To get stats for
- * each you should make multiple calls to this function.
- *
- * Individual fields within the stats structure may be returned
- * as -1, which indicates that the hypervisor does not support
- * that particular statistic.
- *
- * Returns: 0 in case of success or -1 in case of failure.
- */
-int
-virDomainBlockStats(virDomainPtr dom, const char *disk,
-                    virDomainBlockStatsPtr stats, size_t size)
-{
-    virConnectPtr conn;
-    virDomainBlockStatsStruct stats2 = { -1, -1, -1, -1, -1 };
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, stats=%p, size=%zi", disk, stats, size);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    virCheckNonNullArgGoto(disk, error);
-    virCheckNonNullArgGoto(stats, error);
-    if (size > sizeof(stats2)) {
-        virReportInvalidArg(size,
-                            _("size in %s must not exceed %zu"),
-                            __FUNCTION__, sizeof(stats2));
-        goto error;
-    }
-    conn = dom->conn;
-
-    if (conn->driver->domainBlockStats) {
-        if (conn->driver->domainBlockStats(dom, disk, &stats2) == -1)
-            goto error;
-
-        memcpy(stats, &stats2, size);
-        return 0;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockStatsFlags:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @params: pointer to block stats parameter object
- *          (return value, allocated by the caller)
- * @nparams: pointer to number of block stats; input and output
- * @flags: bitwise-OR of virTypedParameterFlags
- *
- * This function is to get block stats parameters for block
- * devices attached to the domain.
- *
- * The @disk parameter is either the device target shorthand (the
- * <target dev='...'/> sub-element, such as "vda"), or (since 0.9.8)
- * an unambiguous source name of the block device (the <source
- * file='...'/> sub-element, such as "/path/to/image").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk. Some drivers might also
- * accept the empty string for the @disk parameter, and then yield
- * summary stats for the entire domain.
- *
- * Domains may have more than one block device.  To get stats for
- * each you should make multiple calls to this function.
- *
- * On input, @nparams gives the size of the @params array; on output,
- * @nparams gives how many slots were filled with parameter
- * information, which might be less but will not exceed the input
- * value.
- *
- * As a special case, calling with @params as NULL and @nparams as 0 on
- * input will cause @nparams on output to contain the number of parameters
- * supported by the hypervisor. (Note that block devices of different types
- * might support different parameters, so it might be necessary to compute
- * @nparams for each block device). The caller should then allocate @params
- * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
- * again. See virDomainGetMemoryParameters() for more details.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainBlockStatsFlags(virDomainPtr dom,
-                         const char *disk,
-                         virTypedParameterPtr params,
-                         int *nparams,
-                         unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, params=%p, nparams=%d, flags=%x",
-                     disk, params, nparams ? *nparams : -1, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    virCheckNonNullArgGoto(disk, error);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (*nparams != 0)
-        virCheckNonNullArgGoto(params, error);
-
-    if (VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-    conn = dom->conn;
-
-    if (conn->driver->domainBlockStatsFlags) {
-        int ret;
-        ret = conn->driver->domainBlockStatsFlags(dom, disk, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainInterfaceStats:
- * @dom: pointer to the domain object
- * @path: path to the interface
- * @stats: network interface stats (returned)
- * @size: size of stats structure
- *
- * This function returns network interface stats for interfaces
- * attached to the domain.
- *
- * The path parameter is the name of the network interface.
- *
- * Domains may have more than one network interface.  To get stats for
- * each you should make multiple calls to this function.
- *
- * Individual fields within the stats structure may be returned
- * as -1, which indicates that the hypervisor does not support
- * that particular statistic.
- *
- * Returns: 0 in case of success or -1 in case of failure.
- */
-int
-virDomainInterfaceStats(virDomainPtr dom, const char *path,
-                        virDomainInterfaceStatsPtr stats, size_t size)
-{
-    virConnectPtr conn;
-    virDomainInterfaceStatsStruct stats2 = { -1, -1, -1, -1,
-                                             -1, -1, -1, -1 };
-
-    VIR_DOMAIN_DEBUG(dom, "path=%s, stats=%p, size=%zi",
-                     path, stats, size);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    virCheckNonNullArgGoto(path, error);
-    virCheckNonNullArgGoto(stats, error);
-    if (size > sizeof(stats2)) {
-        virReportInvalidArg(size,
-                            _("size in %s must not exceed %zu"),
-                            __FUNCTION__, sizeof(stats2));
-        goto error;
-    }
-
-    conn = dom->conn;
-
-    if (conn->driver->domainInterfaceStats) {
-        if (conn->driver->domainInterfaceStats(dom, path, &stats2) == -1)
-            goto error;
-
-        memcpy(stats, &stats2, size);
-        return 0;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetInterfaceParameters:
- * @domain: pointer to domain object
- * @device: the interface name or mac address
- * @params: pointer to interface parameter objects
- * @nparams: number of interface parameter (this value can be the same or
- *          less than the number of parameters supported)
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Change a subset or all parameters of interface; currently this
- * includes bandwidth parameters.  The value of @flags should be
- * either VIR_DOMAIN_AFFECT_CURRENT, or a bitwise-or of values
- * VIR_DOMAIN_AFFECT_LIVE and VIR_DOMAIN_AFFECT_CONFIG, although
- * hypervisors vary in which flags are supported.
- *
- * This function may require privileged access to the hypervisor.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainSetInterfaceParameters(virDomainPtr domain,
-                                const char *device,
-                                virTypedParameterPtr params,
-                                int nparams, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "device=%s, params=%p, nparams=%d, flags=%x",
-                     device, params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(params, error);
-    virCheckPositiveArgGoto(nparams, error);
-
-    if (virTypedParameterValidateSet(conn, params, nparams) < 0)
-        goto error;
-
-    if (conn->driver->domainSetInterfaceParameters) {
-        int ret;
-        ret = conn->driver->domainSetInterfaceParameters(domain, device,
-                                                         params, nparams,
-                                                         flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetInterfaceParameters:
- * @domain: pointer to domain object
- * @device: the interface name or mac address
- * @params: pointer to interface parameter objects
- *          (return value, allocated by the caller)
- * @nparams: pointer to number of interface parameter; input and output
- * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
- *
- * Get all interface parameters. On input, @nparams gives the size of
- * the @params array; on output, @nparams gives how many slots were
- * filled with parameter information, which might be less but will not
- * exceed the input value.
- *
- * As a special case, calling with @params as NULL and @nparams as 0 on
- * input will cause @nparams on output to contain the number of parameters
- * supported by the hypervisor. The caller should then allocate @params
- * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the
- * API again. See virDomainGetMemoryParameters() for an equivalent usage
- * example.
- *
- * This function may require privileged access to the hypervisor. This function
- * expects the caller to allocate the @params.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainGetInterfaceParameters(virDomainPtr domain,
-                                const char *device,
-                                virTypedParameterPtr params,
-                                int *nparams, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "device=%s, params=%p, nparams=%d, flags=%x",
-                     device, params, (nparams) ? *nparams : -1, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (*nparams != 0)
-        virCheckNonNullArgGoto(params, error);
-
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetInterfaceParameters) {
-        int ret;
-        ret = conn->driver->domainGetInterfaceParameters(domain, device,
-                                                         params, nparams,
-                                                         flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainMemoryStats:
- * @dom: pointer to the domain object
- * @stats: nr_stats-sized array of stat structures (returned)
- * @nr_stats: number of memory statistics requested
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * This function provides memory statistics for the domain.
- *
- * Up to 'nr_stats' elements of 'stats' will be populated with memory statistics
- * from the domain.  Only statistics supported by the domain, the driver, and
- * this version of libvirt will be returned.
- *
- * Memory Statistics:
- *
- * VIR_DOMAIN_MEMORY_STAT_SWAP_IN:
- *     The total amount of data read from swap space (in kb).
- * VIR_DOMAIN_MEMORY_STAT_SWAP_OUT:
- *     The total amount of memory written out to swap space (in kb).
- * VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT:
- *     The number of page faults that required disk IO to service.
- * VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT:
- *     The number of page faults serviced without disk IO.
- * VIR_DOMAIN_MEMORY_STAT_UNUSED:
- *     The amount of memory which is not being used for any purpose (in kb).
- * VIR_DOMAIN_MEMORY_STAT_AVAILABLE:
- *     The total amount of memory available to the domain's OS (in kb).
- * VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON:
- *     Current balloon value (in kb).
- *
- * Returns: The number of stats provided or -1 in case of failure.
- */
-int
-virDomainMemoryStats(virDomainPtr dom, virDomainMemoryStatPtr stats,
-                     unsigned int nr_stats, unsigned int flags)
-{
-    virConnectPtr conn;
-    unsigned long nr_stats_ret = 0;
-
-    VIR_DOMAIN_DEBUG(dom, "stats=%p, nr_stats=%u, flags=%x",
-                     stats, nr_stats, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-
-    if (!stats || nr_stats == 0)
-        return 0;
-
-    if (nr_stats > VIR_DOMAIN_MEMORY_STAT_NR)
-        nr_stats = VIR_DOMAIN_MEMORY_STAT_NR;
-
-    conn = dom->conn;
-    if (conn->driver->domainMemoryStats) {
-        nr_stats_ret = conn->driver->domainMemoryStats(dom, stats, nr_stats,
-                                                       flags);
-        if (nr_stats_ret == -1)
-            goto error;
-        return nr_stats_ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockPeek:
- * @dom: pointer to the domain object
- * @disk: path to the block device, or device shorthand
- * @offset: offset within block device
- * @size: size to read
- * @buffer: return buffer (must be at least size bytes)
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * This function allows you to read the contents of a domain's
- * disk device.
- *
- * Typical uses for this are to determine if the domain has
- * written a Master Boot Record (indicating that the domain
- * has completed installation), or to try to work out the state
- * of the domain's filesystems.
- *
- * (Note that in the local case you might try to open the
- * block device or file directly, but that won't work in the
- * remote case, nor if you don't have sufficient permission.
- * Hence the need for this call).
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or (since 0.9.5) the device target shorthand
- * (the <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * 'offset' and 'size' represent an area which must lie entirely
- * within the device or file.  'size' may be 0 to test if the
- * call would succeed.
- *
- * 'buffer' is the return buffer and must be at least 'size' bytes.
- *
- * NB. The remote driver imposes a 64K byte limit on 'size'.
- * For your program to be able to work reliably over a remote
- * connection you should split large requests to <= 65536 bytes.
- * However, with 0.9.13 this RPC limit has been raised to 1M byte.
- * Starting with version 1.0.6 the RPC limit has been raised again.
- * Now large requests up to 16M byte are supported.
- *
- * Returns: 0 in case of success or -1 in case of failure.
- */
-int
-virDomainBlockPeek(virDomainPtr dom,
-                   const char *disk,
-                   unsigned long long offset /* really 64 bits */,
-                   size_t size,
-                   void *buffer,
-                   unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, offset=%lld, size=%zi, buffer=%p, flags=%x",
-                     disk, offset, size, buffer, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-
-    /* Allow size == 0 as an access test. */
-    if (size > 0)
-        virCheckNonNullArgGoto(buffer, error);
-
-    if (conn->driver->domainBlockPeek) {
-        int ret;
-        ret = conn->driver->domainBlockPeek(dom, disk, offset, size,
-                                            buffer, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockResize:
- * @dom: pointer to the domain object
- * @disk: path to the block image, or shorthand
- * @size: new size of the block image, see below for unit
- * @flags: bitwise-OR of virDomainBlockResizeFlags
- *
- * Resize a block device of domain while the domain is running.  If
- * @flags is 0, then @size is in kibibytes (blocks of 1024 bytes);
- * since 0.9.11, if @flags includes VIR_DOMAIN_BLOCK_RESIZE_BYTES,
- * @size is in bytes instead.  @size is taken directly as the new
- * size.  Depending on the file format, the hypervisor may round up
- * to the next alignment boundary.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or (since 0.9.5) the device target shorthand
- * (the <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * Note that this call may fail if the underlying virtualization hypervisor
- * does not support it; this call requires privileged access to the
- * hypervisor.
- *
- * Returns: 0 in case of success or -1 in case of failure.
- */
-int
-virDomainBlockResize(virDomainPtr dom,
-                     const char *disk,
-                     unsigned long long size,
-                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, size=%llu, flags=%x", disk, size, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-
-    if (conn->driver->domainBlockResize) {
-        int ret;
-        ret = conn->driver->domainBlockResize(dom, disk, size, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainMemoryPeek:
- * @dom: pointer to the domain object
- * @start: start of memory to peek
- * @size: size of memory to peek
- * @buffer: return buffer (must be at least size bytes)
- * @flags: bitwise-OR of virDomainMemoryFlags
- *
- * This function allows you to read the contents of a domain's
- * memory.
- *
- * The memory which is read is controlled by the 'start', 'size'
- * and 'flags' parameters.
- *
- * If 'flags' is VIR_MEMORY_VIRTUAL then the 'start' and 'size'
- * parameters are interpreted as virtual memory addresses for
- * whichever task happens to be running on the domain at the
- * moment.  Although this sounds haphazard it is in fact what
- * you want in order to read Linux kernel state, because it
- * ensures that pointers in the kernel image can be interpreted
- * coherently.
- *
- * 'buffer' is the return buffer and must be at least 'size' bytes.
- * 'size' may be 0 to test if the call would succeed.
- *
- * NB. The remote driver imposes a 64K byte limit on 'size'.
- * For your program to be able to work reliably over a remote
- * connection you should split large requests to <= 65536 bytes.
- * However, with 0.9.13 this RPC limit has been raised to 1M byte.
- * Starting with version 1.0.6 the RPC limit has been raised again.
- * Now large requests up to 16M byte are supported.
- *
- * Returns: 0 in case of success or -1 in case of failure.
- */
-int
-virDomainMemoryPeek(virDomainPtr dom,
-                    unsigned long long start /* really 64 bits */,
-                    size_t size,
-                    void *buffer,
-                    unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "start=%lld, size=%zi, buffer=%p, flags=%x",
-                     start, size, buffer, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    /* Note on access to physical memory: A VIR_MEMORY_PHYSICAL flag is
-     * a possibility.  However it isn't really useful unless the caller
-     * can also access registers, particularly CR3 on x86 in order to
-     * get the Page Table Directory.  Since registers are different on
-     * every architecture, that would imply another call to get the
-     * machine registers.
-     *
-     * The QEMU driver handles VIR_MEMORY_VIRTUAL, mapping it
-     * to the qemu 'memsave' command which does the virtual to physical
-     * mapping inside qemu.
-     *
-     * The QEMU driver also handles VIR_MEMORY_PHYSICAL, mapping it
-     * to the qemu 'pmemsave' command.
-     *
-     * At time of writing there is no Xen driver.  However the Xen
-     * hypervisor only lets you map physical pages from other domains,
-     * and so the Xen driver would have to do the virtual to physical
-     * mapping by chasing 2, 3 or 4-level page tables from the PTD.
-     * There is example code in libxc (xc_translate_foreign_address)
-     * which does this, although we cannot copy this code directly
-     * because of incompatible licensing.
-     */
-
-    /* Exactly one of these two flags must be set.  */
-    if (!(flags & VIR_MEMORY_VIRTUAL) == !(flags & VIR_MEMORY_PHYSICAL)) {
-        virReportInvalidArg(flags,
-                            _("flags in %s must include VIR_MEMORY_VIRTUAL or "
-                              "VIR_MEMORY_PHYSICAL"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    /* Allow size == 0 as an access test. */
-    if (size > 0)
-        virCheckNonNullArgGoto(buffer, error);
-
-    if (conn->driver->domainMemoryPeek) {
-        int ret;
-        ret = conn->driver->domainMemoryPeek(dom, start, size,
-                                             buffer, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetBlockInfo:
- * @domain: a domain object
- * @disk: path to the block device, or device shorthand
- * @info: pointer to a virDomainBlockInfo structure allocated by the user
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Extract information about a domain's block device.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or (since 0.9.5) the device target shorthand
- * (the <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * For QEMU domains, the allocation and physical virDomainBlockInfo
- * values returned will generally be the same, except when using a
- * non raw, block backing device, such as qcow2 for an active domain.
- * When the persistent domain is not active, QEMU will return the
- * default which is the same value for allocation and physical.
- *
- * Active QEMU domains can return an allocation value which is more
- * representative of the currently used blocks by the device compared
- * to the physical size of the device. Applications can use/monitor
- * the allocation value with the understanding that if the domain
- * becomes inactive during an attempt to get the value, the default
- * values will be returned. Thus, the application should check
- * after the call for the domain being inactive if the values are
- * the same. Optionally, the application could be watching for a
- * shutdown event and then ignore any values received afterwards.
- * This can be an issue when a domain is being migrated and the
- * exact timing of the domain being made inactive and check of
- * the allocation value results the default being returned. For
- * a transient domain in the similar situation, this call will return
- * -1 and an error message indicating the "domain is not running".
- *
- * The following is some pseudo code illustrating the call sequence:
- *
- *   ...
- *   virDomainPtr dom;
- *   virDomainBlockInfo info;
- *   char *device;
- *   ...
- *   // Either get a list of all domains or a specific domain
- *   // via a virDomainLookupBy*() call.
- *   //
- *   // It's also required to fill in the device pointer, but that's
- *   // specific to the implementation. For the purposes of this example
- *   // a qcow2 backed device name string would need to be provided.
- *   ...
- *   // If the following call is made on a persistent domain with a
- *   // qcow2 block backed block device, then it's possible the returned
- *   // allocation equals the physical value. In that case, the domain
- *   // that may have been active prior to calling has become inactive,
- *   // such as is the case during a domain migration. Thus once we
- *   // get data returned, check for active domain when the values are
- *   // the same.
- *   if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
- *       goto failure;
- *   if (info.allocation == info.physical) {
- *       // If the domain is no longer active,
- *       // then the defaults are being returned.
- *       if (!virDomainIsActive())
- *               goto ignore_return;
- *   }
- *   // Do something with the allocation and physical values
- *   ...
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainGetBlockInfo(virDomainPtr domain, const char *disk,
-                      virDomainBlockInfoPtr info, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "info=%p, flags=%x", info, flags);
-
-    virResetLastError();
-
-    if (info)
-        memset(info, 0, sizeof(*info));
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(disk, error);
-    virCheckNonNullArgGoto(info, error);
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetBlockInfo) {
-        int ret;
-        ret = conn->driver->domainGetBlockInfo(domain, disk, info, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/************************************************************************
- *									*
- *		Handling of defined but not running domains		*
- *									*
- ************************************************************************/
-
-/**
- * virDomainDefineXML:
- * @conn: pointer to the hypervisor connection
- * @xml: the XML description for the domain, preferably in UTF-8
- *
- * Define a domain, but does not start it.
- * This definition is persistent, until explicitly undefined with
- * virDomainUndefine(). A previous definition for this domain would be
- * overridden if it already exists.
- *
- * Some hypervisors may prevent this operation if there is a current
- * block copy operation on a transient domain with the same id as the
- * domain being defined; in that case, use virDomainBlockJobAbort() to
- * stop the block copy first.
- *
- * virDomainFree should be used to free the resources after the
- * domain object is no longer needed.
- *
- * Returns NULL in case of error, a pointer to the domain otherwise
- */
-virDomainPtr
-virDomainDefineXML(virConnectPtr conn, const char *xml)
-{
-    VIR_DEBUG("conn=%p, xml=%s", conn, xml);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, NULL);
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(xml, error);
-
-    if (conn->driver->domainDefineXML) {
-        virDomainPtr ret;
-        ret = conn->driver->domainDefineXML(conn, xml);
-        if (!ret)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return NULL;
-}
-
-
-/**
- * virDomainUndefine:
- * @domain: pointer to a defined domain
- *
- * Undefine a domain. If the domain is running, it's converted to
- * transient domain, without stopping it. If the domain is inactive,
- * the domain configuration is removed.
- *
- * If the domain has a managed save image (see
- * virDomainHasManagedSaveImage()), or if it is inactive and has any
- * snapshot metadata (see virDomainSnapshotNum()), then the undefine will
- * fail. See virDomainUndefineFlags() for more control.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-virDomainUndefine(virDomainPtr domain)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainUndefine) {
-        int ret;
-        ret = conn->driver->domainUndefine(domain);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainUndefineFlags:
- * @domain: pointer to a defined domain
- * @flags: bitwise-OR of supported virDomainUndefineFlagsValues
- *
- * Undefine a domain. If the domain is running, it's converted to
- * transient domain, without stopping it. If the domain is inactive,
- * the domain configuration is removed.
- *
- * If the domain has a managed save image (see virDomainHasManagedSaveImage()),
- * then including VIR_DOMAIN_UNDEFINE_MANAGED_SAVE in @flags will also remove
- * that file, and omitting the flag will cause the undefine process to fail.
- *
- * If the domain is inactive and has any snapshot metadata (see
- * virDomainSnapshotNum()), then including
- * VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA in @flags will also remove
- * that metadata.  Omitting the flag will cause the undefine of an
- * inactive domain to fail.  Active snapshots will retain snapshot
- * metadata until the (now-transient) domain halts, regardless of
- * whether this flag is present.  On hypervisors where snapshots do
- * not use libvirt metadata, this flag has no effect.
- *
- * If the domain has any nvram specified, then including
- * VIR_DOMAIN_UNDEFINE_NVRAM will also remove that file, and omitting the flag
- * will cause the undefine process to fail.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-virDomainUndefineFlags(virDomainPtr domain,
-                       unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainUndefineFlags) {
-        int ret;
-        ret = conn->driver->domainUndefineFlags(domain, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virConnectNumOfDefinedDomains:
- * @conn: pointer to the hypervisor connection
- *
- * Provides the number of defined but inactive domains.
- *
- * Returns the number of domain found or -1 in case of error
- */
-int
-virConnectNumOfDefinedDomains(virConnectPtr conn)
-{
-    VIR_DEBUG("conn=%p", conn);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-
-    if (conn->driver->connectNumOfDefinedDomains) {
-        int ret;
-        ret = conn->driver->connectNumOfDefinedDomains(conn);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectListDefinedDomains:
- * @conn: pointer to the hypervisor connection
- * @names: pointer to an array to store the names
- * @maxnames: size of the array
- *
- * list the defined but inactive domains, stores the pointers to the names
- * in @names
- *
- * For active domains, see virConnectListDomains().  For more control over
- * the results, see virConnectListAllDomains().
- *
- * Returns the number of names provided in the array or -1 in case of error.
- * Note that this command is inherently racy; a domain can be defined between
- * a call to virConnectNumOfDefinedDomains() and this call; you are only
- * guaranteed that all currently defined domains were listed if the return
- * is less than @maxids.  The client must call free() on each returned name.
- */
-int
-virConnectListDefinedDomains(virConnectPtr conn, char **const names,
-                             int maxnames)
-{
-    VIR_DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(names, error);
-    virCheckNonNegativeArgGoto(maxnames, error);
-
-    if (conn->driver->connectListDefinedDomains) {
-        int ret;
-        ret = conn->driver->connectListDefinedDomains(conn, names, maxnames);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectListAllDomains:
- * @conn: Pointer to the hypervisor connection.
- * @domains: Pointer to a variable to store the array containing domain objects
- *           or NULL if the list is not required (just returns number of guests).
- * @flags: bitwise-OR of virConnectListAllDomainsFlags
- *
- * Collect a possibly-filtered list of all domains, and return an allocated
- * array of information for each.  This API solves the race inherent in
- * virConnectListDomains() and virConnectListDefinedDomains().
- *
- * Normally, all domains are returned; however, @flags can be used to
- * filter the results for a smaller list of targeted domains.  The valid
- * flags are divided into groups, where each group contains bits that
- * describe mutually exclusive attributes of a domain, and where all bits
- * within a group describe all possible domains.  Some hypervisors might
- * reject explicit bits from a group where the hypervisor cannot make a
- * distinction (for example, not all hypervisors can tell whether domains
- * have snapshots).  For a group supported by a given hypervisor, the
- * behavior when no bits of a group are set is identical to the behavior
- * when all bits in that group are set.  When setting bits from more than
- * one group, it is possible to select an impossible combination (such
- * as an inactive transient domain), in that case a hypervisor may return
- * either 0 or an error.
- *
- * The first group of @flags is VIR_CONNECT_LIST_DOMAINS_ACTIVE (online
- * domains) and VIR_CONNECT_LIST_DOMAINS_INACTIVE (offline domains).
- *
- * The next group of @flags is VIR_CONNECT_LIST_DOMAINS_PERSISTENT (defined
- * domains) and VIR_CONNECT_LIST_DOMAINS_TRANSIENT (running but not defined).
- *
- * The next group of @flags covers various domain states:
- * VIR_CONNECT_LIST_DOMAINS_RUNNING, VIR_CONNECT_LIST_DOMAINS_PAUSED,
- * VIR_CONNECT_LIST_DOMAINS_SHUTOFF, and a catch-all for all other states
- * (such as crashed, this catch-all covers the possibility of adding new
- * states).
- *
- * The remaining groups cover boolean attributes commonly asked about
- * domains; they include VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE and
- * VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE, for filtering based on whether
- * a managed save image exists; VIR_CONNECT_LIST_DOMAINS_AUTOSTART and
- * VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART, for filtering based on autostart;
- * VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT and
- * VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT, for filtering based on whether
- * a domain has snapshots.
- *
- * Example of usage:
- *
- *   virDomainPtr *domains;
- *   size_t i;
- *   int ret;
- *   unsigned int flags = VIR_CONNECT_LIST_DOMAINS_RUNNING |
- *                        VIR_CONNECT_LIST_DOMAINS_PERSISTENT;
- *   ret = virConnectListAllDomains(conn, &domains, flags);
- *   if (ret < 0)
- *       error();
- *   for (i = 0; i < ret; i++) {
- *        do_something_with_domain(domains[i]);
- *        //here or in a separate loop if needed
- *        virDomainFree(domains[i]);
- *   }
- *   free(domains);
- *
- * Returns the number of domains found or -1 and sets domains to NULL in case of
- * error.  On success, the array stored into @domains is guaranteed to have an
- * extra allocated element set to NULL but not included in the return count, to
- * make iteration easier. The caller is responsible for calling virDomainFree()
- * on each array element, then calling free() on @domains.
- */
-int
-virConnectListAllDomains(virConnectPtr conn,
-                         virDomainPtr **domains,
-                         unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, domains=%p, flags=%x", conn, domains, flags);
-
-    virResetLastError();
-
-    if (domains)
-        *domains = NULL;
-
-    virCheckConnectReturn(conn, -1);
-
-    if (conn->driver->connectListAllDomains) {
-        int ret;
-        ret = conn->driver->connectListAllDomains(conn, domains, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainCreate:
- * @domain: pointer to a defined domain
- *
- * Launch a defined domain. If the call succeeds the domain moves from the
- * defined to the running domains pools.  The domain will be paused only
- * if restoring from managed state created from a paused domain.  For more
- * control, see virDomainCreateWithFlags().
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-virDomainCreate(virDomainPtr domain)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainCreate) {
-        int ret;
-        ret = conn->driver->domainCreate(domain);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainCreateWithFlags:
- * @domain: pointer to a defined domain
- * @flags: bitwise-OR of supported virDomainCreateFlags
- *
- * Launch a defined domain. If the call succeeds the domain moves from the
- * defined to the running domains pools.
- *
- * If the VIR_DOMAIN_START_PAUSED flag is set, or if the guest domain
- * has a managed save image that requested paused state (see
- * virDomainManagedSave()) the guest domain will be started, but its
- * CPUs will remain paused. The CPUs can later be manually started
- * using virDomainResume().  In all other cases, the guest domain will
- * be running.
- *
- * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
- * domain will be automatically destroyed when the virConnectPtr
- * object is finally released. This will also happen if the
- * client application crashes / loses its connection to the
- * libvirtd daemon. Any domains marked for auto destroy will
- * block attempts at migration, save-to-file, or snapshots.
- *
- * If the VIR_DOMAIN_START_BYPASS_CACHE flag is set, and there is a
- * managed save file for this domain (created by virDomainManagedSave()),
- * then libvirt will attempt to bypass the file system cache while restoring
- * the file, or fail if it cannot do so for the given system; this can allow
- * less pressure on file system cache, but also risks slowing loads from NFS.
- *
- * If the VIR_DOMAIN_START_FORCE_BOOT flag is set, then any managed save
- * file for this domain is discarded, and the domain boots from scratch.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-virDomainCreateWithFlags(virDomainPtr domain, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainCreateWithFlags) {
-        int ret;
-        ret = conn->driver->domainCreateWithFlags(domain, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainCreateWithFiles:
- * @domain: pointer to a defined domain
- * @nfiles: number of file descriptors passed
- * @files: list of file descriptors passed
- * @flags: bitwise-OR of supported virDomainCreateFlags
- *
- * Launch a defined domain. If the call succeeds the domain moves from the
- * defined to the running domains pools.
- *
- * @files provides an array of file descriptors which will be
- * made available to the 'init' process of the guest. The file
- * handles exposed to the guest will be renumbered to start
- * from 3 (ie immediately following stderr). This is only
- * supported for guests which use container based virtualization
- * technology.
- *
- * If the VIR_DOMAIN_START_PAUSED flag is set, or if the guest domain
- * has a managed save image that requested paused state (see
- * virDomainManagedSave()) the guest domain will be started, but its
- * CPUs will remain paused. The CPUs can later be manually started
- * using virDomainResume().  In all other cases, the guest domain will
- * be running.
- *
- * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest
- * domain will be automatically destroyed when the virConnectPtr
- * object is finally released. This will also happen if the
- * client application crashes / loses its connection to the
- * libvirtd daemon. Any domains marked for auto destroy will
- * block attempts at migration, save-to-file, or snapshots.
- *
- * If the VIR_DOMAIN_START_BYPASS_CACHE flag is set, and there is a
- * managed save file for this domain (created by virDomainManagedSave()),
- * then libvirt will attempt to bypass the file system cache while restoring
- * the file, or fail if it cannot do so for the given system; this can allow
- * less pressure on file system cache, but also risks slowing loads from NFS.
- *
- * If the VIR_DOMAIN_START_FORCE_BOOT flag is set, then any managed save
- * file for this domain is discarded, and the domain boots from scratch.
- *
- * Returns 0 in case of success, -1 in case of error
- */
-int
-virDomainCreateWithFiles(virDomainPtr domain, unsigned int nfiles,
-                         int *files, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "nfiles=%u, files=%p, flags=%x",
-                     nfiles, files, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainCreateWithFiles) {
-        int ret;
-        ret = conn->driver->domainCreateWithFiles(domain,
-                                                  nfiles, files,
-                                                  flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetAutostart:
- * @domain: a domain object
- * @autostart: the value returned
- *
- * Provides a boolean value indicating whether the domain
- * configured to be automatically started when the host
- * machine boots.
- *
- * Returns -1 in case of error, 0 in case of success
- */
-int
-virDomainGetAutostart(virDomainPtr domain,
-                      int *autostart)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "autostart=%p", autostart);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(autostart, error);
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetAutostart) {
-        int ret;
-        ret = conn->driver->domainGetAutostart(domain, autostart);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetAutostart:
- * @domain: a domain object
- * @autostart: whether the domain should be automatically started 0 or 1
- *
- * Configure the domain to be automatically started
- * when the host machine boots.
- *
- * Returns -1 in case of error, 0 in case of success
- */
-int
-virDomainSetAutostart(virDomainPtr domain,
-                      int autostart)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "autostart=%d", autostart);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainSetAutostart) {
-        int ret;
-        ret = conn->driver->domainSetAutostart(domain, autostart);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainInjectNMI:
- * @domain: pointer to domain object, or NULL for Domain0
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Send NMI to the guest
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainInjectNMI(virDomainPtr domain, unsigned int flags)
-{
-    virConnectPtr conn;
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainInjectNMI) {
-        int ret;
-        ret = conn->driver->domainInjectNMI(domain, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSendKey:
- * @domain:    pointer to domain object, or NULL for Domain0
- * @codeset:   the code set of keycodes, from virKeycodeSet
- * @holdtime:  the duration (in milliseconds) that the keys will be held
- * @keycodes:  array of keycodes
- * @nkeycodes: number of keycodes, up to VIR_DOMAIN_SEND_KEY_MAX_KEYS
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Send key(s) to the guest.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainSendKey(virDomainPtr domain,
-                 unsigned int codeset,
-                 unsigned int holdtime,
-                 unsigned int *keycodes,
-                 int nkeycodes,
-                 unsigned int flags)
-{
-    virConnectPtr conn;
-    VIR_DOMAIN_DEBUG(domain, "codeset=%u, holdtime=%u, nkeycodes=%u, flags=%x",
-                     codeset, holdtime, nkeycodes, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(keycodes, error);
-    virCheckPositiveArgGoto(nkeycodes, error);
-
-    if (nkeycodes > VIR_DOMAIN_SEND_KEY_MAX_KEYS) {
-        virReportInvalidArg(nkeycodes,
-                            _("nkeycodes in %s must be <= %d"),
-                            __FUNCTION__, VIR_DOMAIN_SEND_KEY_MAX_KEYS);
-        goto error;
-    }
-
-    if (conn->driver->domainSendKey) {
-        int ret;
-        ret = conn->driver->domainSendKey(domain, codeset, holdtime,
-                                          keycodes, nkeycodes, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSendProcessSignal:
- * @domain: pointer to domain object
- * @pid_value: a positive integer process ID, or negative integer process group ID
- * @signum: a signal from the virDomainProcessSignal enum
- * @flags: one of the virDomainProcessSignalFlag values
- *
- * Send a signal to the designated process in the guest
- *
- * The signal numbers must be taken from the virDomainProcessSignal
- * enum. These will be translated to the corresponding signal
- * number for the guest OS, by the guest agent delivering the
- * signal. If there is no mapping from virDomainProcessSignal to
- * the native OS signals, this API will report an error.
- *
- * If @pid_value is an integer greater than zero, it is
- * treated as a process ID. If @pid_value is an integer
- * less than zero, it is treated as a process group ID.
- * All the @pid_value numbers are from the container/guest
- * namespace. The value zero is not valid.
- *
- * Not all hypervisors will support sending signals to
- * arbitrary processes or process groups. If this API is
- * implemented the minimum requirement is to be able to
- * use @pid_value == 1 (i.e. kill init). No other value is
- * required to be supported.
- *
- * If the @signum is VIR_DOMAIN_PROCESS_SIGNAL_NOP then this
- * API will simply report whether the process is running in
- * the container/guest.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainSendProcessSignal(virDomainPtr domain,
-                           long long pid_value,
-                           unsigned int signum,
-                           unsigned int flags)
-{
-    virConnectPtr conn;
-    VIR_DOMAIN_DEBUG(domain, "pid=%lld, signum=%u flags=%x",
-                     pid_value, signum, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonZeroArgGoto(pid_value, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainSendProcessSignal) {
-        int ret;
-        ret = conn->driver->domainSendProcessSignal(domain,
-                                                    pid_value,
-                                                    signum,
-                                                    flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetVcpus:
- * @domain: pointer to domain object, or NULL for Domain0
- * @nvcpus: the new number of virtual CPUs for this domain
- *
- * Dynamically change the number of virtual CPUs used by the domain.
- * Note that this call may fail if the underlying virtualization hypervisor
- * does not support it or if growing the number is arbitrarily limited.
- * This function may require privileged access to the hypervisor.
- *
- * Note that if this call is executed before the guest has finished booting,
- * the guest may fail to process the change.
- *
- * This command only changes the runtime configuration of the domain,
- * so can only be called on an active domain.  It is hypervisor-dependent
- * whether it also affects persistent configuration; for more control,
- * use virDomainSetVcpusFlags().
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "nvcpus=%u", nvcpus);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonZeroArgGoto(nvcpus, error);
-
-    if (conn->driver->domainSetVcpus) {
-        int ret;
-        ret = conn->driver->domainSetVcpus(domain, nvcpus);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetVcpusFlags:
- * @domain: pointer to domain object, or NULL for Domain0
- * @nvcpus: the new number of virtual CPUs for this domain, must be at least 1
- * @flags: bitwise-OR of virDomainVcpuFlags
- *
- * Dynamically change the number of virtual CPUs used by the domain.
- * Note that this call may fail if the underlying virtualization hypervisor
- * does not support it or if growing the number is arbitrarily limited.
- * This function may require privileged access to the hypervisor.
- *
- * @flags may include VIR_DOMAIN_AFFECT_LIVE to affect a running
- * domain (which may fail if domain is not active), or
- * VIR_DOMAIN_AFFECT_CONFIG to affect the next boot via the XML
- * description of the domain.  Both flags may be set.
- * If neither flag is specified (that is, @flags is VIR_DOMAIN_AFFECT_CURRENT),
- * then an inactive domain modifies persistent setup, while an active domain
- * is hypervisor-dependent on whether just live or both live and persistent
- * state is changed.
- *
- * Note that if this call is executed before the guest has finished booting,
- * the guest may fail to process the change.
- *
- * If @flags includes VIR_DOMAIN_VCPU_MAXIMUM, then
- * VIR_DOMAIN_AFFECT_LIVE must be clear, and only the maximum virtual
- * CPU limit is altered; generally, this value must be less than or
- * equal to virConnectGetMaxVcpus().  Otherwise, this call affects the
- * current virtual CPU limit, which must be less than or equal to the
- * maximum limit.
- *
- * If @flags includes VIR_DOMAIN_VCPU_GUEST, then the state of processors is
- * modified inside the guest instead of the hypervisor. This flag can only
- * be used with live guests and is incompatible with VIR_DOMAIN_VCPU_MAXIMUM.
- * The usage of this flag may require a guest agent configured.
- *
- * Not all hypervisors can support all flag combinations.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainSetVcpusFlags(virDomainPtr domain, unsigned int nvcpus,
-                       unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "nvcpus=%u, flags=%x", nvcpus, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckReadOnlyGoto(domain->conn->flags, error);
-
-    if (flags & VIR_DOMAIN_VCPU_GUEST &&
-        flags & VIR_DOMAIN_VCPU_MAXIMUM) {
-        virReportInvalidArg(flags,
-                            _("flags 'VIR_DOMAIN_VCPU_MAXIMUM' and "
-                              "'VIR_DOMAIN_VCPU_GUEST' in '%s' are mutually "
-                              "exclusive"), __FUNCTION__);
-        goto error;
-    }
-
-    virCheckNonZeroArgGoto(nvcpus, error);
-
-    if ((unsigned short) nvcpus != nvcpus) {
-        virReportError(VIR_ERR_OVERFLOW, _("input too large: %u"), nvcpus);
-        goto error;
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainSetVcpusFlags) {
-        int ret;
-        ret = conn->driver->domainSetVcpusFlags(domain, nvcpus, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetVcpusFlags:
- * @domain: pointer to domain object, or NULL for Domain0
- * @flags: bitwise-OR of virDomainVcpuFlags
- *
- * Query the number of virtual CPUs used by the domain.  Note that
- * this call may fail if the underlying virtualization hypervisor does
- * not support it.  This function may require privileged access to the
- * hypervisor.
- *
- * If @flags includes VIR_DOMAIN_AFFECT_LIVE, this will query a
- * running domain (which will fail if domain is not active); if
- * it includes VIR_DOMAIN_AFFECT_CONFIG, this will query the XML
- * description of the domain.  It is an error to set both flags.
- * If neither flag is set (that is, VIR_DOMAIN_AFFECT_CURRENT),
- * then the configuration queried depends on whether the domain
- * is currently running.
- *
- * If @flags includes VIR_DOMAIN_VCPU_MAXIMUM, then the maximum
- * virtual CPU limit is queried.  Otherwise, this call queries the
- * current virtual CPU count.
- *
- * If @flags includes VIR_DOMAIN_VCPU_GUEST, then the state of the processors
- * is queried in the guest instead of the hypervisor. This flag is only usable
- * on live domains. Guest agent may be needed for this flag to be available.
- *
- * Returns the number of vCPUs in case of success, -1 in case of failure.
- */
-int
-virDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    if (flags & VIR_DOMAIN_VCPU_GUEST)
-        virCheckReadOnlyGoto(conn->flags, error);
-
-    /* At most one of these two flags should be set.  */
-    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
-        virReportInvalidArg(flags,
-                            _("flags 'affect live' and 'affect config' in %s "
-                              "are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (conn->driver->domainGetVcpusFlags) {
-        int ret;
-        ret = conn->driver->domainGetVcpusFlags(domain, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainPinVcpu:
- * @domain: pointer to domain object, or NULL for Domain0
- * @vcpu: virtual CPU number
- * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN)
- *      Each bit set to 1 means that corresponding CPU is usable.
- *      Bytes are stored in little-endian order: CPU0-7, 8-15...
- *      In each byte, lowest CPU number is least significant bit.
- * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in
- *      underlying virtualization system (Xen...).
- *      If maplen < size, missing bytes are set to zero.
- *      If maplen > size, failure code is returned.
- *
- * Dynamically change the real CPUs which can be allocated to a virtual CPU.
- * This function may require privileged access to the hypervisor.
- *
- * This command only changes the runtime configuration of the domain,
- * so can only be called on an active domain.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
-                 unsigned char *cpumap, int maplen)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "vcpu=%u, cpumap=%p, maplen=%d",
-                     vcpu, cpumap, maplen);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(cpumap, error);
-    virCheckPositiveArgGoto(maplen, error);
-
-    if ((unsigned short) vcpu != vcpu) {
-        virReportError(VIR_ERR_OVERFLOW, _("input too large: %u"), vcpu);
-        goto error;
-    }
-
-    if (conn->driver->domainPinVcpu) {
-        int ret;
-        ret = conn->driver->domainPinVcpu(domain, vcpu, cpumap, maplen);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainPinVcpuFlags:
- * @domain: pointer to domain object, or NULL for Domain0
- * @vcpu: virtual CPU number
- * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN)
- *      Each bit set to 1 means that corresponding CPU is usable.
- *      Bytes are stored in little-endian order: CPU0-7, 8-15...
- *      In each byte, lowest CPU number is least significant bit.
- * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in
- *      underlying virtualization system (Xen...).
- *      If maplen < size, missing bytes are set to zero.
- *      If maplen > size, failure code is returned.
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Dynamically change the real CPUs which can be allocated to a virtual CPU.
- * This function may require privileged access to the hypervisor.
- *
- * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG.
- * Both flags may be set.
- * If VIR_DOMAIN_AFFECT_LIVE is set, the change affects a running domain
- * and may fail if domain is not alive.
- * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state,
- * and will fail for transient domains. If neither flag is specified (that is,
- * @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain modifies
- * persistent setup, while an active domain is hypervisor-dependent on whether
- * just live or both live and persistent state is changed.
- * Not all hypervisors can support all flag combinations.
- *
- * See also virDomainGetVcpuPinInfo for querying this information.
- *
- * Returns 0 in case of success, -1 in case of failure.
- *
- */
-int
-virDomainPinVcpuFlags(virDomainPtr domain, unsigned int vcpu,
-                      unsigned char *cpumap, int maplen, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "vcpu=%u, cpumap=%p, maplen=%d, flags=%x",
-                     vcpu, cpumap, maplen, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(cpumap, error);
-    virCheckPositiveArgGoto(maplen, error);
-
-    if ((unsigned short) vcpu != vcpu) {
-        virReportError(VIR_ERR_OVERFLOW, _("input too large: %u"), vcpu);
-        goto error;
-    }
-
-    if (conn->driver->domainPinVcpuFlags) {
-        int ret;
-        ret = conn->driver->domainPinVcpuFlags(domain, vcpu, cpumap, maplen, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetVcpuPinInfo:
- * @domain: pointer to domain object, or NULL for Domain0
- * @ncpumaps: the number of cpumap (listed first to match virDomainGetVcpus)
- * @cpumaps: pointer to a bit map of real CPUs for all vcpus of this
- *     domain (in 8-bit bytes) (OUT)
- *     It's assumed there is <ncpumaps> cpumap in cpumaps array.
- *     The memory allocated to cpumaps must be (ncpumaps * maplen) bytes
- *     (ie: calloc(ncpumaps, maplen)).
- *     One cpumap inside cpumaps has the format described in
- *     virDomainPinVcpu() API.
- *     Must not be NULL.
- * @maplen: the number of bytes in one cpumap, from 1 up to size of CPU map.
- *     Must be positive.
- * @flags: bitwise-OR of virDomainModificationImpact
- *     Must not be VIR_DOMAIN_AFFECT_LIVE and
- *     VIR_DOMAIN_AFFECT_CONFIG concurrently.
- *
- * Query the CPU affinity setting of all virtual CPUs of domain, store it
- * in cpumaps.
- *
- * Returns the number of virtual CPUs in case of success,
- * -1 in case of failure.
- */
-int
-virDomainGetVcpuPinInfo(virDomainPtr domain, int ncpumaps,
-                        unsigned char *cpumaps, int maplen, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "ncpumaps=%d, cpumaps=%p, maplen=%d, flags=%x",
-                     ncpumaps, cpumaps, maplen, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(cpumaps, error);
-    virCheckPositiveArgGoto(ncpumaps, error);
-    virCheckPositiveArgGoto(maplen, error);
-
-    if (INT_MULTIPLY_OVERFLOW(ncpumaps, maplen)) {
-        virReportError(VIR_ERR_OVERFLOW, _("input too large: %d * %d"),
-                       ncpumaps, maplen);
-        goto error;
-    }
-
-    /* At most one of these two flags should be set.  */
-    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
-        virReportInvalidArg(flags,
-                            _("flags 'affect live' and 'affect config' in %s "
-                              "are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (conn->driver->domainGetVcpuPinInfo) {
-        int ret;
-        ret = conn->driver->domainGetVcpuPinInfo(domain, ncpumaps,
-                                                 cpumaps, maplen, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainPinEmulator:
- * @domain: pointer to domain object, or NULL for Domain0
- * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes) (IN)
- *      Each bit set to 1 means that corresponding CPU is usable.
- *      Bytes are stored in little-endian order: CPU0-7, 8-15...
- *      In each byte, lowest CPU number is least significant bit.
- * @maplen: number of bytes in cpumap, from 1 up to size of CPU map in
- *      underlying virtualization system (Xen...).
- *      If maplen < size, missing bytes are set to zero.
- *      If maplen > size, failure code is returned.
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Dynamically change the real CPUs which can be allocated to all emulator
- * threads. This function may require privileged access to the hypervisor.
- *
- * @flags may include VIR_DOMAIN_AFFECT_LIVE or VIR_DOMAIN_AFFECT_CONFIG.
- * Both flags may be set.
- * If VIR_DOMAIN_AFFECT_LIVE is set, the change affects a running domain
- * and may fail if domain is not alive.
- * If VIR_DOMAIN_AFFECT_CONFIG is set, the change affects persistent state,
- * and will fail for transient domains. If neither flag is specified (that is,
- * @flags is VIR_DOMAIN_AFFECT_CURRENT), then an inactive domain modifies
- * persistent setup, while an active domain is hypervisor-dependent on whether
- * just live or both live and persistent state is changed.
- * Not all hypervisors can support all flag combinations.
- *
- * See also virDomainGetEmulatorPinInfo for querying this information.
- *
- * Returns 0 in case of success, -1 in case of failure.
- *
- */
-int
-virDomainPinEmulator(virDomainPtr domain, unsigned char *cpumap,
-                     int maplen, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "cpumap=%p, maplen=%d, flags=%x",
-                     cpumap, maplen, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    virCheckNonNullArgGoto(cpumap, error);
-    virCheckPositiveArgGoto(maplen, error);
-
-    if (conn->driver->domainPinEmulator) {
-        int ret;
-        ret = conn->driver->domainPinEmulator(domain, cpumap, maplen, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetEmulatorPinInfo:
- * @domain: pointer to domain object, or NULL for Domain0
- * @cpumap: pointer to a bit map of real CPUs for all emulator threads of
- *     this domain (in 8-bit bytes) (OUT)
- *     There is only one cpumap for all emulator threads.
- *     Must not be NULL.
- * @maplen: the number of bytes in one cpumap, from 1 up to size of CPU map.
- *     Must be positive.
- * @flags: bitwise-OR of virDomainModificationImpact
- *     Must not be VIR_DOMAIN_AFFECT_LIVE and
- *     VIR_DOMAIN_AFFECT_CONFIG concurrently.
- *
- * Query the CPU affinity setting of all emulator threads of domain, store
- * it in cpumap.
- *
- * Returns 1 in case of success,
- * 0 in case of no emulator threads are pined to pcpus,
- * -1 in case of failure.
- */
-int
-virDomainGetEmulatorPinInfo(virDomainPtr domain, unsigned char *cpumap,
-                            int maplen, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "cpumap=%p, maplen=%d, flags=%x",
-                     cpumap, maplen, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-
-    virCheckNonNullArgGoto(cpumap, error);
-    virCheckPositiveArgGoto(maplen, error);
-
-    /* At most one of these two flags should be set.  */
-    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
-        virReportInvalidArg(flags,
-                            _("flags 'affect live' and 'affect config' in %s "
-                              "are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainGetEmulatorPinInfo) {
-        int ret;
-        ret = conn->driver->domainGetEmulatorPinInfo(domain, cpumap,
-                                                     maplen, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetVcpus:
- * @domain: pointer to domain object, or NULL for Domain0
- * @info: pointer to an array of virVcpuInfo structures (OUT)
- * @maxinfo: number of structures in info array
- * @cpumaps: pointer to a bit map of real CPUs for all vcpus of this
- *      domain (in 8-bit bytes) (OUT)
- *      If cpumaps is NULL, then no cpumap information is returned by the API.
- *      It's assumed there is <maxinfo> cpumap in cpumaps array.
- *      The memory allocated to cpumaps must be (maxinfo * maplen) bytes
- *      (ie: calloc(maxinfo, maplen)).
- *      One cpumap inside cpumaps has the format described in
- *      virDomainPinVcpu() API.
- * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
- *      underlying virtualization system (Xen...).
- *      Must be zero when cpumaps is NULL and positive when it is non-NULL.
- *
- * Extract information about virtual CPUs of domain, store it in info array
- * and also in cpumaps if this pointer isn't NULL.  This call may fail
- * on an inactive domain.
- *
- * See also virDomainGetVcpuPinInfo for querying just cpumaps, including on
- * an inactive domain.
- *
- * Returns the number of info filled in case of success, -1 in case of failure.
- */
-int
-virDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
-                  unsigned char *cpumaps, int maplen)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "info=%p, maxinfo=%d, cpumaps=%p, maplen=%d",
-                     info, maxinfo, cpumaps, maplen);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(info, error);
-    virCheckPositiveArgGoto(maxinfo, error);
-
-    /* Ensure that domainGetVcpus (aka remoteDomainGetVcpus) does not
-       try to memcpy anything into a NULL pointer.  */
-    if (cpumaps)
-        virCheckPositiveArgGoto(maplen, error);
-    else
-        virCheckZeroArgGoto(maplen, error);
-
-    if (cpumaps && INT_MULTIPLY_OVERFLOW(maxinfo, maplen)) {
-        virReportError(VIR_ERR_OVERFLOW, _("input too large: %d * %d"),
-                       maxinfo, maplen);
-        goto error;
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetVcpus) {
-        int ret;
-        ret = conn->driver->domainGetVcpus(domain, info, maxinfo,
-                                           cpumaps, maplen);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetMaxVcpus:
- * @domain: pointer to domain object
- *
- * Provides the maximum number of virtual CPUs supported for
- * the guest VM. If the guest is inactive, this is basically
- * the same as virConnectGetMaxVcpus(). If the guest is running
- * this will reflect the maximum number of virtual CPUs the
- * guest was booted with.  For more details, see virDomainGetVcpusFlags().
- *
- * Returns the maximum of virtual CPU or -1 in case of error.
- */
-int
-virDomainGetMaxVcpus(virDomainPtr domain)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    if (conn->driver->domainGetMaxVcpus) {
-        int ret;
-        ret = conn->driver->domainGetMaxVcpus(domain);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetSecurityLabel:
- * @domain: a domain object
- * @seclabel: pointer to a virSecurityLabel structure
- *
- * Extract security label of an active domain. The 'label' field
- * in the @seclabel argument will be initialized to the empty
- * string if the domain is not running under a security model.
- *
- * Returns 0 in case of success, -1 in case of failure
- */
-int
-virDomainGetSecurityLabel(virDomainPtr domain, virSecurityLabelPtr seclabel)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "seclabel=%p", seclabel);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(seclabel, error);
-
-    if (conn->driver->domainGetSecurityLabel) {
-        int ret;
-        ret = conn->driver->domainGetSecurityLabel(domain, seclabel);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetSecurityLabelList:
- * @domain: a domain object
- * @seclabels: will be auto-allocated and filled with domains' security labels.
- * Caller must free memory on return.
- *
- * Extract the security labels of an active domain. The 'label' field
- * in the @seclabels argument will be initialized to the empty
- * string if the domain is not running under a security model.
- *
- * Returns number of elemnets in @seclabels on success, -1 in case of failure.
- */
-int
-virDomainGetSecurityLabelList(virDomainPtr domain,
-                              virSecurityLabelPtr* seclabels)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "seclabels=%p", seclabels);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-
-    virCheckNonNullArgGoto(seclabels, error);
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetSecurityLabelList) {
-        int ret;
-        ret = conn->driver->domainGetSecurityLabelList(domain, seclabels);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-/**
- * virDomainSetMetadata:
- * @domain: a domain object
- * @type: type of metadata, from virDomainMetadataType
- * @metadata: new metadata text
- * @key: XML namespace key, or NULL
- * @uri: XML namespace URI, or NULL
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Sets the appropriate domain element given by @type to the
- * value of @metadata.  A @type of VIR_DOMAIN_METADATA_DESCRIPTION
- * is free-form text; VIR_DOMAIN_METADATA_TITLE is free-form, but no
- * newlines are permitted, and should be short (although the length is
- * not enforced). For these two options @key and @uri are irrelevant and
- * must be set to NULL.
- *
- * For type VIR_DOMAIN_METADATA_ELEMENT @metadata  must be well-formed
- * XML belonging to namespace defined by @uri with local name @key.
- *
- * Passing NULL for @metadata says to remove that element from the
- * domain XML (passing the empty string leaves the element present).
- *
- * The resulting metadata will be present in virDomainGetXMLDesc(),
- * as well as quick access through virDomainGetMetadata().
- *
- * @flags controls whether the live domain, persistent configuration,
- * or both will be modified.
- *
- * Returns 0 on success, -1 in case of failure.
- */
-int
-virDomainSetMetadata(virDomainPtr domain,
-                     int type,
-                     const char *metadata,
-                     const char *key,
-                     const char *uri,
-                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "type=%d, metadata='%s', key='%s', uri='%s', flags=%x",
-                     type, NULLSTR(metadata), NULLSTR(key), NULLSTR(uri),
-                     flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    switch (type) {
-    case VIR_DOMAIN_METADATA_TITLE:
-        if (metadata && strchr(metadata, '\n')) {
-            virReportInvalidArg(metadata,
-                                _("metadata title in %s can't contain "
-                                  "newlines"),
-                                __FUNCTION__);
-            goto error;
-        }
-        /* fallthrough */
-    case VIR_DOMAIN_METADATA_DESCRIPTION:
-        virCheckNullArgGoto(uri, error);
-        virCheckNullArgGoto(key, error);
-        break;
-    case VIR_DOMAIN_METADATA_ELEMENT:
-        virCheckNonNullArgGoto(uri, error);
-        if (metadata)
-            virCheckNonNullArgGoto(key, error);
-        break;
-    default:
-        /* For future expansion */
-        break;
-    }
-
-    if (conn->driver->domainSetMetadata) {
-        int ret;
-        ret = conn->driver->domainSetMetadata(domain, type, metadata, key, uri,
-                                              flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetMetadata:
- * @domain: a domain object
- * @type: type of metadata, from virDomainMetadataType
- * @uri: XML namespace identifier
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Retrieves the appropriate domain element given by @type.
- * If VIR_DOMAIN_METADATA_ELEMENT is requested parameter @uri
- * must be set to the name of the namespace the requested elements
- * belong to, otherwise must be NULL.
- *
- * If an element of the domain XML is not present, the resulting
- * error will be VIR_ERR_NO_DOMAIN_METADATA.  This method forms
- * a shortcut for seeing information from virDomainSetMetadata()
- * without having to go through virDomainGetXMLDesc().
- *
- * @flags controls whether the live domain or persistent
- * configuration will be queried.
- *
- * Returns the metadata string on success (caller must free),
- * or NULL in case of failure.
- */
-char *
-virDomainGetMetadata(virDomainPtr domain,
-                     int type,
-                     const char *uri,
-                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "type=%d, uri='%s', flags=%x",
-                     type, NULLSTR(uri), flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-
-    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
-        virReportInvalidArg(flags,
-                            _("flags 'affect live' and 'affect config' in %s "
-                              "are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    switch (type) {
-    case VIR_DOMAIN_METADATA_TITLE:
-    case VIR_DOMAIN_METADATA_DESCRIPTION:
-        virCheckNullArgGoto(uri, error);
-        break;
-    case VIR_DOMAIN_METADATA_ELEMENT:
-        virCheckNonNullArgGoto(uri, error);
-        break;
-    default:
-        /* For future expansion */
-        break;
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetMetadata) {
-        char *ret;
-        if (!(ret = conn->driver->domainGetMetadata(domain, type, uri, flags)))
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virNodeGetSecurityModel:
- * @conn: a connection object
- * @secmodel: pointer to a virSecurityModel structure
- *
- * Extract the security model of a hypervisor. The 'model' field
- * in the @secmodel argument may be initialized to the empty
- * string if the driver has not activated a security model.
- *
- * Returns 0 in case of success, -1 in case of failure
- */
-int
-virNodeGetSecurityModel(virConnectPtr conn, virSecurityModelPtr secmodel)
-{
-    VIR_DEBUG("conn=%p secmodel=%p", conn, secmodel);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(secmodel, error);
-
-    if (conn->driver->nodeGetSecurityModel) {
-        int ret;
-        ret = conn->driver->nodeGetSecurityModel(conn, secmodel);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainAttachDevice:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of one device
- *
- * Create a virtual device attachment to backend.  This function,
- * having hotplug semantics, is only allowed on an active domain.
- *
- * For compatibility, this method can also be used to change the media
- * in an existing CDROM/Floppy device, however, applications are
- * recommended to use the virDomainUpdateDeviceFlag method instead.
- *
- * Be aware that hotplug changes might not persist across a domain going
- * into S4 state (also known as hibernation) unless you also modify the
- * persistent domain definition.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainAttachDevice(virDomainPtr domain, const char *xml)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "xml=%s", xml);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(xml, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainAttachDevice) {
-       int ret;
-       ret = conn->driver->domainAttachDevice(domain, xml);
-       if (ret < 0)
-          goto error;
-       return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainAttachDeviceFlags:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of one device
- * @flags: bitwise-OR of virDomainDeviceModifyFlags
- *
- * Attach a virtual device to a domain, using the flags parameter
- * to control how the device is attached.  VIR_DOMAIN_AFFECT_CURRENT
- * specifies that the device allocation is made based on current domain
- * state.  VIR_DOMAIN_AFFECT_LIVE specifies that the device shall be
- * allocated to the active domain instance only and is not added to the
- * persisted domain configuration.  VIR_DOMAIN_AFFECT_CONFIG
- * specifies that the device shall be allocated to the persisted domain
- * configuration only.  Note that the target hypervisor must return an
- * error if unable to satisfy flags.  E.g. the hypervisor driver will
- * return failure if LIVE is specified but it only supports modifying the
- * persisted device allocation.
- *
- * For compatibility, this method can also be used to change the media
- * in an existing CDROM/Floppy device, however, applications are
- * recommended to use the virDomainUpdateDeviceFlag method instead.
- *
- * Be aware that hotplug changes might not persist across a domain going
- * into S4 state (also known as hibernation) unless you also modify the
- * persistent domain definition.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainAttachDeviceFlags(virDomainPtr domain,
-                           const char *xml, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "xml=%s, flags=%x", xml, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(xml, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainAttachDeviceFlags) {
-        int ret;
-        ret = conn->driver->domainAttachDeviceFlags(domain, xml, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainDetachDevice:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of one device
- *
- * Destroy a virtual device attachment to backend.  This function,
- * having hot-unplug semantics, is only allowed on an active domain.
- *
- * Be aware that hotplug changes might not persist across a domain going
- * into S4 state (also known as hibernation) unless you also modify the
- * persistent domain definition.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainDetachDevice(virDomainPtr domain, const char *xml)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "xml=%s", xml);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(xml, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainDetachDevice) {
-        int ret;
-        ret = conn->driver->domainDetachDevice(domain, xml);
-         if (ret < 0)
-             goto error;
-         return ret;
-     }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainDetachDeviceFlags:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of one device
- * @flags: bitwise-OR of virDomainDeviceModifyFlags
- *
- * Detach a virtual device from a domain, using the flags parameter
- * to control how the device is detached.  VIR_DOMAIN_AFFECT_CURRENT
- * specifies that the device allocation is removed based on current domain
- * state.  VIR_DOMAIN_AFFECT_LIVE specifies that the device shall be
- * deallocated from the active domain instance only and is not from the
- * persisted domain configuration.  VIR_DOMAIN_AFFECT_CONFIG
- * specifies that the device shall be deallocated from the persisted domain
- * configuration only.  Note that the target hypervisor must return an
- * error if unable to satisfy flags.  E.g. the hypervisor driver will
- * return failure if LIVE is specified but it only supports removing the
- * persisted device allocation.
- *
- * Some hypervisors may prevent this operation if there is a current
- * block copy operation on the device being detached; in that case,
- * use virDomainBlockJobAbort() to stop the block copy first.
- *
- * Beware that depending on the hypervisor and device type, detaching a device
- * from a running domain may be asynchronous. That is, calling
- * virDomainDetachDeviceFlags may just request device removal while the device
- * is actually removed later (in cooperation with a guest OS). Previously,
- * this fact was ignored and the device could have been removed from domain
- * configuration before it was actually removed by the hypervisor causing
- * various failures on subsequent operations. To check whether the device was
- * successfully removed, either recheck domain configuration using
- * virDomainGetXMLDesc() or add handler for VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED
- * event. In case the device is already gone when virDomainDetachDeviceFlags
- * returns, the event is delivered before this API call ends. To help existing
- * clients work better in most cases, this API will try to transform an
- * asynchronous device removal that finishes shortly after the request into
- * a synchronous removal. In other words, this API may wait a bit for the
- * removal to complete in case it was not synchronous.
- *
- * Be aware that hotplug changes might not persist across a domain going
- * into S4 state (also known as hibernation) unless you also modify the
- * persistent domain definition.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainDetachDeviceFlags(virDomainPtr domain,
-                           const char *xml, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "xml=%s, flags=%x", xml, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(xml, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainDetachDeviceFlags) {
-        int ret;
-        ret = conn->driver->domainDetachDeviceFlags(domain, xml, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainUpdateDeviceFlags:
- * @domain: pointer to domain object
- * @xml: pointer to XML description of one device
- * @flags: bitwise-OR of virDomainDeviceModifyFlags
- *
- * Change a virtual device on a domain, using the flags parameter
- * to control how the device is changed.  VIR_DOMAIN_AFFECT_CURRENT
- * specifies that the device change is made based on current domain
- * state.  VIR_DOMAIN_AFFECT_LIVE specifies that the device shall be
- * changed on the active domain instance only and is not added to the
- * persisted domain configuration. VIR_DOMAIN_AFFECT_CONFIG
- * specifies that the device shall be changed on the persisted domain
- * configuration only.  Note that the target hypervisor must return an
- * error if unable to satisfy flags.  E.g. the hypervisor driver will
- * return failure if LIVE is specified but it only supports modifying the
- * persisted device allocation.
- *
- * This method is used for actions such changing CDROM/Floppy device
- * media, altering the graphics configuration such as password,
- * reconfiguring the NIC device backend connectivity, etc.
- *
- * Returns 0 in case of success, -1 in case of failure.
- */
-int
-virDomainUpdateDeviceFlags(virDomainPtr domain,
-                           const char *xml, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "xml=%s, flags=%x", xml, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(xml, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainUpdateDeviceFlags) {
-        int ret;
-        ret = conn->driver->domainUpdateDeviceFlags(domain, xml, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virNodeGetCellsFreeMemory:
- * @conn: pointer to the hypervisor connection
- * @freeMems: pointer to the array of unsigned long long
- * @startCell: index of first cell to return freeMems info on.
- * @maxCells: Maximum number of cells for which freeMems information can
- *            be returned.
- *
- * This call returns the amount of free memory in one or more NUMA cells.
- * The @freeMems array must be allocated by the caller and will be filled
- * with the amount of free memory in bytes for each cell requested,
- * starting with startCell (in freeMems[0]), up to either
- * (startCell + maxCells), or the number of additional cells in the node,
- * whichever is smaller.
- *
- * Returns the number of entries filled in freeMems, or -1 in case of error.
- */
-int
-virNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems,
-                          int startCell, int maxCells)
-{
-    VIR_DEBUG("conn=%p, freeMems=%p, startCell=%d, maxCells=%d",
-          conn, freeMems, startCell, maxCells);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(freeMems, error);
-    virCheckPositiveArgGoto(maxCells, error);
-    virCheckNonNegativeArgGoto(startCell, error);
-
-    if (conn->driver->nodeGetCellsFreeMemory) {
-        int ret;
-        ret = conn->driver->nodeGetCellsFreeMemory(conn, freeMems, startCell, maxCells);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/*
- * Domain Event Notification
- */
-
-/**
- * virConnectDomainEventRegister:
- * @conn: pointer to the connection
- * @cb: callback to the function handling domain events
- * @opaque: opaque data to pass on to the callback
- * @freecb: optional function to deallocate opaque when not used anymore
- *
- * Adds a callback to receive notifications of domain lifecycle events
- * occurring on a connection.  This function requires that an event loop
- * has been previously registered with virEventRegisterImpl() or
- * virEventRegisterDefaultImpl().
- *
- * Use of this method is no longer recommended. Instead applications
- * should try virConnectDomainEventRegisterAny() which has a more flexible
- * API contract.
- *
- * The virDomainPtr object handle passed into the callback upon delivery
- * of an event is only valid for the duration of execution of the callback.
- * If the callback wishes to keep the domain object after the callback returns,
- * it shall take a reference to it, by calling virDomainRef.
- * The reference can be released once the object is no longer required
- * by calling virDomainFree.
- *
- * Returns 0 on success, -1 on failure.  Older versions of some hypervisors
- * sometimes returned a positive number on success, but without any reliable
- * semantics on what that number represents.
- */
-int
-virConnectDomainEventRegister(virConnectPtr conn,
-                              virConnectDomainEventCallback cb,
-                              void *opaque,
-                              virFreeCallback freecb)
-{
-    VIR_DEBUG("conn=%p, cb=%p, opaque=%p, freecb=%p", conn, cb, opaque, freecb);
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(cb, error);
-
-    if (conn->driver && conn->driver->connectDomainEventRegister) {
-        int ret;
-        ret = conn->driver->connectDomainEventRegister(conn, cb, opaque, freecb);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectDomainEventDeregister:
- * @conn: pointer to the connection
- * @cb: callback to the function handling domain events
- *
- * Removes a callback previously registered with the
- * virConnectDomainEventRegister() function.
- *
- * Use of this method is no longer recommended. Instead applications
- * should try virConnectDomainEventDeregisterAny() which has a more flexible
- * API contract
- *
- * Returns 0 on success, -1 on failure.  Older versions of some hypervisors
- * sometimes returned a positive number on success, but without any reliable
- * semantics on what that number represents.
- */
-int
-virConnectDomainEventDeregister(virConnectPtr conn,
-                                virConnectDomainEventCallback cb)
-{
-    VIR_DEBUG("conn=%p, cb=%p", conn, cb);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(cb, error);
-
-    if (conn->driver && conn->driver->connectDomainEventDeregister) {
-        int ret;
-        ret = conn->driver->connectDomainEventDeregister(conn, cb);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainIsActive:
- * @dom: pointer to the domain object
- *
- * Determine if the domain is currently running
- *
- * Returns 1 if running, 0 if inactive, -1 on error
- */
-int
-virDomainIsActive(virDomainPtr dom)
-{
-    VIR_DEBUG("dom=%p", dom);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-
-    if (dom->conn->driver->domainIsActive) {
-        int ret;
-        ret = dom->conn->driver->domainIsActive(dom);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainIsPersistent:
- * @dom: pointer to the domain object
- *
- * Determine if the domain has a persistent configuration
- * which means it will still exist after shutting down
- *
- * Returns 1 if persistent, 0 if transient, -1 on error
- */
-int
-virDomainIsPersistent(virDomainPtr dom)
-{
-    VIR_DOMAIN_DEBUG(dom);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-
-    if (dom->conn->driver->domainIsPersistent) {
-        int ret;
-        ret = dom->conn->driver->domainIsPersistent(dom);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainIsUpdated:
- * @dom: pointer to the domain object
- *
- * Determine if the domain has been updated.
- *
- * Returns 1 if updated, 0 if not, -1 on error
- */
-int
-virDomainIsUpdated(virDomainPtr dom)
-{
-    VIR_DOMAIN_DEBUG(dom);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-
-    if (dom->conn->driver->domainIsUpdated) {
-        int ret;
-        ret = dom->conn->driver->domainIsUpdated(dom);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virConnectIsEncrypted:
- * @conn: pointer to the connection object
- *
- * Determine if the connection to the hypervisor is encrypted
- *
- * Returns 1 if encrypted, 0 if not encrypted, -1 on error
- */
-int
-virConnectIsEncrypted(virConnectPtr conn)
-{
-    VIR_DEBUG("conn=%p", conn);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    if (conn->driver->connectIsEncrypted) {
-        int ret;
-        ret = conn->driver->connectIsEncrypted(conn);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectIsSecure:
- * @conn: pointer to the connection object
- *
- * Determine if the connection to the hypervisor is secure
- *
- * A connection will be classed as secure if it is either
- * encrypted, or running over a channel which is not exposed
- * to eavesdropping (eg a UNIX domain socket, or pipe)
- *
- * Returns 1 if secure, 0 if not secure, -1 on error
- */
-int
-virConnectIsSecure(virConnectPtr conn)
-{
-    VIR_DEBUG("conn=%p", conn);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    if (conn->driver->connectIsSecure) {
-        int ret;
-        ret = conn->driver->connectIsSecure(conn);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectCompareCPU:
- * @conn: virConnect connection
- * @xmlDesc: XML describing the CPU to compare with host CPU
- * @flags: bitwise-OR of virConnectCompareCPUFlags
- *
- * Compares the given CPU description with the host CPU
- *
- * Returns comparison result according to enum virCPUCompareResult. If
- * VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE is used and @xmlDesc CPU is
- * incompatible with host CPU, this function will return VIR_CPU_COMPARE_ERROR
- * (instead of VIR_CPU_COMPARE_INCOMPATIBLE) and the error will use the
- * VIR_ERR_CPU_INCOMPATIBLE code with a message providing more details about
- * the incompatibility.
- */
-int
-virConnectCompareCPU(virConnectPtr conn,
-                     const char *xmlDesc,
-                     unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, xmlDesc=%s, flags=%x", conn, xmlDesc, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, VIR_CPU_COMPARE_ERROR);
-    virCheckNonNullArgGoto(xmlDesc, error);
-
-    if (conn->driver->connectCompareCPU) {
-        int ret;
-
-        ret = conn->driver->connectCompareCPU(conn, xmlDesc, flags);
-        if (ret == VIR_CPU_COMPARE_ERROR)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return VIR_CPU_COMPARE_ERROR;
-}
-
-
-/**
- * virConnectGetCPUModelNames:
- *
- * @conn: virConnect connection
- * @arch: Architecture
- * @models: Pointer to a variable to store the NULL-terminated array of the
- *          CPU models supported for the specified architecture.  Each element
- *          and the array itself must be freed by the caller with free.  Pass
- *          NULL if only the list length is needed.
- * @flags: extra flags; not used yet, so callers should always pass 0.
- *
- * Get the list of supported CPU models for a specific architecture.
- *
- * Returns -1 on error, number of elements in @models on success.
- */
-int
-virConnectGetCPUModelNames(virConnectPtr conn, const char *arch, char ***models,
-                           unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, arch=%s, models=%p, flags=%x",
-              conn, arch, models, flags);
-    virResetLastError();
-
-    if (models)
-        *models = NULL;
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(arch, error);
-
-    if (conn->driver->connectGetCPUModelNames) {
-        int ret;
-
-        ret = conn->driver->connectGetCPUModelNames(conn, arch, models, flags);
-        if (ret < 0)
-            goto error;
-
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectBaselineCPU:
- *
- * @conn: virConnect connection
- * @xmlCPUs: array of XML descriptions of host CPUs
- * @ncpus: number of CPUs in xmlCPUs
- * @flags: bitwise-OR of virConnectBaselineCPUFlags
- *
- * Computes the most feature-rich CPU which is compatible with all given
- * host CPUs.
- *
- * If @flags includes VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES then libvirt
- * will explicitly list all CPU features that are part of the host CPU,
- * without this flag features that are part of the CPU model will not be
- * listed.
- *
- * Returns XML description of the computed CPU (caller frees) or NULL on error.
- */
-char *
-virConnectBaselineCPU(virConnectPtr conn,
-                      const char **xmlCPUs,
-                      unsigned int ncpus,
-                      unsigned int flags)
-{
-    size_t i;
-
-    VIR_DEBUG("conn=%p, xmlCPUs=%p, ncpus=%u, flags=%x",
-              conn, xmlCPUs, ncpus, flags);
-    if (xmlCPUs) {
-        for (i = 0; i < ncpus; i++)
-            VIR_DEBUG("xmlCPUs[%zu]=%s", i, NULLSTR(xmlCPUs[i]));
-    }
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, NULL);
-    virCheckNonNullArgGoto(xmlCPUs, error);
-
-    if (conn->driver->connectBaselineCPU) {
-        char *cpu;
-
-        cpu = conn->driver->connectBaselineCPU(conn, xmlCPUs, ncpus, flags);
-        if (!cpu)
-            goto error;
-        return cpu;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return NULL;
-}
-
-
-/**
- * virDomainGetJobInfo:
- * @domain: a domain object
- * @info: pointer to a virDomainJobInfo structure allocated by the user
- *
- * Extract information about progress of a background job on a domain.
- * Will return an error if the domain is not active.
- *
- * This function returns a limited amount of information in comparison
- * to virDomainGetJobStats().
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainGetJobInfo(virDomainPtr domain, virDomainJobInfoPtr info)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "info=%p", info);
-
-    virResetLastError();
-
-    if (info)
-        memset(info, 0, sizeof(*info));
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(info, error);
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetJobInfo) {
-        int ret;
-        ret = conn->driver->domainGetJobInfo(domain, info);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetJobStats:
- * @domain: a domain object
- * @type: where to store the job type (one of virDomainJobType)
- * @params: where to store job statistics
- * @nparams: number of items in @params
- * @flags: bitwise-OR of virDomainGetJobStatsFlags
- *
- * Extract information about progress of a background job on a domain.
- * Will return an error if the domain is not active. The function returns
- * a superset of progress information provided by virDomainGetJobInfo.
- * Possible fields returned in @params are defined by VIR_DOMAIN_JOB_*
- * macros and new fields will likely be introduced in the future so callers
- * may receive fields that they do not understand in case they talk to a
- * newer server.
- *
- * When @flags contains VIR_DOMAIN_JOB_STATS_COMPLETED, the function will
- * return statistics about a recently completed job. Specifically, this
- * flag may be used to query statistics of a completed incoming migration.
- * Statistics of a completed job are automatically destroyed once read or
- * when libvirtd is restarted. Note that time information returned for
- * completed migrations may be completely irrelevant unless both source and
- * destination hosts have synchronized time (i.e., NTP daemon is running on
- * both of them).
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainGetJobStats(virDomainPtr domain,
-                     int *type,
-                     virTypedParameterPtr *params,
-                     int *nparams,
-                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "type=%p, params=%p, nparams=%p, flags=%x",
-                     type, params, nparams, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    virCheckNonNullArgGoto(type, error);
-    virCheckNonNullArgGoto(params, error);
-    virCheckNonNullArgGoto(nparams, error);
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetJobStats) {
-        int ret;
-        ret = conn->driver->domainGetJobStats(domain, type, params,
-                                              nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainAbortJob:
- * @domain: a domain object
- *
- * Requests that the current background job be aborted at the
- * soonest opportunity.
- *
- * Returns 0 in case of success and -1 in case of failure.
- */
-int
-virDomainAbortJob(virDomainPtr domain)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainAbortJob) {
-        int ret;
-        ret = conn->driver->domainAbortJob(domain);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainMigrateSetMaxDowntime:
- * @domain: a domain object
- * @downtime: maximum tolerable downtime for live migration, in milliseconds
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Sets maximum tolerable time for which the domain is allowed to be paused
- * at the end of live migration. It's supposed to be called while the domain is
- * being live-migrated as a reaction to migration progress.
- *
- * Returns 0 in case of success, -1 otherwise.
- */
-int
-virDomainMigrateSetMaxDowntime(virDomainPtr domain,
-                               unsigned long long downtime,
-                               unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "downtime=%llu, flags=%x", downtime, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigrateSetMaxDowntime) {
-        if (conn->driver->domainMigrateSetMaxDowntime(domain, downtime, flags) < 0)
-            goto error;
-        return 0;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainMigrateGetCompressionCache:
- * @domain: a domain object
- * @cacheSize: return value of current size of the cache (in bytes)
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Gets current size of the cache (in bytes) used for compressing repeatedly
- * transferred memory pages during live migration.
- *
- * Returns 0 in case of success, -1 otherwise.
- */
-int
-virDomainMigrateGetCompressionCache(virDomainPtr domain,
-                                    unsigned long long *cacheSize,
-                                    unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "cacheSize=%p, flags=%x", cacheSize, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(cacheSize, error);
-
-    if (conn->driver->domainMigrateGetCompressionCache) {
-        if (conn->driver->domainMigrateGetCompressionCache(domain, cacheSize,
-                                                           flags) < 0)
-            goto error;
-        return 0;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainMigrateSetCompressionCache:
- * @domain: a domain object
- * @cacheSize: size of the cache (in bytes) used for compression
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Sets size of the cache (in bytes) used for compressing repeatedly
- * transferred memory pages during live migration. It's supposed to be called
- * while the domain is being live-migrated as a reaction to migration progress
- * and increasing number of compression cache misses obtained from
- * virDomainGetJobStats.
- *
- * Returns 0 in case of success, -1 otherwise.
- */
-int
-virDomainMigrateSetCompressionCache(virDomainPtr domain,
-                                    unsigned long long cacheSize,
-                                    unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "cacheSize=%llu, flags=%x", cacheSize, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigrateSetCompressionCache) {
-        if (conn->driver->domainMigrateSetCompressionCache(domain, cacheSize,
-                                                           flags) < 0)
-            goto error;
-        return 0;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainMigrateSetMaxSpeed:
- * @domain: a domain object
- * @bandwidth: migration bandwidth limit in MiB/s
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * The maximum bandwidth (in MiB/s) that will be used to do migration
- * can be specified with the bandwidth parameter. Not all hypervisors
- * will support a bandwidth cap
- *
- * Returns 0 in case of success, -1 otherwise.
- */
-int
-virDomainMigrateSetMaxSpeed(virDomainPtr domain,
-                            unsigned long bandwidth,
-                            unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "bandwidth=%lu, flags=%x", bandwidth, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigrateSetMaxSpeed) {
-        if (conn->driver->domainMigrateSetMaxSpeed(domain, bandwidth, flags) < 0)
-            goto error;
-        return 0;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainMigrateGetMaxSpeed:
- * @domain: a domain object
- * @bandwidth: return value of current migration bandwidth limit in MiB/s
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Get the current maximum bandwidth (in MiB/s) that will be used if the
- * domain is migrated.  Not all hypervisors will support a bandwidth limit.
- *
- * Returns 0 in case of success, -1 otherwise.
- */
-int
-virDomainMigrateGetMaxSpeed(virDomainPtr domain,
-                            unsigned long *bandwidth,
-                            unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "bandwidth = %p, flags=%x", bandwidth, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    virCheckNonNullArgGoto(bandwidth, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainMigrateGetMaxSpeed) {
-        if (conn->driver->domainMigrateGetMaxSpeed(domain, bandwidth, flags) < 0)
-            goto error;
-        return 0;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectDomainEventRegisterAny:
- * @conn: pointer to the connection
- * @dom: pointer to the domain
- * @eventID: the event type to receive
- * @cb: callback to the function handling domain events
- * @opaque: opaque data to pass on to the callback
- * @freecb: optional function to deallocate opaque when not used anymore
- *
- * Adds a callback to receive notifications of arbitrary domain events
- * occurring on a domain.  This function requires that an event loop
- * has been previously registered with virEventRegisterImpl() or
- * virEventRegisterDefaultImpl().
- *
- * If @dom is NULL, then events will be monitored for any domain. If @dom
- * is non-NULL, then only the specific domain will be monitored.
- *
- * Most types of event have a callback providing a custom set of parameters
- * for the event. When registering an event, it is thus necessary to use
- * the VIR_DOMAIN_EVENT_CALLBACK() macro to cast the supplied function pointer
- * to match the signature of this method.
- *
- * The virDomainPtr object handle passed into the callback upon delivery
- * of an event is only valid for the duration of execution of the callback.
- * If the callback wishes to keep the domain object after the callback returns,
- * it shall take a reference to it, by calling virDomainRef().
- * The reference can be released once the object is no longer required
- * by calling virDomainFree().
- *
- * The return value from this method is a positive integer identifier
- * for the callback. To unregister a callback, this callback ID should
- * be passed to the virConnectDomainEventDeregisterAny() method.
- *
- * Returns a callback identifier on success, -1 on failure.
- */
-int
-virConnectDomainEventRegisterAny(virConnectPtr conn,
-                                 virDomainPtr dom,
-                                 int eventID,
-                                 virConnectDomainEventGenericCallback cb,
-                                 void *opaque,
-                                 virFreeCallback freecb)
-{
-    VIR_DOMAIN_DEBUG(dom, "conn=%p, eventID=%d, cb=%p, opaque=%p, freecb=%p",
-                     conn, eventID, cb, opaque, freecb);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    if (dom) {
-        virCheckDomainGoto(dom, error);
-        if (dom->conn != conn) {
-            virReportInvalidArg(dom,
-                                _("domain '%s' in %s must match connection"),
-                                dom->name, __FUNCTION__);
-            goto error;
-        }
-    }
-    virCheckNonNullArgGoto(cb, error);
-    virCheckNonNegativeArgGoto(eventID, error);
-    if (eventID >= VIR_DOMAIN_EVENT_ID_LAST) {
-        virReportInvalidArg(eventID,
-                            _("eventID in %s must be less than %d"),
-                            __FUNCTION__, VIR_DOMAIN_EVENT_ID_LAST);
-        goto error;
-    }
-
-    if (conn->driver && conn->driver->connectDomainEventRegisterAny) {
-        int ret;
-        ret = conn->driver->connectDomainEventRegisterAny(conn, dom, eventID, cb, opaque, freecb);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectDomainEventDeregisterAny:
- * @conn: pointer to the connection
- * @callbackID: the callback identifier
- *
- * Removes an event callback. The callbackID parameter should be the
- * value obtained from a previous virConnectDomainEventRegisterAny() method.
- *
- * Returns 0 on success, -1 on failure.  Older versions of some hypervisors
- * sometimes returned a positive number on success, but without any reliable
- * semantics on what that number represents. */
-int
-virConnectDomainEventDeregisterAny(virConnectPtr conn,
-                                   int callbackID)
-{
-    VIR_DEBUG("conn=%p, callbackID=%d", conn, callbackID);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNegativeArgGoto(callbackID, error);
-
-    if (conn->driver && conn->driver->connectDomainEventDeregisterAny) {
-        int ret;
-        ret = conn->driver->connectDomainEventDeregisterAny(conn, callbackID);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainManagedSave:
- * @dom: pointer to the domain
- * @flags: bitwise-OR of virDomainSaveRestoreFlags
- *
- * This method will suspend a domain and save its memory contents to
- * a file on disk. After the call, if successful, the domain is not
- * listed as running anymore.
- * The difference from virDomainSave() is that libvirt is keeping track of
- * the saved state itself, and will reuse it once the domain is being
- * restarted (automatically or via an explicit libvirt call).
- * As a result any running domain is sure to not have a managed saved image.
- * This also implies that managed save only works on persistent domains,
- * since the domain must still exist in order to use virDomainCreate() to
- * restart it.
- *
- * If @flags includes VIR_DOMAIN_SAVE_BYPASS_CACHE, then libvirt will
- * attempt to bypass the file system cache while creating the file, or
- * fail if it cannot do so for the given system; this can allow less
- * pressure on file system cache, but also risks slowing saves to NFS.
- *
- * Normally, the managed saved state will remember whether the domain
- * was running or paused, and start will resume to the same state.
- * Specifying VIR_DOMAIN_SAVE_RUNNING or VIR_DOMAIN_SAVE_PAUSED in
- * @flags will override the default saved into the file.  These two
- * flags are mutually exclusive.
- *
- * Returns 0 in case of success or -1 in case of failure
- */
-int
-virDomainManagedSave(virDomainPtr dom, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if ((flags & VIR_DOMAIN_SAVE_RUNNING) && (flags & VIR_DOMAIN_SAVE_PAUSED)) {
-        virReportInvalidArg(flags,
-                            _("running and paused flags in %s are mutually "
-                              "exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (conn->driver->domainManagedSave) {
-        int ret;
-
-        ret = conn->driver->domainManagedSave(dom, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainHasManagedSaveImage:
- * @dom: pointer to the domain
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Check if a domain has a managed save image as created by
- * virDomainManagedSave(). Note that any running domain should not have
- * such an image, as it should have been removed on restart.
- *
- * Returns 0 if no image is present, 1 if an image is present, and
- *         -1 in case of error
- */
-int
-virDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    if (conn->driver->domainHasManagedSaveImage) {
-        int ret;
-
-        ret = conn->driver->domainHasManagedSaveImage(dom, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainManagedSaveRemove:
- * @dom: pointer to the domain
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Remove any managed save image for this domain.
- *
- * Returns 0 in case of success, and -1 in case of error
- */
-int
-virDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn->driver->domainManagedSaveRemove) {
-        int ret;
-
-        ret = conn->driver->domainManagedSaveRemove(dom, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-
-/**
- * virDomainOpenConsole:
- * @dom: a domain object
- * @dev_name: the console, serial or parallel port device alias, or NULL
- * @st: a stream to associate with the console
- * @flags: bitwise-OR of virDomainConsoleFlags
- *
- * This opens the backend associated with a console, serial or
- * parallel port device on a guest, if the backend is supported.
- * If the @dev_name is omitted, then the first console or serial
- * device is opened. The console is associated with the passed
- * in @st stream, which should have been opened in non-blocking
- * mode for bi-directional I/O.
- *
- * By default, when @flags is 0, the open will fail if libvirt
- * detects that the console is already in use by another client;
- * passing VIR_DOMAIN_CONSOLE_FORCE will cause libvirt to forcefully
- * remove the other client prior to opening this console.
- *
- * If flag VIR_DOMAIN_CONSOLE_SAFE the console is opened only in the
- * case where the hypervisor driver supports safe (mutually exclusive)
- * console handling.
- *
- * Older servers did not support either flag, and also did not forbid
- * simultaneous clients on a console, with potentially confusing results.
- * When passing @flags of 0 in order to support a wider range of server
- * versions, it is up to the client to ensure mutual exclusion.
- *
- * Returns 0 if the console was opened, -1 on error
- */
-int
-virDomainOpenConsole(virDomainPtr dom,
-                     const char *dev_name,
-                     virStreamPtr st,
-                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "dev_name=%s, st=%p, flags=%x",
-                     NULLSTR(dev_name), st, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckStreamGoto(st, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn != st->conn) {
-        virReportInvalidArg(st,
-                            _("stream in %s must match connection of domain '%s'"),
-                            __FUNCTION__, dom->name);
-        goto error;
-    }
-
-    if (conn->driver->domainOpenConsole) {
-        int ret;
-        ret = conn->driver->domainOpenConsole(dom, dev_name, st, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainOpenChannel:
- * @dom: a domain object
- * @name: the channel name, or NULL
- * @st: a stream to associate with the channel
- * @flags: bitwise-OR of virDomainChannelFlags
- *
- * This opens the host interface associated with a channel device on a
- * guest, if the host interface is supported.  If @name is given, it
- * can match either the device alias (e.g. "channel0"), or the virtio
- * target name (e.g. "org.qemu.guest_agent.0").  If @name is omitted,
- * then the first channel is opened. The channel is associated with
- * the passed in @st stream, which should have been opened in
- * non-blocking mode for bi-directional I/O.
- *
- * By default, when @flags is 0, the open will fail if libvirt detects
- * that the channel is already in use by another client; passing
- * VIR_DOMAIN_CHANNEL_FORCE will cause libvirt to forcefully remove the
- * other client prior to opening this channel.
- *
- * Returns 0 if the channel was opened, -1 on error
- */
-int
-virDomainOpenChannel(virDomainPtr dom,
-                     const char *name,
-                     virStreamPtr st,
-                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "name=%s, st=%p, flags=%x",
-                     NULLSTR(name), st, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckStreamGoto(st, error);
-    virCheckReadOnlyGoto(conn->flags, error);
-
-    if (conn != st->conn) {
-        virReportInvalidArg(st,
-                            _("stream in %s must match connection of domain '%s'"),
-                            __FUNCTION__, dom->name);
-        goto error;
-    }
-
-    if (conn->driver->domainOpenChannel) {
-        int ret;
-        ret = conn->driver->domainOpenChannel(dom, name, st, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockJobAbort:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @flags: bitwise-OR of virDomainBlockJobAbortFlags
- *
- * Cancel the active block job on the given disk.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or (since 0.9.5) the device target shorthand
- * (the <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * If the current block job for @disk is VIR_DOMAIN_BLOCK_JOB_TYPE_PULL, then
- * by default, this function performs a synchronous operation and the caller
- * may assume that the operation has completed when 0 is returned.  However,
- * BlockJob operations may take a long time to cancel, and during this time
- * further domain interactions may be unresponsive.  To avoid this problem,
- * pass VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC in the @flags argument to enable
- * asynchronous behavior, returning as soon as possible.  When the job has
- * been canceled, a BlockJob event will be emitted, with status
- * VIR_DOMAIN_BLOCK_JOB_CANCELED (even if the ABORT_ASYNC flag was not
- * used); it is also possible to poll virDomainBlockJobInfo() to see if
- * the job cancellation is still pending.  This type of job can be restarted
- * to pick up from where it left off.
- *
- * If the current block job for @disk is VIR_DOMAIN_BLOCK_JOB_TYPE_COPY, then
- * the default is to abort the mirroring and revert to the source disk;
- * likewise, if the current job is VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT,
- * the default is to abort without changing the active layer of @disk.
- * Adding @flags of VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT causes this call to
- * fail with VIR_ERR_BLOCK_COPY_ACTIVE if the copy or commit is not yet
- * ready; otherwise it will swap the disk over to the new active image
- * to end the mirroring or active commit.  An event will be issued when the
- * job is ended, and it is possible to use VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC
- * to control whether this command waits for the completion of the job.
- * Restarting a copy or active commit job requires starting over from the
- * beginning of the first phase.
- *
- * Returns -1 in case of failure, 0 when successful.
- */
-int
-virDomainBlockJobAbort(virDomainPtr dom, const char *disk,
-                       unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, flags=%x", disk, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-
-    if (conn->driver->domainBlockJobAbort) {
-        int ret;
-        ret = conn->driver->domainBlockJobAbort(dom, disk, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetBlockJobInfo:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @info: pointer to a virDomainBlockJobInfo structure
- * @flags: bitwise-OR of virDomainBlockJobInfoFlags
- *
- * Request block job information for the given disk.  If an operation is active
- * @info will be updated with the current progress.  The units used for the
- * bandwidth field of @info depends on @flags.  If @flags includes
- * VIR_DOMAIN_BLOCK_JOB_INFO_BANDWIDTH_BYTES, bandwidth is in bytes/second
- * (although this mode can risk failure due to overflow, depending on both
- * client and server word size); otherwise, the value is rounded up to MiB/s.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or (since 0.9.5) the device target shorthand
- * (the <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * Returns -1 in case of failure, 0 when nothing found, 1 when info was found.
- */
-int
-virDomainGetBlockJobInfo(virDomainPtr dom, const char *disk,
-                         virDomainBlockJobInfoPtr info, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, info=%p, flags=%x", disk, info, flags);
-
-    virResetLastError();
-
-    if (info)
-        memset(info, 0, sizeof(*info));
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckNonNullArgGoto(disk, error);
-    virCheckNonNullArgGoto(info, error);
-
-    if (conn->driver->domainGetBlockJobInfo) {
-        int ret;
-        ret = conn->driver->domainGetBlockJobInfo(dom, disk, info, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockJobSetSpeed:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @bandwidth: specify bandwidth limit; flags determine the unit
- * @flags: bitwise-OR of virDomainBlockJobSetSpeedFlags
- *
- * Set the maximimum allowable bandwidth that a block job may consume.  If
- * bandwidth is 0, the limit will revert to the hypervisor default of
- * unlimited.
- *
- * If @flags contains VIR_DOMAIN_BLOCK_JOB_SPEED_BANDWIDTH_BYTES, @bandwidth
- * is in bytes/second; otherwise, it is in MiB/second.  Values larger than
- * 2^52 bytes/sec may be rejected due to overflow considerations based on
- * the word size of both client and server, and values larger than 2^31
- * bytes/sec may cause overflow problems if later queried by
- * virDomainGetBlockJobInfo() without scaling.  Hypervisors may further
- * restrict the range of valid bandwidth values.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or (since 0.9.5) the device target shorthand
- * (the <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * Returns -1 in case of failure, 0 when successful.
- */
-int
-virDomainBlockJobSetSpeed(virDomainPtr dom, const char *disk,
-                          unsigned long bandwidth, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, bandwidth=%lu, flags=%x",
-                     disk, bandwidth, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-
-    if (conn->driver->domainBlockJobSetSpeed) {
-        int ret;
-        ret = conn->driver->domainBlockJobSetSpeed(dom, disk, bandwidth, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockPull:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @bandwidth: (optional) specify bandwidth limit; flags determine the unit
- * @flags: bitwise-OR of virDomainBlockPullFlags
- *
- * Populate a disk image with data from its backing image.  Once all data from
- * its backing image has been pulled, the disk no longer depends on a backing
- * image.  This function pulls data for the entire device in the background.
- * Progress of the operation can be checked with virDomainGetBlockJobInfo() and
- * the operation can be aborted with virDomainBlockJobAbort().  When finished,
- * an asynchronous event is raised to indicate the final status.  To move
- * data in the opposite direction, see virDomainBlockCommit().
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or (since 0.9.5) the device target shorthand
- * (the <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * The maximum bandwidth that will be used to do the copy can be
- * specified with the @bandwidth parameter.  If set to 0, there is no
- * limit.  If @flags includes VIR_DOMAIN_BLOCK_PULL_BANDWIDTH_BYTES,
- * @bandwidth is in bytes/second; otherwise, it is in MiB/second.
- * Values larger than 2^52 bytes/sec may be rejected due to overflow
- * considerations based on the word size of both client and server,
- * and values larger than 2^31 bytes/sec may cause overflow problems
- * if later queried by virDomainGetBlockJobInfo() without scaling.
- * Hypervisors may further restrict the range of valid bandwidth
- * values.  Some hypervisors do not support this feature and will
- * return an error if bandwidth is not 0; in this case, it might still
- * be possible for a later call to virDomainBlockJobSetSpeed() to
- * succeed.  The actual speed can be determined with
- * virDomainGetBlockJobInfo().
- *
- * This is shorthand for virDomainBlockRebase() with a NULL base.
- *
- * Returns 0 if the operation has started, -1 on failure.
- */
-int
-virDomainBlockPull(virDomainPtr dom, const char *disk,
-                   unsigned long bandwidth, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, bandwidth=%lu, flags=%x",
-                     disk, bandwidth, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-
-    if (conn->driver->domainBlockPull) {
-        int ret;
-        ret = conn->driver->domainBlockPull(dom, disk, bandwidth, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockRebase:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @base: path to backing file to keep, or device shorthand,
- *        or NULL for no backing file
- * @bandwidth: (optional) specify bandwidth limit; flags determine the unit
- * @flags: bitwise-OR of virDomainBlockRebaseFlags
- *
- * Populate a disk image with data from its backing image chain, and
- * setting the backing image to @base, or alternatively copy an entire
- * backing chain to a new file @base.
- *
- * When @flags is 0, this starts a pull, where @base must be the absolute
- * path of one of the backing images further up the chain, or NULL to
- * convert the disk image so that it has no backing image.  Once all
- * data from its backing image chain has been pulled, the disk no
- * longer depends on those intermediate backing images.  This function
- * pulls data for the entire device in the background.  Progress of
- * the operation can be checked with virDomainGetBlockJobInfo() with a
- * job type of VIR_DOMAIN_BLOCK_JOB_TYPE_PULL, and the operation can be
- * aborted with virDomainBlockJobAbort().  When finished, an asynchronous
- * event is raised to indicate the final status, and the job no longer
- * exists.  If the job is aborted, a new one can be started later to
- * resume from the same point.
- *
- * If @flags contains VIR_DOMAIN_BLOCK_REBASE_RELATIVE, the name recorded
- * into the active disk as the location for @base will be kept relative.
- * The operation will fail if libvirt can't infer the name.
- *
- * When @flags includes VIR_DOMAIN_BLOCK_REBASE_COPY, this starts a copy,
- * where @base must be the name of a new file to copy the chain to.  By
- * default, the copy will pull the entire source chain into the destination
- * file, but if @flags also contains VIR_DOMAIN_BLOCK_REBASE_SHALLOW, then
- * only the top of the source chain will be copied (the source and
- * destination have a common backing file).  By default, @base will be
- * created with the same file format as the source, but this can be altered
- * by adding VIR_DOMAIN_BLOCK_REBASE_COPY_RAW to force the copy to be raw
- * (does not make sense with the shallow flag unless the source is also raw),
- * or by using VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT to reuse an existing file
- * which was pre-created with the correct format and metadata and sufficient
- * size to hold the copy. In case the VIR_DOMAIN_BLOCK_REBASE_SHALLOW flag
- * is used the pre-created file has to exhibit the same guest visible contents
- * as the backing file of the original image. This allows a management app to
- * pre-create files with relative backing file names, rather than the default
- * of absolute backing file names; as a security precaution, you should
- * generally only use reuse_ext with the shallow flag and a non-raw
- * destination file.  By default, the copy destination will be treated as
- * type='file', but using VIR_DOMAIN_BLOCK_REBASE_COPY_DEV treats the
- * destination as type='block' (affecting how virDomainGetBlockInfo() will
- * report allocation after pivoting).
- *
- * A copy job has two parts; in the first phase, the @bandwidth parameter
- * affects how fast the source is pulled into the destination, and the job
- * can only be canceled by reverting to the source file; progress in this
- * phase can be tracked via the virDomainBlockJobInfo() command, with a
- * job type of VIR_DOMAIN_BLOCK_JOB_TYPE_COPY.  The job transitions to the
- * second phase when the job info states cur == end, and remains alive to
- * mirror all further changes to both source and destination.  The user
- * must call virDomainBlockJobAbort() to end the mirroring while choosing
- * whether to revert to source or pivot to the destination.  An event is
- * issued when the job ends, and depending on the hypervisor, an event may
- * also be issued when the job transitions from pulling to mirroring.  If
- * the job is aborted, a new job will have to start over from the beginning
- * of the first phase.
- *
- * Some hypervisors will restrict certain actions, such as virDomainSave()
- * or virDomainDetachDevice(), while a copy job is active; they may
- * also restrict a copy job to transient domains.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or the device target shorthand (the
- * <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * The @base parameter can be either a path to a file within the backing
- * chain, or the device target shorthand (the <target dev='...'/>
- * sub-element, such as "vda") followed by an index to the backing chain
- * enclosed in square brackets. Backing chain indexes can be found by
- * inspecting //disk//backingStore/@index in the domain XML. Thus, for
- * example, "vda[3]" refers to the backing store with index equal to "3"
- * in the chain of disk "vda".
- *
- * The maximum bandwidth that will be used to do the copy can be
- * specified with the @bandwidth parameter.  If set to 0, there is no
- * limit.  If @flags includes VIR_DOMAIN_BLOCK_REBASE_BANDWIDTH_BYTES,
- * @bandwidth is in bytes/second; otherwise, it is in MiB/second.
- * Values larger than 2^52 bytes/sec may be rejected due to overflow
- * considerations based on the word size of both client and server,
- * and values larger than 2^31 bytes/sec may cause overflow problems
- * if later queried by virDomainGetBlockJobInfo() without scaling.
- * Hypervisors may further restrict the range of valid bandwidth
- * values.  Some hypervisors do not support this feature and will
- * return an error if bandwidth is not 0; in this case, it might still
- * be possible for a later call to virDomainBlockJobSetSpeed() to
- * succeed.  The actual speed can be determined with
- * virDomainGetBlockJobInfo().
- *
- * When @base is NULL and @flags is 0, this is identical to
- * virDomainBlockPull().  When @flags contains VIR_DOMAIN_BLOCK_REBASE_COPY,
- * this command is shorthand for virDomainBlockCopy() where the destination
- * XML encodes @base as a <disk type='file'>, @bandwidth is properly scaled
- * and passed as a typed parameter, the shallow and reuse external flags
- * are preserved, and remaining flags control whether the XML encodes a
- * destination format of raw instead of leaving the destination identical
- * to the source format or probed from the reused file.
- *
- * Returns 0 if the operation has started, -1 on failure.
- */
-int
-virDomainBlockRebase(virDomainPtr dom, const char *disk,
-                     const char *base, unsigned long bandwidth,
-                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, base=%s, bandwidth=%lu, flags=%x",
-                     disk, NULLSTR(base), bandwidth, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-
-    if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY) {
-        virCheckNonNullArgGoto(base, error);
-    } else if (flags & (VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
-                        VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
-                        VIR_DOMAIN_BLOCK_REBASE_COPY_RAW |
-                        VIR_DOMAIN_BLOCK_REBASE_COPY_DEV)) {
-        virReportInvalidArg(flags,
-                            _("use of flags in %s requires a copy job"),
-                            __FUNCTION__);
-        goto error;
-    }
-
-    if (conn->driver->domainBlockRebase) {
-        int ret;
-        ret = conn->driver->domainBlockRebase(dom, disk, base, bandwidth,
-                                              flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockCopy:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @destxml: XML description of the copy destination
- * @params: Pointer to block copy parameter objects, or NULL
- * @nparams: Number of block copy parameters (this value can be the same or
- *           less than the number of parameters supported)
- * @flags: bitwise-OR of virDomainBlockCopyFlags
- *
- * Copy the guest-visible contents of a disk image to a new file described
- * by @destxml.  The destination XML has a top-level element of <disk>, and
- * resembles what is used when hot-plugging a disk via virDomainAttachDevice(),
- * except that only sub-elements related to describing the new host resource
- * are necessary (sub-elements related to the guest view, such as <target>,
- * are ignored).  It is strongly recommended to include a <driver type='...'/>
- * format designation for the destination, to avoid the potential of any
- * security problem that might be caused by probing a file for its format.
- *
- * This command starts a long-running copy.  By default, the copy will pull
- * the entire source chain into the destination file, but if @flags also
- * contains VIR_DOMAIN_BLOCK_COPY_SHALLOW, then only the top of the source
- * chain will be copied (the source and destination have a common backing
- * file).  The format of the destination file is controlled by the <driver>
- * sub-element of the XML.  The destination will be created unless the
- * VIR_DOMAIN_BLOCK_COPY_REUSE_EXT flag is present stating that the file
- * was pre-created with the correct format and metadata and sufficient
- * size to hold the copy. In case the VIR_DOMAIN_BLOCK_COPY_SHALLOW flag
- * is used the pre-created file has to exhibit the same guest visible contents
- * as the backing file of the original image. This allows a management app to
- * pre-create files with relative backing file names, rather than the default
- * of absolute backing file names.
- *
- * A copy job has two parts; in the first phase, the source is copied into
- * the destination, and the job can only be canceled by reverting to the
- * source file; progress in this phase can be tracked via the
- * virDomainBlockJobInfo() command, with a job type of
- * VIR_DOMAIN_BLOCK_JOB_TYPE_COPY.  The job transitions to the second
- * phase when the job info states cur == end, and remains alive to mirror
- * all further changes to both source and destination.  The user must
- * call virDomainBlockJobAbort() to end the mirroring while choosing
- * whether to revert to source or pivot to the destination.  An event is
- * issued when the job ends, and depending on the hypervisor, an event may
- * also be issued when the job transitions from pulling to mirroring.  If
- * the job is aborted, a new job will have to start over from the beginning
- * of the first phase.
- *
- * Some hypervisors will restrict certain actions, such as virDomainSave()
- * or virDomainDetachDevice(), while a copy job is active; they may
- * also restrict a copy job to transient domains.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or the device target shorthand (the
- * <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * The @params and @nparams arguments can be used to set hypervisor-specific
- * tuning parameters, such as maximum bandwidth or granularity.  For a
- * parameter that the hypervisor understands, explicitly specifying 0
- * behaves the same as omitting the parameter, to use the hypervisor
- * default; however, omitting a parameter is less likely to fail.
- *
- * This command is a superset of the older virDomainBlockRebase() when used
- * with the VIR_DOMAIN_BLOCK_REBASE_COPY flag, and offers better control
- * over the destination format, the ability to copy to a destination that
- * is not a local file, and the possibility of additional tuning parameters.
- *
- * Returns 0 if the operation has started, -1 on failure.
- */
-int
-virDomainBlockCopy(virDomainPtr dom, const char *disk,
-                   const char *destxml,
-                   virTypedParameterPtr params,
-                   int nparams,
-                   unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom,
-                     "disk=%s, destxml=%s, params=%p, nparams=%d, flags=%x",
-                     disk, destxml, params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-    virCheckNonNullArgGoto(destxml, error);
-    virCheckNonNegativeArgGoto(nparams, error);
-    if (nparams)
-        virCheckNonNullArgGoto(params, error);
-
-    if (conn->driver->domainBlockCopy) {
-        int ret;
-        ret = conn->driver->domainBlockCopy(dom, disk, destxml,
-                                            params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainBlockCommit:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @base: path to backing file to merge into, or device shorthand,
- *        or NULL for default
- * @top: path to file within backing chain that contains data to be merged,
- *       or device shorthand, or NULL to merge all possible data
- * @bandwidth: (optional) specify bandwidth limit; flags determine the unit
- * @flags: bitwise-OR of virDomainBlockCommitFlags
- *
- * Commit changes that were made to temporary top-level files within a disk
- * image backing file chain into a lower-level base file.  In other words,
- * take all the difference between @base and @top, and update @base to contain
- * that difference; after the commit, any portion of the chain that previously
- * depended on @top will now depend on @base, and all files after @base up
- * to and including @top will now be invalidated.  A typical use of this
- * command is to reduce the length of a backing file chain after taking an
- * external disk snapshot.  To move data in the opposite direction, see
- * virDomainBlockPull().
- *
- * This command starts a long-running commit block job, whose status may
- * be tracked by virDomainBlockJobInfo() with a job type of
- * VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT, and the operation can be aborted with
- * virDomainBlockJobAbort().  When finished, an asynchronous event is
- * raised to indicate the final status, and the job no longer exists.  If
- * the job is aborted, it is up to the hypervisor whether starting a new
- * job will resume from the same point, or start over.
- *
- * As a special case, if @top is the active image (or NULL), and @flags
- * includes VIR_DOMAIN_BLOCK_COMMIT_ACTIVE, the block job will have a type
- * of VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT, and operates in two phases.
- * In the first phase, the contents are being committed into @base, and the
- * job can only be canceled.  The job transitions to the second phase when
- * the job info states cur == end, and remains alive to keep all further
- * changes to @top synchronized into @base; an event with status
- * VIR_DOMAIN_BLOCK_JOB_READY is also issued to mark the job transition.
- * Once in the second phase, the user must choose whether to cancel the job
- * (keeping @top as the active image, but now containing only the changes
- * since the time the job ended) or to pivot the job (adjusting to @base as
- * the active image, and invalidating @top).
- *
- * Be aware that this command may invalidate files even if it is aborted;
- * the user is cautioned against relying on the contents of invalidated
- * intermediate files such as @top (when @top is not the active image)
- * without manually rebasing those files to use a backing file of a
- * read-only copy of @base prior to the point where the commit operation
- * was started (and such a rebase cannot be safely done until the commit
- * has successfully completed).  However, the domain itself will not have
- * any issues; the active layer remains valid throughout the entire commit
- * operation.
- *
- * Some hypervisors may support a shortcut where if @flags contains
- * VIR_DOMAIN_BLOCK_COMMIT_DELETE, then this command will unlink all files
- * that were invalidated, after the commit successfully completes.
- *
- * If @flags contains VIR_DOMAIN_BLOCK_COMMIT_RELATIVE, the name recorded
- * into the overlay of the @top image (if there is such image) as the
- * path to the new backing file will be kept relative to other images.
- * The operation will fail if libvirt can't infer the name.
- *
- * By default, if @base is NULL, the commit target will be the bottom of
- * the backing chain; if @flags contains VIR_DOMAIN_BLOCK_COMMIT_SHALLOW,
- * then the immediate backing file of @top will be used instead.  If @top
- * is NULL, the active image at the top of the chain will be used.  Some
- * hypervisors place restrictions on how much can be committed, and might
- * fail if @base is not the immediate backing file of @top, or if @top is
- * the active layer in use by a running domain but @flags did not include
- * VIR_DOMAIN_BLOCK_COMMIT_ACTIVE, or if @top is not the top-most file;
- * restrictions may differ for online vs. offline domains.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or the device target shorthand (the
- * <target dev='...'/> sub-element, such as "vda").  Valid names
- * can be found by calling virDomainGetXMLDesc() and inspecting
- * elements within //domain/devices/disk.
- *
- * The @base and @top parameters can be either paths to files within the
- * backing chain, or the device target shorthand (the <target dev='...'/>
- * sub-element, such as "vda") followed by an index to the backing chain
- * enclosed in square brackets. Backing chain indexes can be found by
- * inspecting //disk//backingStore/@index in the domain XML. Thus, for
- * example, "vda[3]" refers to the backing store with index equal to "3"
- * in the chain of disk "vda".
- *
- * The maximum bandwidth that will be used to do the commit can be
- * specified with the @bandwidth parameter.  If set to 0, there is no
- * limit.  If @flags includes VIR_DOMAIN_BLOCK_COMMIT_BANDWIDTH_BYTES,
- * @bandwidth is in bytes/second; otherwise, it is in MiB/second.
- * Values larger than 2^52 bytes/sec may be rejected due to overflow
- * considerations based on the word size of both client and server,
- * and values larger than 2^31 bytes/sec may cause overflow problems
- * if later queried by virDomainGetBlockJobInfo() without scaling.
- * Hypervisors may further restrict the range of valid bandwidth
- * values.  Some hypervisors do not support this feature and will
- * return an error if bandwidth is not 0; in this case, it might still
- * be possible for a later call to virDomainBlockJobSetSpeed() to
- * succeed.  The actual speed can be determined with
- * virDomainGetBlockJobInfo().
- *
- * Returns 0 if the operation has started, -1 on failure.
- */
-int
-virDomainBlockCommit(virDomainPtr dom, const char *disk,
-                     const char *base, const char *top,
-                     unsigned long bandwidth, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, base=%s, top=%s, bandwidth=%lu, flags=%x",
-                     disk, NULLSTR(base), NULLSTR(top), bandwidth, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-
-    if (conn->driver->domainBlockCommit) {
-        int ret;
-        ret = conn->driver->domainBlockCommit(dom, disk, base, top, bandwidth,
-                                              flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainOpenGraphics:
- * @dom: pointer to domain object
- * @idx: index of graphics config to open
- * @fd: file descriptor to attach graphics to
- * @flags: bitwise-OR of virDomainOpenGraphicsFlags
- *
- * This will attempt to connect the file descriptor @fd, to
- * the graphics backend of @dom. If @dom has multiple graphics
- * backends configured, then @idx will determine which one is
- * opened, starting from @idx 0.
- *
- * To disable any authentication, pass the VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH
- * constant for @flags.
- *
- * The caller should use an anonymous socketpair to open
- * @fd before invocation.
- *
- * This method can only be used when connected to a local
- * libvirt hypervisor, over a UNIX domain socket. Attempts
- * to use this method over a TCP connection will always fail
- *
- * Returns 0 on success, -1 on failure
- */
-int
-virDomainOpenGraphics(virDomainPtr dom,
-                      unsigned int idx,
-                      int fd,
-                      unsigned int flags)
-{
-    struct stat sb;
-    VIR_DOMAIN_DEBUG(dom, "idx=%u, fd=%d, flags=%x",
-                     idx, fd, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    virCheckNonNegativeArgGoto(fd, error);
-
-    if (fstat(fd, &sb) < 0) {
-        virReportSystemError(errno,
-                             _("Unable to access file descriptor %d"), fd);
-        goto error;
-    }
-
-    if (!S_ISSOCK(sb.st_mode)) {
-        virReportInvalidArg(fd,
-                          _("fd %d in %s must be a socket"),
-                            fd, __FUNCTION__);
-        goto error;
-    }
-
-    virCheckReadOnlyGoto(dom->conn->flags, error);
-
-    if (!VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
-                                  VIR_DRV_FEATURE_FD_PASSING)) {
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                       _("fd passing is not supported by this connection"));
-        goto error;
-    }
-
-    if (dom->conn->driver->domainOpenGraphics) {
-        int ret;
-        ret = dom->conn->driver->domainOpenGraphics(dom, idx, fd, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainOpenGraphicsFD:
- * @dom: pointer to domain object
- * @idx: index of graphics config to open
- * @flags: bitwise-OR of virDomainOpenGraphicsFlags
- *
- * This will create a socket pair connected to the graphics backend of @dom.
- * One end of the socket will be returned on success, and the other end is
- * handed to the hypervisor.
- * If @dom has multiple graphics backends configured, then @idx will determine
- * which one is opened, starting from @idx 0.
- *
- * To disable any authentication, pass the VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH
- * constant for @flags.
- *
- * This method can only be used when connected to a local
- * libvirt hypervisor, over a UNIX domain socket. Attempts
- * to use this method over a TCP connection will always fail.
- *
- * Returns an fd on success, -1 on failure
- */
-int
-virDomainOpenGraphicsFD(virDomainPtr dom,
-                        unsigned int idx,
-                        unsigned int flags)
-{
-    VIR_DOMAIN_DEBUG(dom, "idx=%u, flags=%x", idx, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-
-    virCheckReadOnlyGoto(dom->conn->flags, error);
-
-    if (!VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
-                                  VIR_DRV_FEATURE_FD_PASSING)) {
-        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
-                       _("fd passing is not supported by this connection"));
-        goto error;
-    }
-
-    if (dom->conn->driver->domainOpenGraphicsFD) {
-        int ret;
-        ret = dom->conn->driver->domainOpenGraphicsFD(dom, idx, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virConnectSetKeepAlive:
- * @conn: pointer to a hypervisor connection
- * @interval: number of seconds of inactivity before a keepalive message is sent
- * @count: number of messages that can be sent in a row
- *
- * Start sending keepalive messages after @interval seconds of inactivity and
- * consider the connection to be broken when no response is received after
- * @count keepalive messages sent in a row.  In other words, sending count + 1
- * keepalive message results in closing the connection.  When @interval is
- * <= 0, no keepalive messages will be sent.  When @count is 0, the connection
- * will be automatically closed after @interval seconds of inactivity without
- * sending any keepalive messages.
- *
- * Note: The client has to implement and run an event loop with
- * virEventRegisterImpl() or virEventRegisterDefaultImpl() to be able to
- * use keepalive messages.  Failure to do so may result in connections
- * being closed unexpectedly.
- *
- * Note: This API function controls only keepalive messages sent by the client.
- * If the server is configured to use keepalive you still need to run the event
- * loop to respond to them, even if you disable keepalives by this function.
- *
- * Returns -1 on error, 0 on success, 1 when remote party doesn't support
- * keepalive messages.
- */
-int
-virConnectSetKeepAlive(virConnectPtr conn,
-                       int interval,
-                       unsigned int count)
-{
-    int ret = -1;
-
-    VIR_DEBUG("conn=%p, interval=%d, count=%u", conn, interval, count);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-
-    if (conn->driver->connectSetKeepAlive) {
-        ret = conn->driver->connectSetKeepAlive(conn, interval, count);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectIsAlive:
- * @conn: pointer to the connection object
- *
- * Determine if the connection to the hypervisor is still alive
- *
- * A connection will be classed as alive if it is either local, or running
- * over a channel (TCP or UNIX socket) which is not closed.
- *
- * Returns 1 if alive, 0 if dead, -1 on error
- */
-int
-virConnectIsAlive(virConnectPtr conn)
-{
-    VIR_DEBUG("conn=%p", conn);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    if (conn->driver->connectIsAlive) {
-        int ret;
-        ret = conn->driver->connectIsAlive(conn);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virConnectRegisterCloseCallback:
- * @conn: pointer to connection object
- * @cb: callback to invoke upon close
- * @opaque: user data to pass to @cb
- * @freecb: callback to free @opaque
- *
- * Registers a callback to be invoked when the connection
- * is closed. This callback is invoked when there is any
- * condition that causes the socket connection to the
- * hypervisor to be closed.
- *
- * This function is only applicable to hypervisor drivers
- * which maintain a persistent open connection. Drivers
- * which open a new connection for every operation will
- * not invoke this.
- *
- * The @freecb must not invoke any other libvirt public
- * APIs, since it is not called from a re-entrant safe
- * context.
- *
- * Returns 0 on success, -1 on error
- */
-int
-virConnectRegisterCloseCallback(virConnectPtr conn,
-                                virConnectCloseFunc cb,
-                                void *opaque,
-                                virFreeCallback freecb)
-{
-    VIR_DEBUG("conn=%p", conn);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-
-    virObjectRef(conn);
-
-    virMutexLock(&conn->lock);
-    virObjectLock(conn->closeCallback);
-
-    virCheckNonNullArgGoto(cb, error);
-
-    if (conn->closeCallback->callback) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("A close callback is already registered"));
-        goto error;
-    }
-
-    conn->closeCallback->conn = conn;
-    conn->closeCallback->callback = cb;
-    conn->closeCallback->opaque = opaque;
-    conn->closeCallback->freeCallback = freecb;
-
-    virObjectUnlock(conn->closeCallback);
-    virMutexUnlock(&conn->lock);
-
-    return 0;
-
- error:
-    virObjectUnlock(conn->closeCallback);
-    virMutexUnlock(&conn->lock);
-    virDispatchError(conn);
-    virObjectUnref(conn);
-    return -1;
-}
-
-
-/**
- * virConnectUnregisterCloseCallback:
- * @conn: pointer to connection object
- * @cb: pointer to the current registered callback
- *
- * Unregisters the callback previously set with the
- * virConnectRegisterCloseCallback method. The callback
- * will no longer receive notifications when the connection
- * closes. If a virFreeCallback was provided at time of
- * registration, it will be invoked
- *
- * Returns 0 on success, -1 on error
- */
-int
-virConnectUnregisterCloseCallback(virConnectPtr conn,
-                                  virConnectCloseFunc cb)
-{
-    VIR_DEBUG("conn=%p", conn);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-
-    virMutexLock(&conn->lock);
-    virObjectLock(conn->closeCallback);
-
-    virCheckNonNullArgGoto(cb, error);
-
-    if (conn->closeCallback->callback != cb) {
-        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
-                       _("A different callback was requested"));
-        goto error;
-    }
-
-    conn->closeCallback->callback = NULL;
-    if (conn->closeCallback->freeCallback)
-        conn->closeCallback->freeCallback(conn->closeCallback->opaque);
-    conn->closeCallback->freeCallback = NULL;
-
-    virObjectUnref(conn);
-    virObjectUnlock(conn->closeCallback);
-    virMutexUnlock(&conn->lock);
-
-    return 0;
-
- error:
-    virObjectUnlock(conn->closeCallback);
-    virMutexUnlock(&conn->lock);
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainSetBlockIoTune:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @params: Pointer to blkio parameter objects
- * @nparams: Number of blkio parameters (this value can be the same or
- *           less than the number of parameters supported)
- * @flags: bitwise-OR of virDomainModificationImpact
- *
- * Change all or a subset of the per-device block IO tunables.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or the device target shorthand (the <target
- * dev='...'/> sub-element, such as "xvda").  Valid names can be found
- * by calling virDomainGetXMLDesc() and inspecting elements
- * within //domain/devices/disk.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainSetBlockIoTune(virDomainPtr dom,
-                        const char *disk,
-                        virTypedParameterPtr params,
-                        int nparams,
-                        unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, params=%p, nparams=%d, flags=%x",
-                     disk, params, nparams, flags);
-    VIR_TYPED_PARAMS_DEBUG(params, nparams);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-    conn = dom->conn;
-
-    virCheckReadOnlyGoto(conn->flags, error);
-    virCheckNonNullArgGoto(disk, error);
-    virCheckPositiveArgGoto(nparams, error);
-    virCheckNonNullArgGoto(params, error);
-
-    if (virTypedParameterValidateSet(dom->conn, params, nparams) < 0)
-        goto error;
-
-    if (conn->driver->domainSetBlockIoTune) {
-        int ret;
-        ret = conn->driver->domainSetBlockIoTune(dom, disk, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetBlockIoTune:
- * @dom: pointer to domain object
- * @disk: path to the block device, or device shorthand
- * @params: Pointer to blkio parameter object
- *          (return value, allocated by the caller)
- * @nparams: Pointer to number of blkio parameters
- * @flags: bitwise-OR of virDomainModificationImpact and virTypedParameterFlags
- *
- * Get all block IO tunable parameters for a given device.  On input,
- * @nparams gives the size of the @params array; on output, @nparams
- * gives how many slots were filled with parameter information, which
- * might be less but will not exceed the input value.
- *
- * As a special case, calling with @params as NULL and @nparams as 0
- * on input will cause @nparams on output to contain the number of
- * parameters supported by the hypervisor, either for the given @disk
- * (note that block devices of different types might support different
- * parameters), or if @disk is NULL, for all possible disks. The
- * caller should then allocate @params array,
- * i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
- * again.  See virDomainGetMemoryParameters() for more details.
- *
- * The @disk parameter is either an unambiguous source name of the
- * block device (the <source file='...'/> sub-element, such as
- * "/path/to/image"), or the device target shorthand (the <target
- * dev='...'/> sub-element, such as "xvda").  Valid names can be found
- * by calling virDomainGetXMLDesc() and inspecting elements
- * within //domain/devices/disk.  This parameter cannot be NULL
- * unless @nparams is 0 on input.
- *
- * Returns -1 in case of error, 0 in case of success.
- */
-int
-virDomainGetBlockIoTune(virDomainPtr dom,
-                        const char *disk,
-                        virTypedParameterPtr params,
-                        int *nparams,
-                        unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(dom, "disk=%s, params=%p, nparams=%d, flags=%x",
-                     NULLSTR(disk), params, (nparams) ? *nparams : -1, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-
-    virCheckNonNullArgGoto(nparams, error);
-    virCheckNonNegativeArgGoto(*nparams, error);
-    if (*nparams != 0) {
-        virCheckNonNullArgGoto(params, error);
-        virCheckNonNullArgGoto(disk, error);
-    }
-
-    if (VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-
-    /* At most one of these two flags should be set.  */
-    if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
-        (flags & VIR_DOMAIN_AFFECT_CONFIG)) {
-        virReportInvalidArg(flags,
-                            _("flags 'affect live' and 'affect config' in %s "
-                              "are mutually exclusive"),
-                            __FUNCTION__);
-        goto error;
-    }
-    conn = dom->conn;
-
-    if (conn->driver->domainGetBlockIoTune) {
-        int ret;
-        ret = conn->driver->domainGetBlockIoTune(dom, disk, params, nparams, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetCPUStats:
- * @domain: domain to query
- * @params: array to populate on output
- * @nparams: number of parameters per cpu
- * @start_cpu: which cpu to start with, or -1 for summary
- * @ncpus: how many cpus to query
- * @flags: bitwise-OR of virTypedParameterFlags
- *
- * Get statistics relating to CPU usage attributable to a single
- * domain (in contrast to the statistics returned by
- * virNodeGetCPUStats() for all processes on the host).  @dom
- * must be running (an inactive domain has no attributable cpu
- * usage).  On input, @params must contain at least @nparams * @ncpus
- * entries, allocated by the caller.
- *
- * If @start_cpu is -1, then @ncpus must be 1, and the returned
- * results reflect the statistics attributable to the entire
- * domain (such as user and system time for the process as a
- * whole).  Otherwise, @start_cpu represents which cpu to start
- * with, and @ncpus represents how many consecutive processors to
- * query, with statistics attributable per processor (such as
- * per-cpu usage).  If @ncpus is larger than the number of cpus
- * available to query, then the trailing part of the array will
- * be unpopulated.
- *
- * The remote driver imposes a limit of 128 @ncpus and 16 @nparams;
- * the number of parameters per cpu should not exceed 16, but if you
- * have a host with more than 128 CPUs, your program should split
- * the request into multiple calls.
- *
- * As special cases, if @params is NULL and @nparams is 0 and
- * @ncpus is 1, and the return value will be how many
- * statistics are available for the given @start_cpu.  This number
- * may be different for @start_cpu of -1 than for any non-negative
- * value, but will be the same for all non-negative @start_cpu.
- * Likewise, if @params is NULL and @nparams is 0 and @ncpus is 0,
- * the number of cpus available to query is returned.  From the
- * host perspective, this would typically match the cpus member
- * of virNodeGetInfo(), but might be less due to host cpu hotplug.
- *
- * For now, @flags is unused, and the statistics all relate to the
- * usage from the host perspective.  It is possible that a future
- * version will support a flag that queries the cpu usage from the
- * guest's perspective, where the maximum cpu to query would be
- * related to virDomainGetVcpusFlags() rather than virNodeGetInfo().
- * An individual guest vcpu cannot be reliably mapped back to a
- * specific host cpu unless a single-processor vcpu pinning was used,
- * but when @start_cpu is -1, any difference in usage between a host
- * and guest perspective would serve as a measure of hypervisor overhead.
- *
- * Typical use sequence is below.
- *
- * getting total stats: set start_cpu as -1, ncpus 1
- * virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0) => nparams
- * params = calloc(nparams, sizeof(virTypedParameter))
- * virDomainGetCPUStats(dom, params, nparams, -1, 1, 0) => total stats.
- *
- * getting per-cpu stats:
- * virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0) => ncpus
- * virDomainGetCPUStats(dom, NULL, 0, 0, 1, 0) => nparams
- * params = calloc(ncpus * nparams, sizeof(virTypedParameter))
- * virDomainGetCPUStats(dom, params, nparams, 0, ncpus, 0) => per-cpu stats
- *
- * Returns -1 on failure, or the number of statistics that were
- * populated per cpu on success (this will be less than the total
- * number of populated @params, unless @ncpus was 1; and may be
- * less than @nparams).  The populated parameters start at each
- * stride of @nparams, which means the results may be discontiguous;
- * any unpopulated parameters will be zeroed on success (this includes
- * skipped elements if @nparams is too large, and tail elements if
- * @ncpus is too large).  The caller is responsible for freeing any
- * returned string parameters.
- */
-int
-virDomainGetCPUStats(virDomainPtr domain,
-                     virTypedParameterPtr params,
-                     unsigned int nparams,
-                     int start_cpu,
-                     unsigned int ncpus,
-                     unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain,
-                     "params=%p, nparams=%d, start_cpu=%d, ncpus=%u, flags=%x",
-                     params, nparams, start_cpu, ncpus, flags);
-    virResetLastError();
-
-    virCheckDomainReturn(domain, -1);
-    conn = domain->conn;
-
-    /* Special cases:
-     * start_cpu must be non-negative, or else -1
-     * if start_cpu is -1, ncpus must be 1
-     * params == NULL must match nparams == 0
-     * ncpus must be non-zero unless params == NULL
-     * nparams * ncpus must not overflow (RPC may restrict it even more)
-     */
-    if (start_cpu == -1) {
-        if (ncpus != 1) {
-            virReportInvalidArg(start_cpu,
-                                _("ncpus in %s must be 1 when start_cpu is -1"),
-                                __FUNCTION__);
-            goto error;
-        }
-    } else {
-        virCheckNonNegativeArgGoto(start_cpu, error);
-    }
-    if (nparams)
-        virCheckNonNullArgGoto(params, error);
-    else
-        virCheckNullArgGoto(params, error);
-    if (ncpus == 0)
-        virCheckNullArgGoto(params, error);
-
-    if (nparams && ncpus > UINT_MAX / nparams) {
-        virReportError(VIR_ERR_OVERFLOW, _("input too large: %u * %u"),
-                       nparams, ncpus);
-        goto error;
-    }
-    if (VIR_DRV_SUPPORTS_FEATURE(domain->conn->driver, domain->conn,
-                                 VIR_DRV_FEATURE_TYPED_PARAM_STRING))
-        flags |= VIR_TYPED_PARAM_STRING_OKAY;
-
-    if (conn->driver->domainGetCPUStats) {
-        int ret;
-
-        ret = conn->driver->domainGetCPUStats(domain, params, nparams,
-                                              start_cpu, ncpus, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetDiskErrors:
- * @dom: a domain object
- * @errors: array to populate on output
- * @maxerrors: size of @errors array
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * The function populates @errors array with all disks that encountered an
- * I/O error.  Disks with no error will not be returned in the @errors array.
- * Each disk is identified by its target (the dev attribute of target
- * subelement in domain XML), such as "vda", and accompanied with the error
- * that was seen on it.  The caller is also responsible for calling free()
- * on each disk name returned.
- *
- * In a special case when @errors is NULL and @maxerrors is 0, the function
- * returns preferred size of @errors that the caller should use to get all
- * disk errors.
- *
- * Since calling virDomainGetDiskErrors(dom, NULL, 0, 0) to get preferred size
- * of @errors array and getting the errors are two separate operations, new
- * disks may be hotplugged to the domain and new errors may be encountered
- * between the two calls.  Thus, this function may not return all disk errors
- * because the supplied array is not large enough.  Such errors may, however,
- * be detected by listening to domain events.
- *
- * Returns number of disks with errors filled in the @errors array or -1 on
- * error.
- */
-int
-virDomainGetDiskErrors(virDomainPtr dom,
-                       virDomainDiskErrorPtr errors,
-                       unsigned int maxerrors,
-                       unsigned int flags)
-{
-    VIR_DOMAIN_DEBUG(dom, "errors=%p, maxerrors=%u, flags=%x",
-                     errors, maxerrors, flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(dom, -1);
-
-    if (maxerrors)
-        virCheckNonNullArgGoto(errors, error);
-    else
-        virCheckNullArgGoto(errors, error);
-
-    if (dom->conn->driver->domainGetDiskErrors) {
-        int ret = dom->conn->driver->domainGetDiskErrors(dom, errors,
-                                                         maxerrors, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(dom->conn);
-    return -1;
-}
-
-
-/**
- * virDomainGetHostname:
- * @domain: a domain object
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Get the hostname for that domain.
- *
- * Dependent on hypervisor used, this may require a guest agent to be
- * available.
- *
- * Returns the hostname which must be freed by the caller, or
- * NULL if there was an error.
- */
-char *
-virDomainGetHostname(virDomainPtr domain, unsigned int flags)
-{
-    virConnectPtr conn;
-
-    VIR_DOMAIN_DEBUG(domain, "flags=%x", flags);
-
-    virResetLastError();
-
-    virCheckDomainReturn(domain, NULL);
-    conn = domain->conn;
-
-    if (conn->driver->domainGetHostname) {
-        char *ret;
-        ret = conn->driver->domainGetHostname(domain, flags);
-        if (!ret)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(domain->conn);
-    return NULL;
-}
-
-
-/**
- * virNodeGetCPUMap:
- * @conn: pointer to the hypervisor connection
- * @cpumap: optional pointer to a bit map of real CPUs on the host node
- *      (in 8-bit bytes) (OUT)
- *      In case of success each bit set to 1 means that corresponding
- *      CPU is online.
- *      Bytes are stored in little-endian order: CPU0-7, 8-15...
- *      In each byte, lowest CPU number is least significant bit.
- *      The bit map is allocated by virNodeGetCPUMap and needs
- *      to be released using free() by the caller.
- * @online: optional number of online CPUs in cpumap (OUT)
- *      Contains the number of online CPUs if the call was successful.
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Get CPU map of host node CPUs.
- *
- * Returns number of CPUs present on the host node,
- * or -1 if there was an error.
- */
-int
-virNodeGetCPUMap(virConnectPtr conn,
-                 unsigned char **cpumap,
-                 unsigned int *online,
-                 unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, cpumap=%p, online=%p, flags=%x",
-              conn, cpumap, online, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-
-    if (conn->driver->nodeGetCPUMap) {
-        int ret = conn->driver->nodeGetCPUMap(conn, cpumap, online, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return -1;
-}
-
-
-/**
- * virDomainFSTrim:
- * @dom: a domain object
- * @mountPoint: which mount point to trim
- * @minimum: Minimum contiguous free range to discard in bytes
- * @flags: extra flags, not used yet, so callers should always pass 0
- *
- * Calls FITRIM within the guest (hence guest agent may be
- * required depending on hypervisor used). Either call it on each
- * mounted filesystem (@mountPoint is NULL) or just on specified
- * @mountPoint. @minimum hints that free ranges smaller than this
- * may be ignored (this is a hint and the guest may not respect
- * it).  By increasing this value, the fstrim operation will
- * complete more quickly for filesystems with badly fragmented
- * free space, although not all blocks will be discarded.
- * If @minimum is not zero, the command may fail.
- *
- * Returns 0 on success, -1 otherwise.
+ * Returns -1 on error, 0 on success, 1 when remote party doesn't support
+ * keepalive messages.
  */
 int
-virDomainFSTrim(virDomainPtr dom,
-                const char *mountPoint,
-                unsigned long long minimum,
-                unsigned int flags)
+virConnectSetKeepAlive(virConnectPtr conn,
+                       int interval,
+                       unsigned int count)
 {
-    VIR_DOMAIN_DEBUG(dom, "mountPoint=%s, minimum=%llu, flags=%x",
-                     mountPoint, minimum, flags);
+    int ret = -1;
+
+    VIR_DEBUG("conn=%p, interval=%d, count=%u", conn, interval, count);
 
     virResetLastError();
 
-    virCheckDomainReturn(dom, -1);
-    virCheckReadOnlyGoto(dom->conn->flags, error);
+    virCheckConnectReturn(conn, -1);
 
-    if (dom->conn->driver->domainFSTrim) {
-        int ret = dom->conn->driver->domainFSTrim(dom, mountPoint,
-                                                  minimum, flags);
+    if (conn->driver->connectSetKeepAlive) {
+        ret = conn->driver->connectSetKeepAlive(conn, interval, count);
         if (ret < 0)
             goto error;
         return ret;
@@ -13362,185 +2594,200 @@ virDomainFSTrim(virDomainPtr dom,
     virReportUnsupportedError();
 
  error:
-    virDispatchError(dom->conn);
+    virDispatchError(conn);
     return -1;
 }
 
+
 /**
- * virDomainFSFreeze:
- * @dom: a domain object
- * @mountpoints: list of mount points to be frozen
- * @nmountpoints: the number of mount points specified in @mountpoints
- * @flags: extra flags; not used yet, so callers should always pass 0
+ * virConnectIsAlive:
+ * @conn: pointer to the connection object
  *
- * Freeze specified filesystems within the guest (hence guest agent
- * may be required depending on hypervisor used). If @mountpoints is NULL and
- * @nmountpoints is 0, every mounted filesystem on the guest is frozen.
- * In some environments (e.g. QEMU guest with guest agent which doesn't
- * support mountpoints argument), @mountpoints may need to be NULL.
+ * Determine if the connection to the hypervisor is still alive
+ *
+ * A connection will be classed as alive if it is either local, or running
+ * over a channel (TCP or UNIX socket) which is not closed.
  *
- * Returns the number of frozen filesystems on success, -1 otherwise.
+ * Returns 1 if alive, 0 if dead, -1 on error
  */
 int
-virDomainFSFreeze(virDomainPtr dom,
-                  const char **mountpoints,
-                  unsigned int nmountpoints,
-                  unsigned int flags)
+virConnectIsAlive(virConnectPtr conn)
 {
-    VIR_DOMAIN_DEBUG(dom, "mountpoints=%p, nmountpoints=%d, flags=%x",
-                     mountpoints, nmountpoints, flags);
+    VIR_DEBUG("conn=%p", conn);
 
     virResetLastError();
 
-    virCheckDomainReturn(dom, -1);
-    virCheckReadOnlyGoto(dom->conn->flags, error);
-    if (nmountpoints)
-        virCheckNonNullArgGoto(mountpoints, error);
-    else
-        virCheckNullArgGoto(mountpoints, error);
-
-    if (dom->conn->driver->domainFSFreeze) {
-        int ret = dom->conn->driver->domainFSFreeze(
-            dom, mountpoints, nmountpoints, flags);
+    virCheckConnectReturn(conn, -1);
+    if (conn->driver->connectIsAlive) {
+        int ret;
+        ret = conn->driver->connectIsAlive(conn);
         if (ret < 0)
             goto error;
         return ret;
     }
 
     virReportUnsupportedError();
-
  error:
-    virDispatchError(dom->conn);
+    virDispatchError(conn);
     return -1;
 }
 
+
 /**
- * virDomainFSThaw:
- * @dom: a domain object
- * @mountpoints: list of mount points to be thawed
- * @nmountpoints: the number of mount points specified in @mountpoints
- * @flags: extra flags; not used yet, so callers should always pass 0
+ * virConnectRegisterCloseCallback:
+ * @conn: pointer to connection object
+ * @cb: callback to invoke upon close
+ * @opaque: user data to pass to @cb
+ * @freecb: callback to free @opaque
+ *
+ * Registers a callback to be invoked when the connection
+ * is closed. This callback is invoked when there is any
+ * condition that causes the socket connection to the
+ * hypervisor to be closed.
+ *
+ * This function is only applicable to hypervisor drivers
+ * which maintain a persistent open connection. Drivers
+ * which open a new connection for every operation will
+ * not invoke this.
  *
- * Thaw specified filesystems within the guest. If @mountpoints is NULL and
- * @nmountpoints is 0, every mounted filesystem on the guest is thawed.
- * In some drivers (e.g. QEMU driver), @mountpoints may need to be NULL.
+ * The @freecb must not invoke any other libvirt public
+ * APIs, since it is not called from a re-entrant safe
+ * context.
  *
- * Returns the number of thawed filesystems on success, -1 otherwise.
+ * Returns 0 on success, -1 on error
  */
 int
-virDomainFSThaw(virDomainPtr dom,
-                const char **mountpoints,
-                unsigned int nmountpoints,
-                unsigned int flags)
+virConnectRegisterCloseCallback(virConnectPtr conn,
+                                virConnectCloseFunc cb,
+                                void *opaque,
+                                virFreeCallback freecb)
 {
-    VIR_DOMAIN_DEBUG(dom, "flags=%x", flags);
+    VIR_DEBUG("conn=%p", conn);
 
     virResetLastError();
 
-    virCheckDomainReturn(dom, -1);
-    virCheckReadOnlyGoto(dom->conn->flags, error);
-    if (nmountpoints)
-        virCheckNonNullArgGoto(mountpoints, error);
-    else
-        virCheckNullArgGoto(mountpoints, error);
+    virCheckConnectReturn(conn, -1);
 
-    if (dom->conn->driver->domainFSThaw) {
-        int ret = dom->conn->driver->domainFSThaw(
-            dom, mountpoints, nmountpoints, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
+    virObjectRef(conn);
+
+    virMutexLock(&conn->lock);
+    virObjectLock(conn->closeCallback);
+
+    virCheckNonNullArgGoto(cb, error);
+
+    if (conn->closeCallback->callback) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("A close callback is already registered"));
+        goto error;
     }
 
-    virReportUnsupportedError();
+    conn->closeCallback->conn = conn;
+    conn->closeCallback->callback = cb;
+    conn->closeCallback->opaque = opaque;
+    conn->closeCallback->freeCallback = freecb;
+
+    virObjectUnlock(conn->closeCallback);
+    virMutexUnlock(&conn->lock);
+
+    return 0;
 
  error:
-    virDispatchError(dom->conn);
+    virObjectUnlock(conn->closeCallback);
+    virMutexUnlock(&conn->lock);
+    virDispatchError(conn);
+    virObjectUnref(conn);
     return -1;
 }
 
+
 /**
- * virDomainGetTime:
- * @dom: a domain object
- * @seconds: domain's time in seconds
- * @nseconds: the nanoscond part of @seconds
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Extract information about guest time and store it into
- * @seconds and @nseconds. The @seconds represents the number of
- * seconds since the UNIX Epoch of 1970-01-01 00:00:00 in UTC.
+ * virConnectUnregisterCloseCallback:
+ * @conn: pointer to connection object
+ * @cb: pointer to the current registered callback
  *
- * Please note that some hypervisors may require guest agent to
- * be configured and running in order to run this API.
+ * Unregisters the callback previously set with the
+ * virConnectRegisterCloseCallback method. The callback
+ * will no longer receive notifications when the connection
+ * closes. If a virFreeCallback was provided at time of
+ * registration, it will be invoked
  *
- * Returns 0 on success, -1 otherwise.
+ * Returns 0 on success, -1 on error
  */
 int
-virDomainGetTime(virDomainPtr dom,
-                 long long *seconds,
-                 unsigned int *nseconds,
-                 unsigned int flags)
+virConnectUnregisterCloseCallback(virConnectPtr conn,
+                                  virConnectCloseFunc cb)
 {
-    VIR_DOMAIN_DEBUG(dom, "seconds=%p, nseconds=%p, flags=%x",
-                     seconds, nseconds, flags);
+    VIR_DEBUG("conn=%p", conn);
 
     virResetLastError();
 
-    virCheckDomainReturn(dom, -1);
+    virCheckConnectReturn(conn, -1);
 
-    if (dom->conn->driver->domainGetTime) {
-        int ret = dom->conn->driver->domainGetTime(dom, seconds,
-                                                   nseconds, flags);
-        if (ret < 0)
-            goto error;
-        return ret;
+    virMutexLock(&conn->lock);
+    virObjectLock(conn->closeCallback);
+
+    virCheckNonNullArgGoto(cb, error);
+
+    if (conn->closeCallback->callback != cb) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("A different callback was requested"));
+        goto error;
     }
 
-    virReportUnsupportedError();
+    conn->closeCallback->callback = NULL;
+    if (conn->closeCallback->freeCallback)
+        conn->closeCallback->freeCallback(conn->closeCallback->opaque);
+    conn->closeCallback->freeCallback = NULL;
+
+    virObjectUnref(conn);
+    virObjectUnlock(conn->closeCallback);
+    virMutexUnlock(&conn->lock);
+
+    return 0;
 
  error:
-    virDispatchError(dom->conn);
+    virObjectUnlock(conn->closeCallback);
+    virMutexUnlock(&conn->lock);
+    virDispatchError(conn);
     return -1;
 }
 
+
 /**
- * virDomainSetTime:
- * @dom: a domain object
- * @seconds: time to set
- * @nseconds: the nanosecond part of @seconds
- * @flags: bitwise-OR of virDomainSetTimeFlags
- *
- * When a domain is suspended or restored from a file the
- * domain's OS has no idea that there was a big gap in the time.
- * Depending on how long the gap was, NTP might not be able to
- * resynchronize the guest.
- *
- * This API tries to set guest time to the given value. The time
- * to set (@seconds and @nseconds) should be in seconds relative
- * to the Epoch of 1970-01-01 00:00:00 in UTC.
+ * virNodeGetCPUMap:
+ * @conn: pointer to the hypervisor connection
+ * @cpumap: optional pointer to a bit map of real CPUs on the host node
+ *      (in 8-bit bytes) (OUT)
+ *      In case of success each bit set to 1 means that corresponding
+ *      CPU is online.
+ *      Bytes are stored in little-endian order: CPU0-7, 8-15...
+ *      In each byte, lowest CPU number is least significant bit.
+ *      The bit map is allocated by virNodeGetCPUMap and needs
+ *      to be released using free() by the caller.
+ * @online: optional number of online CPUs in cpumap (OUT)
+ *      Contains the number of online CPUs if the call was successful.
+ * @flags: extra flags; not used yet, so callers should always pass 0
  *
- * Please note that some hypervisors may require guest agent to
- * be configured and running in order to be able to run this API.
+ * Get CPU map of host node CPUs.
  *
- * Returns 0 on success, -1 otherwise.
+ * Returns number of CPUs present on the host node,
+ * or -1 if there was an error.
  */
 int
-virDomainSetTime(virDomainPtr dom,
-                 long long seconds,
-                 unsigned int nseconds,
+virNodeGetCPUMap(virConnectPtr conn,
+                 unsigned char **cpumap,
+                 unsigned int *online,
                  unsigned int flags)
 {
-    VIR_DOMAIN_DEBUG(dom, "seconds=%lld, nseconds=%u, flags=%x",
-                     seconds, nseconds, flags);
+    VIR_DEBUG("conn=%p, cpumap=%p, online=%p, flags=%x",
+              conn, cpumap, online, flags);
 
     virResetLastError();
 
-    virCheckDomainReturn(dom, -1);
-    virCheckReadOnlyGoto(dom->conn->flags, error);
+    virCheckConnectReturn(conn, -1);
 
-    if (dom->conn->driver->domainSetTime) {
-        int ret = dom->conn->driver->domainSetTime(dom, seconds,
-                                                   nseconds, flags);
+    if (conn->driver->nodeGetCPUMap) {
+        int ret = conn->driver->nodeGetCPUMap(conn, cpumap, online, flags);
         if (ret < 0)
             goto error;
         return ret;
@@ -13549,7 +2796,7 @@ virDomainSetTime(virDomainPtr dom,
     virReportUnsupportedError();
 
  error:
-    virDispatchError(dom->conn);
+    virDispatchError(conn);
     return -1;
 }
 
@@ -13650,339 +2897,6 @@ virNodeGetFreePages(virConnectPtr conn,
 
 
 /**
- * virConnectGetDomainCapabilities:
- * @conn: pointer to the hypervisor connection
- * @emulatorbin: path to emulator
- * @arch: domain architecture
- * @machine: machine type
- * @virttype: virtualization type
- * @flags: extra flags; not used yet, so callers should always pass 0
- *
- * Prior creating a domain (for instance via virDomainCreateXML
- * or virDomainDefineXML) it may be suitable to know what the
- * underlying emulator and/or libvirt is capable of. For
- * instance, if host, libvirt and qemu is capable of VFIO
- * passthrough and so on.
- *
- * Returns NULL in case of error or an XML string
- * defining the capabilities.
- */
-char *
-virConnectGetDomainCapabilities(virConnectPtr conn,
-                                const char *emulatorbin,
-                                const char *arch,
-                                const char *machine,
-                                const char *virttype,
-                                unsigned int flags)
-{
-    VIR_DEBUG("conn=%p, emulatorbin=%s, arch=%s, "
-              "machine=%s, virttype=%s, flags=%x",
-              conn, NULLSTR(emulatorbin), NULLSTR(arch),
-              NULLSTR(machine), NULLSTR(virttype), flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, NULL);
-
-    if (conn->driver->connectGetDomainCapabilities) {
-        char *ret;
-        ret = conn->driver->connectGetDomainCapabilities(conn, emulatorbin,
-                                                         arch, machine,
-                                                         virttype, flags);
-        if (!ret)
-            goto error;
-        VIR_DEBUG("conn=%p, ret=%s", conn, ret);
-        return ret;
-    }
-
-    virReportUnsupportedError();
-
- error:
-    virDispatchError(conn);
-    return NULL;
-}
-
-
-/**
- * virConnectGetAllDomainStats:
- * @conn: pointer to the hypervisor connection
- * @stats: stats to return, binary-OR of virDomainStatsTypes
- * @retStats: Pointer that will be filled with the array of returned stats
- * @flags: extra flags; binary-OR of virConnectGetAllDomainStatsFlags
- *
- * Query statistics for all domains on a given connection.
- *
- * Report statistics of various parameters for a running VM according to @stats
- * field. The statistics are returned as an array of structures for each queried
- * domain. The structure contains an array of typed parameters containing the
- * individual statistics. The typed parameter name for each statistic field
- * consists of a dot-separated string containing name of the requested group
- * followed by a group specific description of the statistic value.
- *
- * The statistic groups are enabled using the @stats parameter which is a
- * binary-OR of enum virDomainStatsTypes. The following groups are available
- * (although not necessarily implemented for each hypervisor):
- *
- * VIR_DOMAIN_STATS_STATE: Return domain state and reason for entering that
- * state. The typed parameter keys are in this format:
- * "state.state" - state of the VM, returned as int from virDomainState enum
- * "state.reason" - reason for entering given state, returned as int from
- *                  virDomain*Reason enum corresponding to given state.
- *
- * VIR_DOMAIN_STATS_CPU_TOTAL: Return CPU statistics and usage information.
- * The typed parameter keys are in this format:
- * "cpu.time" - total cpu time spent for this domain in nanoseconds
- *              as unsigned long long.
- * "cpu.user" - user cpu time spent in nanoseconds as unsigned long long.
- * "cpu.system" - system cpu time spent in nanoseconds as unsigned long long.
- *
- * VIR_DOMAIN_STATS_BALLOON: Return memory balloon device information.
- * The typed parameter keys are in this format:
- * "balloon.current" - the memory in kiB currently used
- *                     as unsigned long long.
- * "balloon.maximum" - the maximum memory in kiB allowed
- *                     as unsigned long long.
- *
- * VIR_DOMAIN_STATS_VCPU: Return virtual CPU statistics.
- * Due to VCPU hotplug, the vcpu.<num>.* array could be sparse.
- * The actual size of the array corresponds to "vcpu.current".
- * The array size will never exceed "vcpu.maximum".
- * The typed parameter keys are in this format:
- * "vcpu.current" - current number of online virtual CPUs as unsigned int.
- * "vcpu.maximum" - maximum number of online virtual CPUs as unsigned int.
- * "vcpu.<num>.state" - state of the virtual CPU <num>, as int
- *                      from virVcpuState enum.
- * "vcpu.<num>.time" - virtual cpu time spent by virtual CPU <num>
- *                     as unsigned long long.
- *
- * VIR_DOMAIN_STATS_INTERFACE: Return network interface statistics.
- * The typed parameter keys are in this format:
- * "net.count" - number of network interfaces on this domain
- *               as unsigned int.
- * "net.<num>.name" - name of the interface <num> as string.
- * "net.<num>.rx.bytes" - bytes received as unsigned long long.
- * "net.<num>.rx.pkts" - packets received as unsigned long long.
- * "net.<num>.rx.errs" - receive errors as unsigned long long.
- * "net.<num>.rx.drop" - receive packets dropped as unsigned long long.
- * "net.<num>.tx.bytes" - bytes transmitted as unsigned long long.
- * "net.<num>.tx.pkts" - packets transmitted as unsigned long long.
- * "net.<num>.tx.errs" - transmission errors as unsigned long long.
- * "net.<num>.tx.drop" - transmit packets dropped as unsigned long long.
- *
- * VIR_DOMAIN_STATS_BLOCK: Return block devices statistics.
- * The typed parameter keys are in this format:
- * "block.count" - number of block devices on this domain
- *                 as unsigned int.
- * "block.<num>.name" - name of the block device <num> as string.
- *                      matches the target name (vda/sda/hda) of the
- *                      block device.
- * "block.<num>.rd.reqs" - number of read requests as unsigned long long.
- * "block.<num>.rd.bytes" - number of read bytes as unsigned long long.
- * "block.<num>.rd.times" - total time (ns) spent on reads as
- *                          unsigned long long.
- * "block.<num>.wr.reqs" - number of write requests as unsigned long long.
- * "block.<num>.wr.bytes" - number of written bytes as unsigned long long.
- * "block.<num>.wr.times" - total time (ns) spent on writes as
- *                          unsigned long long.
- * "block.<num>.fl.reqs" - total flush requests as unsigned long long.
- * "block.<num>.fl.times" - total time (ns) spent on cache flushing as
- *                          unsigned long long.
- * "block.<num>.errors" - Xen only: the 'oo_req' value as
- *                        unsigned long long.
- * "block.<num>.allocation" - offset of the highest written sector
- *                            as unsigned long long.
- * "block.<num>.capacity" - logical size in bytes of the block device backing
- *                          image as unsigned long long.
- * "block.<num>.physical" - physical size in bytes of the container of the
- *                          backing image as unsigned long long.
- *
- * Note that entire stats groups or individual stat fields may be missing from
- * the output in case they are not supported by the given hypervisor, are not
- * applicable for the current state of the guest domain, or their retrieval
- * was not successful.
- *
- * Using 0 for @stats returns all stats groups supported by the given
- * hypervisor.
- *
- * Specifying VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS as @flags makes
- * the function return error in case some of the stat types in @stats were
- * not recognized by the daemon.
- *
- * Similarly to virConnectListAllDomains, @flags can contain various flags to
- * filter the list of domains to provide stats for.
- *
- * VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE selects online domains while
- * VIR_CONNECT_GET_ALL_DOMAINS_STATS_INACTIVE selects offline ones.
- *
- * VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT and
- * VIR_CONNECT_GET_ALL_DOMAINS_STATS_TRANSIENT allow to filter the list
- * according to their persistence.
- *
- * To filter the list of VMs by domain state @flags can contain
- * VIR_CONNECT_GET_ALL_DOMAINS_STATS_RUNNING,
- * VIR_CONNECT_GET_ALL_DOMAINS_STATS_PAUSED,
- * VIR_CONNECT_GET_ALL_DOMAINS_STATS_SHUTOFF and/or
- * VIR_CONNECT_GET_ALL_DOMAINS_STATS_OTHER for all other states.
- *
- * Returns the count of returned statistics structures on success, -1 on error.
- * The requested data are returned in the @retStats parameter. The returned
- * array should be freed by the caller. See virDomainStatsRecordListFree.
- */
-int
-virConnectGetAllDomainStats(virConnectPtr conn,
-                            unsigned int stats,
-                            virDomainStatsRecordPtr **retStats,
-                            unsigned int flags)
-{
-    int ret = -1;
-
-    VIR_DEBUG("conn=%p, stats=0x%x, retStats=%p, flags=0x%x",
-              conn, stats, retStats, flags);
-
-    virResetLastError();
-
-    virCheckConnectReturn(conn, -1);
-    virCheckNonNullArgGoto(retStats, cleanup);
-
-    if (!conn->driver->connectGetAllDomainStats) {
-        virReportUnsupportedError();
-        goto cleanup;
-    }
-
-    ret = conn->driver->connectGetAllDomainStats(conn, NULL, 0, stats,
-                                                 retStats, flags);
-
- cleanup:
-    if (ret < 0)
-        virDispatchError(conn);
-
-    return ret;
-}
-
-
-/**
- * virDomainListGetStats:
- * @doms: NULL terminated array of domains
- * @stats: stats to return, binary-OR of virDomainStatsTypes
- * @retStats: Pointer that will be filled with the array of returned stats
- * @flags: extra flags; binary-OR of virConnectGetAllDomainStatsFlags
- *
- * Query statistics for domains provided by @doms. Note that all domains in
- * @doms must share the same connection.
- *
- * Report statistics of various parameters for a running VM according to @stats
- * field. The statistics are returned as an array of structures for each queried
- * domain. The structure contains an array of typed parameters containing the
- * individual statistics. The typed parameter name for each statistic field
- * consists of a dot-separated string containing name of the requested group
- * followed by a group specific description of the statistic value.
- *
- * The statistic groups are enabled using the @stats parameter which is a
- * binary-OR of enum virDomainStatsTypes. The stats groups are documented
- * in virConnectGetAllDomainStats.
- *
- * Using 0 for @stats returns all stats groups supported by the given
- * hypervisor.
- *
- * Specifying VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS as @flags makes
- * the function return error in case some of the stat types in @stats were
- * not recognized by the daemon.
- *
- * Note that any of the domain list filtering flags in @flags will be rejected
- * by this function.
- *
- * Returns the count of returned statistics structures on success, -1 on error.
- * The requested data are returned in the @retStats parameter. The returned
- * array should be freed by the caller. See virDomainStatsRecordListFree.
- * Note that the count of returned stats may be less than the domain count
- * provided via @doms.
- */
-int
-virDomainListGetStats(virDomainPtr *doms,
-                      unsigned int stats,
-                      virDomainStatsRecordPtr **retStats,
-                      unsigned int flags)
-{
-    virConnectPtr conn = NULL;
-    virDomainPtr *nextdom = doms;
-    unsigned int ndoms = 0;
-    int ret = -1;
-
-    VIR_DEBUG("doms=%p, stats=0x%x, retStats=%p, flags=0x%x",
-              doms, stats, retStats, flags);
-
-    virResetLastError();
-
-    virCheckNonNullArgGoto(doms, cleanup);
-    virCheckNonNullArgGoto(retStats, cleanup);
-
-    if (!*doms) {
-        virReportError(VIR_ERR_INVALID_ARG,
-                       _("doms array in %s must contain at least one domain"),
-                       __FUNCTION__);
-        goto cleanup;
-    }
-
-    conn = doms[0]->conn;
-    virCheckConnectReturn(conn, -1);
-
-    if (!conn->driver->connectGetAllDomainStats) {
-        virReportUnsupportedError();
-        goto cleanup;
-    }
-
-    while (*nextdom) {
-        virDomainPtr dom = *nextdom;
-
-        virCheckDomainGoto(dom, cleanup);
-
-        if (dom->conn != conn) {
-            virReportError(VIR_ERR_INVALID_ARG,
-                           _("domains in 'doms' array must belong to a "
-                             "single connection in %s"), __FUNCTION__);
-            goto cleanup;
-        }
-
-        ndoms++;
-        nextdom++;
-    }
-
-    ret = conn->driver->connectGetAllDomainStats(conn, doms, ndoms,
-                                                 stats, retStats, flags);
-
- cleanup:
-    if (ret < 0)
-        virDispatchError(conn);
-    return ret;
-}
-
-
-/**
- * virDomainStatsRecordListFree:
- * @stats: NULL terminated array of virDomainStatsRecords to free
- *
- * Convenience function to free a list of domain stats returned by
- * virDomainListGetStats and virConnectGetAllDomainStats.
- */
-void
-virDomainStatsRecordListFree(virDomainStatsRecordPtr *stats)
-{
-    virDomainStatsRecordPtr *next;
-
-    if (!stats)
-        return;
-
-    for (next = stats; *next; next++) {
-        virTypedParamsFree((*next)->params, (*next)->nparams);
-        virDomainFree((*next)->dom);
-        VIR_FREE(*next);
-    }
-
-    VIR_FREE(stats);
-}
-
-
-/**
  * virNodeAllocPages:
  * @conn: pointer to the hypervisor connection
  * @npages: number of items in the @pageSizes and
diff --git a/src/libvirt_internal.h b/src/libvirt_internal.h
index ebf2acf..304d90f 100644
--- a/src/libvirt_internal.h
+++ b/src/libvirt_internal.h
@@ -285,4 +285,10 @@ int virDomainMigrateConfirm3Params(virDomainPtr domain,
                                    int cookieinlen,
                                    unsigned int flags,
                                    int cancelled);
+
+int
+virTypedParameterValidateSet(virConnectPtr conn,
+                             virTypedParameterPtr params,
+                             int nparams);
+
 #endif
-- 
2.1.0




More information about the libvir-list mailing list