[libvirt] PATCH: Thread-safe error reporting public API

Daniel P. Berrange berrange at redhat.com
Thu Dec 11 20:16:36 UTC 2008


The current public API for error reporting consists of 

 - A global error object
 - A per-connection error object

Some functions always set errors on the global object. Other functions
always set errors on the per-connection object, except when they set 
errors on the global object. Both have built-in race conditions if they
are accessed from multiple threads because of the time between the API
call raising the error, and the caller querying it.

The solution to this is to do away with all of the existing error objects
and replace them with a per-thread error object. Well, except we can't
do away with existing objects because of ABI compatability. This turns
out to not be such a bad problem after all....

So with this patch...


virterror.c gets ability to track a per-thread virErrorPtr instance. This
object is stored in a thread local variable via pthread_{get,set}specific.
It is allocated when first required, and deleted when the thread exits

Every single API will *always* set the  virErrorPtr object associated with
its current thread.

In the public virterror.h we add

  virErrorPtr             virThreadGetLastError (void);
  int                     virThreadCopyLastError (virErrorPtr to);
  void                    virThreadResetLastError (void);

This provides a guarenteed thread-safe public API for fetching error
information. All the other existing APIs have docs updated to recommend
against their use.

In libvirt.c, in any exit paths which result in an error code, we copy
the per-thread virErrorPtr object into either the global error object
or per-connection object as applicable for the scenario. This gives us
100% backwards compatability. NB, we hold a lock when doing this so
that these are race-free when setting them.

At the start of every API call, we call virThreadResetLastError() and
at any exit path with an error, if the error object is not set, then
we set a generic error message. This means that if the internal driver
code is broken and forgets to raise an error, the caller will still
at least see a generic error report.

Finally, virCopyLastError and virConnCopyLastError were not correctly
strdup'ing the char * fields. This meant that if the original error
was cleared, you'd get a use-after-free error, shortly followed by
a double-free error if the first didn't kill you. This patch also
fixes those two methods to correctly strdup the char *.

As for language bindings, they should *all* be updated to use the
virThreadGetLastError() method, and *never* call virGetLastError()
or the virConnGetLastError() calls.

With this patch applied, assuming all the per-hypervisor drivers are
thread-safe (they are except for Xen which is still TODO), then the 
public API for virConectPtr is also (almost[1]) guarenteed to be thread-
safe.

 include/libvirt/virterror.h |    7 
 src/datatypes.c             |   11 
 src/datatypes.h             |   15 
 src/libvirt.c               | 3729 ++++++++++++++++++++++++++++++--------------
 src/libvirt_sym.version.in  |    8 
 src/virterror.c             |  281 +++
 src/virterror_internal.h    |    4 
 7 files changed, 2902 insertions(+), 1153 deletions(-)


Daniel

[1] We need to fix lots of stupid internal mistakes like strerror()
    vs strerror_r() - these were already a problem even with libvirt
    being single-threaded on virConnectPtr, because the app using
    libvirt could be threaded. More on this later...


diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -187,6 +187,13 @@ void			virConnSetErrorFunc	(virConnectPt
                                                  virErrorFunc handler);
 int			virConnCopyLastError	(virConnectPtr conn,
                                                  virErrorPtr to);
+
+
+virErrorPtr             virThreadGetLastError (void);
+int                     virThreadCopyLastError (virErrorPtr to);
+void                    virThreadResetLastError (void);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/datatypes.c b/src/datatypes.c
--- a/src/datatypes.c
+++ b/src/datatypes.c
@@ -192,8 +192,6 @@ virReleaseConnect(virConnectPtr conn) {
         virHashFree(conn->nodeDevices, (virHashDeallocator) virNodeDeviceFree);
 
     virResetError(&conn->err);
-    if (virLastErr.conn == conn)
-        virLastErr.conn = NULL;
 
     xmlFreeURI(conn->uri);
 
@@ -320,10 +318,6 @@ virReleaseDomain(virDomainPtr domain) {
         virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
                         _("domain missing from connection hash table"));
 
-    if (conn->err.dom == domain)
-        conn->err.dom = NULL;
-    if (virLastErr.dom == domain)
-        virLastErr.dom = NULL;
     domain->magic = -1;
     domain->id = -1;
     VIR_FREE(domain->name);
@@ -456,11 +450,6 @@ virReleaseNetwork(virNetworkPtr network)
         virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
                         _("network missing from connection hash table"));
 
-    if (conn->err.net == network)
-        conn->err.net = NULL;
-    if (virLastErr.net == network)
-        virLastErr.net = NULL;
-
     network->magic = -1;
     VIR_FREE(network->name);
     VIR_FREE(network);
diff --git a/src/datatypes.h b/src/datatypes.h
--- a/src/datatypes.h
+++ b/src/datatypes.h
@@ -95,6 +95,10 @@
  * Internal structure associated to a connection
  */
 struct _virConnect {
+    /* All the variables from here, until the 'lock' declaration
+     * are setup at time of connection open, and never changed
+     * since. Thus no need to lock when accessing them
+     */
     unsigned int magic;     /* specific value to check */
     int flags;              /* a set of connection flags */
     xmlURIPtr uri;          /* connection URI */
@@ -114,11 +118,6 @@ struct _virConnect {
     void *            storagePrivateData;
     void *            devMonPrivateData;
 
-    /* Per-connection error. */
-    virError err;           /* the last error */
-    virErrorFunc handler;   /* associated handlet */
-    void *userData;         /* the user data */
-
     /*
      * The lock mutex must be acquired before accessing/changing
      * any of members following this point, or changing the ref
@@ -126,6 +125,12 @@ struct _virConnect {
      * this connection
      */
     PTHREAD_MUTEX_T (lock);
+
+    /* Per-connection error. */
+    virError err;           /* the last error */
+    virErrorFunc handler;   /* associated handlet */
+    void *userData;         /* the user data */
+
     virHashTablePtr domains;  /* hash table for known domains */
     virHashTablePtr networks; /* hash table for known domains */
     virHashTablePtr storagePools;/* hash table for known storage pools */
diff --git a/src/libvirt.c b/src/libvirt.c
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -778,6 +778,8 @@ virGetVersion(unsigned long *libVer, con
 #endif
         if (*typeVer == 0) {
             virLibConnError(NULL, VIR_ERR_NO_SUPPORT, type);
+            /* Copy to global error object for back compatability */
+            virThreadSetGlobalError();
             return (-1);
         }
     }
@@ -791,6 +793,8 @@ do_open (const char *name,
 {
     int i, res;
     virConnectPtr ret;
+
+    virThreadResetLastError();
 
     ret = virGetConnect();
     if (ret == NULL)
@@ -945,17 +949,8 @@ failed:
 failed:
     if (ret->driver) ret->driver->close (ret);
 
-    /* If no global error was set, copy any error set
-       in the connection object we're about to dispose of */
-    if (virLastErr.code == VIR_ERR_OK) {
-        memcpy(&virLastErr, &ret->err, sizeof(ret->err));
-        memset(&ret->err, 0, sizeof(ret->err));
-    }
-
-    /* Still no error set, then raise a generic error */
-    if (virLastErr.code == VIR_ERR_OK)
-        virLibConnError (NULL, VIR_ERR_INTERNAL_ERROR,
-                         _("unable to open connection"));
+    /* Copy to global error object for back compatability */
+    virThreadSetGlobalError();
 
     virUnrefConnect(ret);
 
@@ -1050,8 +1045,16 @@ virConnectClose(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn))
-        return (-1);
+    virThreadResetLastError();
+
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
 
     if (conn->networkDriver)
         conn->networkDriver->close (conn);
@@ -1061,8 +1064,11 @@ virConnectClose(virConnectPtr conn)
         conn->deviceMonitor->close (conn);
     conn->driver->close (conn);
 
-    if (virUnrefConnect(conn) < 0)
-        return (-1);
+    if (virUnrefConnect(conn) < 0) {
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
     return (0);
 }
 
@@ -1073,12 +1079,22 @@ int
 int
 virDrvSupportsFeature (virConnectPtr conn, int feature)
 {
+    int ret;
     DEBUG("conn=%p, feature=%d", conn, feature);
 
-    if (!VIR_IS_CONNECT(conn))
-        return (-1);
-
-    return VIR_DRV_SUPPORTS_FEATURE (conn->driver, conn, feature);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    ret = VIR_DRV_SUPPORTS_FEATURE (conn->driver, conn, feature);
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return ret;
 }
 
 /**
@@ -1098,8 +1114,12 @@ virConnectGetType(virConnectPtr conn)
     const char *ret;
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
 
@@ -1128,20 +1148,32 @@ virConnectGetVersion(virConnectPtr conn,
 {
     DEBUG("conn=%p, hvVer=%p", conn, hvVer);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
     }
 
     if (hvVer == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->version)
-        return conn->driver->version (conn, hvVer);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->version) {
+        int ret = conn->driver->version (conn, hvVer);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -1162,15 +1194,27 @@ virConnectGetHostname (virConnectPtr con
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return NULL;
-    }
-
-    if (conn->driver->getHostname)
-        return conn->driver->getHostname (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return NULL;
+    }
+
+    if (conn->driver->getHostname) {
+        char *ret = conn->driver->getHostname (conn);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -1193,26 +1237,37 @@ virConnectGetURI (virConnectPtr conn)
 virConnectGetURI (virConnectPtr conn)
 {
     char *name;
-
-    DEBUG("conn=%p", conn);
-
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    DEBUG("conn=%p", conn);
+
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
 
     /* Drivers may override getURI, but if they don't then
      * we provide a default implementation.
      */
-    if (conn->driver->getURI)
-        return conn->driver->getURI (conn);
+    if (conn->driver->getURI) {
+        name = conn->driver->getURI (conn);
+        if (!name)
+            goto error;
+    }
 
     name = (char *)xmlSaveUri(conn->uri);
     if (!name) {
         virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__);
-        return NULL;
+        goto error;
     }
     return name;
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return NULL;
 }
 
 /**
@@ -1232,15 +1287,26 @@ virConnectGetMaxVcpus(virConnectPtr conn
 {
     DEBUG("conn=%p, type=%s", conn, type);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->getMaxVcpus)
-        return conn->driver->getMaxVcpus (conn, type);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
+
+    if (conn->driver->getMaxVcpus) {
+        int ret = conn->driver->getMaxVcpus (conn, type);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -1259,20 +1325,31 @@ virConnectListDomains(virConnectPtr conn
 {
     DEBUG("conn=%p, ids=%p, maxids=%d", conn, ids, maxids);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
     }
 
     if ((ids == NULL) || (maxids < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->listDomains)
-        return conn->driver->listDomains (conn, ids, maxids);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->listDomains) {
+        int ret = conn->driver->listDomains (conn, ids, maxids);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -1289,15 +1366,26 @@ virConnectNumOfDomains(virConnectPtr con
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->numOfDomains)
-        return conn->driver->numOfDomains (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        goto error;
+    }
+
+    if (conn->driver->numOfDomains) {
+        int ret = conn->driver->numOfDomains (conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -1320,8 +1408,12 @@ virDomainGetConnect (virDomainPtr dom)
 {
     DEBUG("dom=%p", dom);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_DOMAIN (dom)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
     return dom->conn;
@@ -1348,23 +1440,35 @@ virDomainCreateXML(virConnectPtr conn, c
 {
     DEBUG("conn=%p, xmlDesc=%s, flags=%d", conn, xmlDesc, flags);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (xmlDesc == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
     if (conn->flags & VIR_CONNECT_RO) {
         virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->driver->domainCreateXML)
-        return conn->driver->domainCreateXML (conn, xmlDesc, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainCreateXML) {
+        virDomainPtr ret;
+        ret = conn->driver->domainCreateXML (conn, xmlDesc, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -1404,19 +1508,32 @@ virDomainLookupByID(virConnectPtr conn, 
 {
     DEBUG("conn=%p, id=%d", conn, id);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (id < 0) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->driver->domainLookupByID)
-        return conn->driver->domainLookupByID (conn, id);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainLookupByID) {
+        virDomainPtr ret;
+        ret = conn->driver->domainLookupByID (conn, id);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -1435,19 +1552,32 @@ virDomainLookupByUUID(virConnectPtr conn
 {
     DEBUG("conn=%p, uuid=%s", conn, uuid);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (uuid == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->driver->domainLookupByUUID)
-        return conn->driver->domainLookupByUUID (conn, uuid);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainLookupByUUID) {
+        virDomainPtr ret;
+        ret = conn->driver->domainLookupByUUID (conn, uuid);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -1470,14 +1600,17 @@ virDomainLookupByUUIDString(virConnectPt
 
     DEBUG("conn=%p, uuidstr=%s", conn, uuidstr);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (uuidstr == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-
+        goto error;
     }
     /* XXX: sexpr_uuid() also supports 'xxxx-xxxx-xxxx-xxxx' format.
      *      We needn't it here. Right?
@@ -1495,12 +1628,17 @@ virDomainLookupByUUIDString(virConnectPt
 
     if (ret!=VIR_UUID_BUFLEN) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
     for (i = 0; i < VIR_UUID_BUFLEN; i++)
         uuid[i] = raw[i] & 0xFF;
 
     return virDomainLookupByUUID(conn, &uuid[0]);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return NULL;
 }
 
 /**
@@ -1518,19 +1656,32 @@ virDomainLookupByName(virConnectPtr conn
 {
     DEBUG("conn=%p, name=%s", conn, name);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (name == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->driver->domainLookupByName)
-        return conn->driver->domainLookupByName (conn, name);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainLookupByName) {
+        virDomainPtr dom;
+        dom = conn->driver->domainLookupByName (conn, name);
+        if (!dom)
+            goto error;
+        return dom;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -1552,21 +1703,34 @@ virDomainDestroy(virDomainPtr domain)
 
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-    if (conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->domainDestroy)
-        return conn->driver->domainDestroy (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    conn = domain->conn;
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainDestroy) {
+        int ret;
+        ret = conn->driver->domainDestroy (domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -1584,12 +1748,18 @@ virDomainFree(virDomainPtr domain)
 {
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (virUnrefDomain(domain) < 0)
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (virUnrefDomain(domain) < 0) {
+        virThreadSetGlobalError();
+        return -1;
+    }
     return(0);
 }
 
@@ -1611,21 +1781,34 @@ virDomainSuspend(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainSuspend)
-        return conn->driver->domainSuspend (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainSuspend) {
+        int ret;
+        ret = conn->driver->domainSuspend (domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -1645,21 +1828,34 @@ virDomainResume(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainResume)
-        return conn->driver->domainResume (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainResume) {
+        int ret;
+        ret = conn->driver->domainResume (domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -1682,18 +1878,22 @@ virDomainSave(virDomainPtr domain, const
     virConnectPtr conn;
     DEBUG("domain=%p, to=%s", domain, to);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
     }
     conn = domain->conn;
     if (to == NULL) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     /*
@@ -1716,10 +1916,19 @@ virDomainSave(virDomainPtr domain, const
 
     }
 
-    if (conn->driver->domainSave)
-        return conn->driver->domainSave (domain, to);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->driver->domainSave) {
+        int ret;
+        ret = conn->driver->domainSave (domain, to);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -1738,17 +1947,21 @@ virDomainRestore(virConnectPtr conn, con
     char filepath[4096];
     DEBUG("conn=%p, from=%s", conn, from);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (conn->flags & VIR_CONNECT_RO) {
         virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
     if (from == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     /*
@@ -1759,21 +1972,36 @@ virDomainRestore(virConnectPtr conn, con
         unsigned int len, t;
 
         t = strlen(from);
-        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
-            return (-1);
+        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL) {
+            virLibConnError(conn, VIR_ERR_SYSTEM_ERROR,
+                            _("cannot get working directory"));
+            goto error;
+        }
         len = strlen(filepath);
         /* that should be covered by getcwd() semantic, but be 100% sure */
-        if (len > sizeof(filepath) - (t + 3))
-            return (-1);
+        if (len > sizeof(filepath) - (t + 3)) {
+            virLibConnError(conn, VIR_ERR_INTERNAL_ERROR,
+                            _("path too long"));
+            goto error;
+        }
         filepath[len] = '/';
         strcpy(&filepath[len + 1], from);
         from = &filepath[0];
     }
 
-    if (conn->driver->domainRestore)
-        return conn->driver->domainRestore (conn, from);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->driver->domainRestore) {
+        int ret;
+        ret = conn->driver->domainRestore (conn, from);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -1796,18 +2024,22 @@ virDomainCoreDump(virDomainPtr domain, c
     virConnectPtr conn;
     DEBUG("domain=%p, to=%s, flags=%d", domain, to, flags);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
     }
     conn = domain->conn;
     if (to == NULL) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     /*
@@ -1818,22 +2050,37 @@ virDomainCoreDump(virDomainPtr domain, c
         unsigned int len, t;
 
         t = strlen(to);
-        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
-            return (-1);
+        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL) {
+            virLibDomainError(domain, VIR_ERR_SYSTEM_ERROR,
+                              _("cannot get current directory"));
+            goto error;
+        }
         len = strlen(filepath);
         /* that should be covered by getcwd() semantic, but be 100% sure */
-        if (len > sizeof(filepath) - (t + 3))
-            return (-1);
+        if (len > sizeof(filepath) - (t + 3)) {
+            virLibDomainError(domain, VIR_ERR_INTERNAL_ERROR,
+                              _("path too long"));
+            goto error;
+        }
         filepath[len] = '/';
         strcpy(&filepath[len + 1], to);
         to = &filepath[0];
 
     }
 
-    if (conn->driver->domainCoreDump)
-        return conn->driver->domainCoreDump (domain, to, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->driver->domainCoreDump) {
+        int ret;
+        ret = conn->driver->domainCoreDump (domain, to, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -1856,21 +2103,34 @@ virDomainShutdown(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainShutdown)
-        return conn->driver->domainShutdown (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainShutdown) {
+        int ret;
+        ret = conn->driver->domainShutdown (domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -1891,21 +2151,34 @@ virDomainReboot(virDomainPtr domain, uns
     virConnectPtr conn;
     DEBUG("domain=%p, flags=%u", domain, flags);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainReboot)
-        return conn->driver->domainReboot (domain, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainReboot) {
+        int ret;
+        ret = conn->driver->domainReboot (domain, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -1923,8 +2196,12 @@ virDomainGetName(virDomainPtr domain)
 {
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     return (domain->name);
@@ -1944,12 +2221,18 @@ virDomainGetUUID(virDomainPtr domain, un
 {
     DEBUG("domain=%p, uuid=%p", domain, uuid);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (uuid == NULL) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetConnError(domain->conn);
         return (-1);
     }
 
@@ -1974,20 +2257,29 @@ virDomainGetUUIDString(virDomainPtr doma
     unsigned char uuid[VIR_UUID_BUFLEN];
     DEBUG("domain=%p, buf=%p", domain, buf);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (buf == NULL) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     if (virDomainGetUUID(domain, &uuid[0]))
-        return (-1);
+        goto error;
 
     virUUIDFormat(uuid, buf);
     return (0);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
+    return -1;
 }
 
 /**
@@ -2003,8 +2295,12 @@ virDomainGetID(virDomainPtr domain)
 {
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return ((unsigned int) -1);
     }
     return (domain->id);
@@ -2025,17 +2321,30 @@ virDomainGetOSType(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (NULL);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetOSType)
-        return conn->driver->domainGetOSType (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (NULL);
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetOSType) {
+        char *ret;
+        ret = conn->driver->domainGetOSType (domain);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return NULL;
 }
 
@@ -2055,17 +2364,30 @@ virDomainGetMaxMemory(virDomainPtr domai
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (0);
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainGetMaxMemory)
-        return conn->driver->domainGetMaxMemory (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->driver->domainGetMaxMemory) {
+        unsigned long ret;
+        ret = conn->driver->domainGetMaxMemory (domain);
+        if (ret == 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return 0;
 }
 
@@ -2087,28 +2409,37 @@ virDomainSetMaxMemory(virDomainPtr domai
     virConnectPtr conn;
     DEBUG("domain=%p, memory=%lu", domain, memory);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
     }
     if (memory < 4096) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainSetMaxMemory)
-        return conn->driver->domainSetMaxMemory (domain, memory);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainSetMaxMemory) {
+        int ret;
+        ret = conn->driver->domainSetMaxMemory (domain, memory);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -2130,29 +2461,38 @@ virDomainSetMemory(virDomainPtr domain, 
     virConnectPtr conn;
     DEBUG("domain=%p, memory=%lu", domain, memory);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
     }
     if (memory < 4096) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainSetMemory)
-        return conn->driver->domainSetMemory (domain, memory);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainSetMemory) {
+        int ret;
+        ret = conn->driver->domainSetMemory (domain, memory);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -2173,23 +2513,36 @@ virDomainGetInfo(virDomainPtr domain, vi
     virConnectPtr conn;
     DEBUG("domain=%p, info=%p", domain, info);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (info == NULL) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     memset(info, 0, sizeof(virDomainInfo));
 
     conn = domain->conn;
 
-    if (conn->driver->domainGetInfo)
-        return conn->driver->domainGetInfo (domain, info);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->driver->domainGetInfo) {
+        int ret;
+        ret = conn->driver->domainGetInfo (domain, info);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -2210,17 +2563,30 @@ virDomainGetXMLDesc(virDomainPtr domain,
     virConnectPtr conn;
     DEBUG("domain=%p, flags=%d", domain, flags);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (NULL);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainDumpXML)
-        return conn->driver->domainDumpXML (domain, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (NULL);
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainDumpXML) {
+        char *ret;
+        ret = conn->driver->domainDumpXML (domain, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return NULL;
 }
 
@@ -2289,14 +2655,18 @@ virDomainMigrate (virDomainPtr domain,
     DEBUG("domain=%p, dconn=%p, flags=%lu, dname=%s, uri=%s, bandwidth=%lu",
           domain, dconn, flags, dname, uri, bandwidth);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_DOMAIN (domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
     conn = domain->conn;        /* Source connection. */
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return NULL;
+        goto error;
     }
 
     /* Check that migration is supported by both drivers. */
@@ -2312,7 +2682,7 @@ virDomainMigrate (virDomainPtr domain,
         version = 2;
     else {
         virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-        return NULL;
+        goto error;
     }
 
     /* Prepare the migration.
@@ -2347,13 +2717,13 @@ virDomainMigrate (virDomainPtr domain,
          */
         if (!conn->driver->domainDumpXML) {
             virLibConnError (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
-            return NULL;
+            goto error;
         }
         dom_xml = conn->driver->domainDumpXML (domain,
                                                VIR_DOMAIN_XML_SECURE);
 
         if (!dom_xml)
-            return NULL;
+            goto error;
 
         ret = dconn->driver->domainMigratePrepare2
             (dconn, &cookie, &cookielen, uri, &uri_out, flags, dname,
@@ -2403,6 +2773,11 @@ virDomainMigrate (virDomainPtr domain,
     free (uri_out);
     free (cookie);
     return ddomain;
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
+    return NULL;
 }
 
 /*
@@ -2421,17 +2796,30 @@ virDomainMigratePrepare (virConnectPtr d
 {
     DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p, flags=%lu, dname=%s, bandwidth=%lu", dconn, cookie, cookielen, uri_in, uri_out, flags, dname, bandwidth);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return -1;
-    }
-
-    if (dconn->driver->domainMigratePrepare)
-        return dconn->driver->domainMigratePrepare (dconn, cookie, cookielen,
-                                                    uri_in, uri_out,
-                                                    flags, dname, bandwidth);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
+
+    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;
+    }
 
     virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dconn);
     return -1;
 }
 
@@ -2451,18 +2839,31 @@ virDomainMigratePerform (virDomainPtr do
     virConnectPtr conn;
     DEBUG("domain=%p, cookie=%p, cookielen=%d, uri=%s, flags=%lu, dname=%s, bandwidth=%lu", domain, cookie, cookielen, uri, flags, dname, bandwidth);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_DOMAIN (domain)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return -1;
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainMigratePerform)
-        return conn->driver->domainMigratePerform (domain, cookie, cookielen,
-                                                   uri,
-                                                   flags, dname, bandwidth);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainMigratePerform) {
+        int ret;
+        ret = conn->driver->domainMigratePerform (domain, cookie, cookielen,
+                                                  uri,
+                                                  flags, dname, bandwidth);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
 
     virLibDomainError (domain, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -2480,17 +2881,30 @@ virDomainMigrateFinish (virConnectPtr dc
 {
     DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, flags=%lu", dconn, dname, cookie, cookielen, uri, flags);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return NULL;
-    }
-
-    if (dconn->driver->domainMigrateFinish)
-        return dconn->driver->domainMigrateFinish (dconn, dname,
-                                                   cookie, cookielen,
-                                                   uri, flags);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return NULL;
+    }
+
+    if (dconn->driver->domainMigrateFinish) {
+        virDomainPtr ret;
+        ret = dconn->driver->domainMigrateFinish (dconn, dname,
+                                                  cookie, cookielen,
+                                                  uri, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dconn);
     return NULL;
 }
 
@@ -2512,18 +2926,31 @@ virDomainMigratePrepare2 (virConnectPtr 
 {
     DEBUG("dconn=%p, cookie=%p, cookielen=%p, uri_in=%s, uri_out=%p, flags=%lu, dname=%s, bandwidth=%lu, dom_xml=%s", dconn, cookie, cookielen, uri_in, uri_out, flags, dname, bandwidth, dom_xml);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return -1;
-    }
-
-    if (dconn->driver->domainMigratePrepare2)
-        return dconn->driver->domainMigratePrepare2 (dconn, cookie, cookielen,
-                                                     uri_in, uri_out,
-                                                     flags, dname, bandwidth,
-                                                     dom_xml);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
+
+    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;
+    }
 
     virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dconn);
     return -1;
 }
 
@@ -2542,18 +2969,31 @@ virDomainMigrateFinish2 (virConnectPtr d
 {
     DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, flags=%lu, retcode=%d", dconn, dname, cookie, cookielen, uri, flags, retcode);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return NULL;
-    }
-
-    if (dconn->driver->domainMigrateFinish2)
-        return dconn->driver->domainMigrateFinish2 (dconn, dname,
-                                                    cookie, cookielen,
-                                                    uri, flags,
-                                                    retcode);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return NULL;
+    }
+
+    if (dconn->driver->domainMigrateFinish2) {
+        virDomainPtr ret;
+        ret = dconn->driver->domainMigrateFinish2 (dconn, dname,
+                                                   cookie, cookielen,
+                                                   uri, flags,
+                                                   retcode);
+        if (!ret)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dconn);
     return NULL;
 }
 
@@ -2572,19 +3012,32 @@ virNodeGetInfo(virConnectPtr conn, virNo
 {
     DEBUG("conn=%p, info=%p", conn, info);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (info == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->nodeGetInfo)
-        return conn->driver->nodeGetInfo (conn, info);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->nodeGetInfo) {
+        int ret;
+        ret = conn->driver->nodeGetInfo (conn, info);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -2603,15 +3056,28 @@ virConnectGetCapabilities (virConnectPtr
 {
     DEBUG("conn=%p", conn);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECT (conn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return NULL;
-    }
-
-    if (conn->driver->getCapabilities)
-        return conn->driver->getCapabilities (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return NULL;
+    }
+
+    if (conn->driver->getCapabilities) {
+        char *ret;
+        ret = conn->driver->getCapabilities (conn);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -2628,15 +3094,28 @@ virNodeGetFreeMemory(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECT (conn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return 0;
     }
 
-    if (conn->driver->getFreeMemory)
-        return conn->driver->getFreeMemory (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->driver->getFreeMemory) {
+        unsigned long long ret;
+        ret = conn->driver->getFreeMemory (conn);
+        if (ret == 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return 0;
 }
 
@@ -2656,18 +3135,28 @@ virDomainGetSchedulerType(virDomainPtr d
     char *schedtype;
     DEBUG("domain=%p, nparams=%p", domain, nparams);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
     conn = domain->conn;
 
     if (conn->driver->domainGetSchedulerType){
         schedtype = conn->driver->domainGetSchedulerType (domain, nparams);
+        if (!schedtype)
+            goto error;
         return schedtype;
     }
 
     virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return NULL;
 }
 
@@ -2693,16 +3182,29 @@ virDomainGetSchedulerParameters(virDomai
     virConnectPtr conn;
     DEBUG("domain=%p, params=%p, nparams=%p", domain, params, nparams);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return -1;
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainGetSchedulerParameters)
-        return conn->driver->domainGetSchedulerParameters (domain, params, nparams);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainGetSchedulerParameters) {
+        int ret;
+        ret = conn->driver->domainGetSchedulerParameters (domain, params, nparams);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -2725,20 +3227,33 @@ virDomainSetSchedulerParameters(virDomai
     virConnectPtr conn;
     DEBUG("domain=%p, params=%p, nparams=%d", domain, params, nparams);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return -1;
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return -1;
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainSetSchedulerParameters)
-        return conn->driver->domainSetSchedulerParameters (domain, params, nparams);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainSetSchedulerParameters) {
+        int ret;
+        ret = conn->driver->domainSetSchedulerParameters (domain, params, nparams);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -2774,25 +3289,33 @@ virDomainBlockStats (virDomainPtr dom, c
     struct _virDomainBlockStats stats2 = { -1, -1, -1, -1, -1 };
     DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size);
 
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+        virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
     if (!stats || size > sizeof stats2) {
         virLibDomainError (dom, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return -1;
-    }
-    if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
-        virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return -1;
+        goto error;
     }
     conn = dom->conn;
 
     if (conn->driver->domainBlockStats) {
         if (conn->driver->domainBlockStats (dom, path, &stats2) == -1)
-            return -1;
+            goto error;
 
         memcpy (stats, &stats2, size);
         return 0;
     }
 
     virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dom->conn);
     return -1;
 }
 
@@ -2826,25 +3349,33 @@ virDomainInterfaceStats (virDomainPtr do
                                                -1, -1, -1, -1 };
     DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size);
 
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+        virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
     if (!stats || size > sizeof stats2) {
         virLibDomainError (dom, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return -1;
-    }
-    if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
-        virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return -1;
+        goto error;
     }
     conn = dom->conn;
 
     if (conn->driver->domainInterfaceStats) {
         if (conn->driver->domainInterfaceStats (dom, path, &stats2) == -1)
-            return -1;
+            goto error;
 
         memcpy (stats, &stats2, size);
         return 0;
     }
 
     virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dom->conn);
     return -1;
 }
 
@@ -2899,8 +3430,12 @@ virDomainBlockPeek (virDomainPtr dom,
     DEBUG("domain=%p, path=%s, offset=%lld, size=%zi, buffer=%p",
           dom, path, offset, size, buffer);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return -1;
     }
     conn = dom->conn;
@@ -2908,27 +3443,36 @@ virDomainBlockPeek (virDomainPtr dom,
     if (!path) {
         virLibDomainError (dom, VIR_ERR_INVALID_ARG,
                            _("path is NULL"));
-        return -1;
+        goto error;
     }
 
     if (flags != 0) {
         virLibDomainError (dom, VIR_ERR_INVALID_ARG,
                            _("flags must be zero"));
-        return -1;
+        goto error;
     }
 
     /* Allow size == 0 as an access test. */
     if (size > 0 && !buffer) {
         virLibDomainError (dom, VIR_ERR_INVALID_ARG,
                            _("buffer is NULL"));
-        return -1;
-    }
-
-    if (conn->driver->domainBlockPeek)
-        return conn->driver->domainBlockPeek (dom, path, offset, size,
-                                              buffer, flags);
+        goto error;
+    }
+
+    if (conn->driver->domainBlockPeek) {
+        int ret;
+        ret =conn->driver->domainBlockPeek (dom, path, offset, size,
+                                            buffer, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
 
     virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dom->conn);
     return -1;
 }
 
@@ -2974,8 +3518,12 @@ virDomainMemoryPeek (virDomainPtr dom,
     DEBUG ("domain=%p, start=%lld, size=%zi, buffer=%p, flags=%d",
            dom, start, size, buffer, flags);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return -1;
     }
     conn = dom->conn;
@@ -3004,21 +3552,30 @@ virDomainMemoryPeek (virDomainPtr dom,
     if (flags != VIR_MEMORY_VIRTUAL) {
         virLibDomainError (dom, VIR_ERR_INVALID_ARG,
                            _("flags parameter must be VIR_MEMORY_VIRTUAL"));
-        return -1;
+        goto error;
     }
 
     /* Allow size == 0 as an access test. */
     if (size > 0 && !buffer) {
         virLibDomainError (dom, VIR_ERR_INVALID_ARG,
                            _("buffer is NULL but size is non-zero"));
-        return -1;
-    }
-
-    if (conn->driver->domainMemoryPeek)
-        return conn->driver->domainMemoryPeek (dom, start, size,
-                                               buffer, flags);
+        goto error;
+    }
+
+    if (conn->driver->domainMemoryPeek) {
+        int ret;
+        ret = conn->driver->domainMemoryPeek (dom, start, size,
+                                              buffer, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
 
     virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dom->conn);
     return -1;
 }
 
@@ -3044,23 +3601,36 @@ virDomainDefineXML(virConnectPtr conn, c
 virDomainDefineXML(virConnectPtr conn, const char *xml) {
     DEBUG("conn=%p, xml=%s", conn, xml);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (conn->flags & VIR_CONNECT_RO) {
         virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
     if (xml == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->driver->domainDefineXML)
-        return conn->driver->domainDefineXML (conn, xml);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainDefineXML) {
+        virDomainPtr ret;
+        ret = conn->driver->domainDefineXML (conn, xml);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -3077,20 +3647,33 @@ virDomainUndefine(virDomainPtr domain) {
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    conn = domain->conn;
-    if (conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->domainUndefine)
-        return conn->driver->domainUndefine (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    conn = domain->conn;
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainUndefine) {
+        int ret;
+        ret = conn->driver->domainUndefine (domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3107,15 +3690,28 @@ virConnectNumOfDefinedDomains(virConnect
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->numOfDefinedDomains)
-        return conn->driver->numOfDefinedDomains (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    if (conn->driver->numOfDefinedDomains) {
+        int ret;
+        ret = conn->driver->numOfDefinedDomains (conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -3135,20 +3731,33 @@ virConnectListDefinedDomains(virConnectP
                              int maxnames) {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->listDefinedDomains)
-        return conn->driver->listDefinedDomains (conn, names, maxnames);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->listDefinedDomains) {
+        int ret;
+        ret = conn->driver->listDefinedDomains (conn, names, maxnames);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -3166,24 +3775,33 @@ virDomainCreate(virDomainPtr domain) {
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    conn = domain->conn;
-    if (conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->domainCreate)
-        return conn->driver->domainCreate (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    conn = domain->conn;
+    if (conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->domainCreate) {
+        int ret;
+        ret = conn->driver->domainCreate (domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3205,21 +3823,34 @@ virDomainGetAutostart(virDomainPtr domai
     virConnectPtr conn;
     DEBUG("domain=%p, autostart=%p", domain, autostart);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (!autostart) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetAutostart)
-        return conn->driver->domainGetAutostart (domain, autostart);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetAutostart) {
+        int ret;
+        ret = conn->driver->domainGetAutostart (domain, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3240,17 +3871,30 @@ virDomainSetAutostart(virDomainPtr domai
     virConnectPtr conn;
     DEBUG("domain=%p, autostart=%d", domain, autostart);
 
-    if (!VIR_IS_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainSetAutostart)
-        return conn->driver->domainSetAutostart (domain, autostart);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainSetAutostart) {
+        int ret;
+        ret = conn->driver->domainSetAutostart (domain, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3273,29 +3917,38 @@ virDomainSetVcpus(virDomainPtr domain, u
     virConnectPtr conn;
     DEBUG("domain=%p, nvcpus=%u", domain, nvcpus);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
     }
 
     if (nvcpus < 1) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainSetVcpus)
-        return conn->driver->domainSetVcpus (domain, nvcpus);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainSetVcpus) {
+        int ret;
+        ret = conn->driver->domainSetVcpus (domain, nvcpus);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3324,30 +3977,39 @@ virDomainPinVcpu(virDomainPtr domain, un
     virConnectPtr conn;
     DEBUG("domain=%p, vcpu=%u, cpumap=%p, maplen=%d", domain, vcpu, cpumap, maplen);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
     }
 
     if ((vcpu > 32000) || (cpumap == NULL) || (maplen < 1)) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainPinVcpu)
-        return conn->driver->domainPinVcpu (domain, vcpu, cpumap, maplen);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+       goto error;
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainPinVcpu) {
+        int ret;
+        ret = conn->driver->domainPinVcpu (domain, vcpu, cpumap, maplen);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3379,30 +4041,39 @@ virDomainGetVcpus(virDomainPtr domain, v
     virConnectPtr conn;
     DEBUG("domain=%p, info=%p, maxinfo=%d, cpumaps=%p, maplen=%d", domain, info, maxinfo, cpumaps, maplen);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if ((info == NULL) || (maxinfo < 1)) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
     if (cpumaps != NULL && maplen < 1) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetVcpus)
-        return conn->driver->domainGetVcpus (domain, info, maxinfo,
-                                             cpumaps, maplen);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        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;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3424,17 +4095,30 @@ virDomainGetMaxVcpus(virDomainPtr domain
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = domain->conn;
-
-    if (conn->driver->domainGetMaxVcpus)
-        return conn->driver->domainGetMaxVcpus (domain);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    conn = domain->conn;
+
+    if (conn->driver->domainGetMaxVcpus) {
+        int ret;
+        ret = conn->driver->domainGetMaxVcpus (domain);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3454,20 +4138,33 @@ virDomainAttachDevice(virDomainPtr domai
     virConnectPtr conn;
     DEBUG("domain=%p, xml=%s", domain, xml);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainAttachDevice)
-        return conn->driver->domainAttachDevice (domain, xml);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainAttachDevice) {
+        int ret;
+        ret = conn->driver->domainAttachDevice (domain, xml);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3486,20 +4183,33 @@ virDomainDetachDevice(virDomainPtr domai
     virConnectPtr conn;
     DEBUG("domain=%p, xml=%s", domain, xml);
 
-    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
-        return (-1);
-    }
-    if (domain->conn->flags & VIR_CONNECT_RO) {
-        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-    conn = domain->conn;
-
-    if (conn->driver->domainDetachDevice)
-        return conn->driver->domainDetachDevice (domain, xml);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
+        virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (domain->conn->flags & VIR_CONNECT_RO) {
+        virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+        goto error;
+    }
+    conn = domain->conn;
+
+    if (conn->driver->domainDetachDevice) {
+        int ret;
+        ret = conn->driver->domainDetachDevice (domain, xml);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(domain->conn);
     return -1;
 }
 
@@ -3528,20 +4238,33 @@ virNodeGetCellsFreeMemory(virConnectPtr 
     DEBUG("conn=%p, freeMems=%p, startCell=%d, maxCells=%d",
           conn, freeMems, startCell, maxCells);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     if ((freeMems == NULL) || (maxCells <= 0) || (startCell < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->driver->nodeGetCellsFreeMemory)
-        return conn->driver->nodeGetCellsFreeMemory (conn, freeMems, startCell, maxCells);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->driver->nodeGetCellsFreeMemory) {
+        int ret;
+        ret = conn->driver->nodeGetCellsFreeMemory (conn, freeMems, startCell, maxCells);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -3564,8 +4287,12 @@ virNetworkGetConnect (virNetworkPtr net)
 {
     DEBUG("net=%p", net);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_NETWORK (net)) {
         virLibNetworkError (NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
     return net->conn;
@@ -3584,15 +4311,28 @@ virConnectNumOfNetworks(virConnectPtr co
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->numOfNetworks)
-        return conn->networkDriver->numOfNetworks (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    if (conn->networkDriver && conn->networkDriver->numOfNetworks) {
+        int ret;
+        ret = conn->networkDriver->numOfNetworks (conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -3611,20 +4351,33 @@ virConnectListNetworks(virConnectPtr con
 {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->listNetworks)
-        return conn->networkDriver->listNetworks (conn, names, maxnames);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->listNetworks) {
+        int ret;
+        ret = conn->networkDriver->listNetworks (conn, names, maxnames);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -3641,15 +4394,28 @@ virConnectNumOfDefinedNetworks(virConnec
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->numOfDefinedNetworks)
-        return conn->networkDriver->numOfDefinedNetworks (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    if (conn->networkDriver && conn->networkDriver->numOfDefinedNetworks) {
+        int ret;
+        ret = conn->networkDriver->numOfDefinedNetworks (conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -3669,21 +4435,34 @@ virConnectListDefinedNetworks(virConnect
 {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->listDefinedNetworks)
-        return conn->networkDriver->listDefinedNetworks (conn,
-                                                         names, maxnames);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->listDefinedNetworks) {
+        int ret;
+        ret = conn->networkDriver->listDefinedNetworks (conn,
+                                                        names, maxnames);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -3702,19 +4481,32 @@ virNetworkLookupByName(virConnectPtr con
 {
     DEBUG("conn=%p, name=%s", conn, name);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (name == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->networkLookupByName)
-        return conn->networkDriver->networkLookupByName (conn, name);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto  error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkLookupByName) {
+        virNetworkPtr ret;
+        ret = conn->networkDriver->networkLookupByName (conn, name);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -3733,19 +4525,32 @@ virNetworkLookupByUUID(virConnectPtr con
 {
     DEBUG("conn=%p, uuid=%s", conn, uuid);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (uuid == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->networkLookupByUUID)
-        return conn->networkDriver->networkLookupByUUID (conn, uuid);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkLookupByUUID){
+        virNetworkPtr ret;
+        ret = conn->networkDriver->networkLookupByUUID (conn, uuid);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -3767,13 +4572,17 @@ virNetworkLookupByUUIDString(virConnectP
     int ret;
     DEBUG("conn=%p, uuidstr=%s", conn, uuidstr);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (uuidstr == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
     /* XXX: sexpr_uuid() also supports 'xxxx-xxxx-xxxx-xxxx' format.
@@ -3792,12 +4601,17 @@ virNetworkLookupByUUIDString(virConnectP
 
     if (ret!=VIR_UUID_BUFLEN) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
     for (i = 0; i < VIR_UUID_BUFLEN; i++)
         uuid[i] = raw[i] & 0xFF;
 
     return virNetworkLookupByUUID(conn, &uuid[0]);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return NULL;
 }
 
 /**
@@ -3815,23 +4629,36 @@ virNetworkCreateXML(virConnectPtr conn, 
 {
     DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (xmlDesc == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
     if (conn->flags & VIR_CONNECT_RO) {
         virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->networkCreateXML)
-        return conn->networkDriver->networkCreateXML (conn, xmlDesc);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkCreateXML) {
+        virNetworkPtr ret;
+        ret = conn->networkDriver->networkCreateXML (conn, xmlDesc);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -3849,23 +4676,36 @@ virNetworkDefineXML(virConnectPtr conn, 
 {
     DEBUG("conn=%p, xml=%s", conn, xml);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (conn->flags & VIR_CONNECT_RO) {
         virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
     if (xml == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->networkDefineXML)
-        return conn->networkDriver->networkDefineXML (conn, xml);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkDefineXML) {
+        virNetworkPtr ret;
+        ret = conn->networkDriver->networkDefineXML (conn, xml);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -3882,20 +4722,33 @@ virNetworkUndefine(virNetworkPtr network
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     conn = network->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->networkUndefine)
-        return conn->networkDriver->networkUndefine (network);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkUndefine) {
+        int ret;
+        ret = conn->networkDriver->networkUndefine (network);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
     return -1;
 }
 
@@ -3914,24 +4767,33 @@ virNetworkCreate(virNetworkPtr network)
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
-    if (network == NULL) {
-        TODO
-        return (-1);
-    }
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     conn = network->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->networkCreate)
-        return conn->networkDriver->networkCreate (network);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkCreate) {
+        int ret;
+        ret = conn->networkDriver->networkCreate (network);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
     return -1;
 }
 
@@ -3952,21 +4814,34 @@ virNetworkDestroy(virNetworkPtr network)
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     conn = network->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->networkDriver && conn->networkDriver->networkDestroy)
-        return conn->networkDriver->networkDestroy (network);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->networkDriver && conn->networkDriver->networkDestroy) {
+        int ret;
+        ret = conn->networkDriver->networkDestroy (network);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
     return -1;
 }
 
@@ -3984,12 +4859,19 @@ virNetworkFree(virNetworkPtr network)
 {
     DEBUG("network=%p", network);
 
-    if (!VIR_IS_NETWORK(network)) {
-        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
-        return (-1);
-    }
-    if (virUnrefNetwork(network) < 0)
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (virUnrefNetwork(network) < 0) {
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
     return(0);
 }
 
@@ -4007,8 +4889,12 @@ virNetworkGetName(virNetworkPtr network)
 {
     DEBUG("network=%p", network);
 
-    if (!VIR_IS_NETWORK(network)) {
-        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     return (network->name);
@@ -4028,18 +4914,27 @@ virNetworkGetUUID(virNetworkPtr network,
 {
     DEBUG("network=%p, uuid=%p", network, uuid);
 
-    if (!VIR_IS_NETWORK(network)) {
-        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (uuid == NULL) {
         virLibNetworkError(network, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     memcpy(uuid, &network->uuid[0], VIR_UUID_BUFLEN);
 
     return (0);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
+    return -1;
 }
 
 /**
@@ -4058,13 +4953,17 @@ virNetworkGetUUIDString(virNetworkPtr ne
     unsigned char uuid[VIR_UUID_BUFLEN];
     DEBUG("network=%p, buf=%p", network, buf);
 
-    if (!VIR_IS_NETWORK(network)) {
-        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (buf == NULL) {
         virLibNetworkError(network, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     if (virNetworkGetUUID(network, &uuid[0]))
@@ -4072,6 +4971,11 @@ virNetworkGetUUIDString(virNetworkPtr ne
 
     virUUIDFormat(uuid, buf);
     return (0);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
+    return -1;
 }
 
 /**
@@ -4091,21 +4995,34 @@ virNetworkGetXMLDesc(virNetworkPtr netwo
     virConnectPtr conn;
     DEBUG("network=%p, flags=%d", network, flags);
 
-    if (!VIR_IS_NETWORK(network)) {
-        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (flags != 0) {
         virLibNetworkError(network, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
     conn = network->conn;
 
-    if (conn->networkDriver && conn->networkDriver->networkDumpXML)
-        return conn->networkDriver->networkDumpXML (network, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->networkDriver && conn->networkDriver->networkDumpXML) {
+        char *ret;
+        ret = conn->networkDriver->networkDumpXML (network, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
     return NULL;
 }
 
@@ -4125,17 +5042,30 @@ virNetworkGetBridgeName(virNetworkPtr ne
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
-    if (!VIR_IS_NETWORK(network)) {
-        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
 
     conn = network->conn;
 
-    if (conn->networkDriver && conn->networkDriver->networkGetBridgeName)
-        return conn->networkDriver->networkGetBridgeName (network);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->networkDriver && conn->networkDriver->networkGetBridgeName) {
+        char *ret;
+        ret = conn->networkDriver->networkGetBridgeName (network);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
     return NULL;
 }
 
@@ -4157,21 +5087,34 @@ virNetworkGetAutostart(virNetworkPtr net
     virConnectPtr conn;
     DEBUG("network=%p, autostart=%p", network, autostart);
 
-    if (!VIR_IS_NETWORK(network)) {
-        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (!autostart) {
         virLibNetworkError(network, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     conn = network->conn;
 
-    if (conn->networkDriver && conn->networkDriver->networkGetAutostart)
-        return conn->networkDriver->networkGetAutostart (network, autostart);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->networkDriver && conn->networkDriver->networkGetAutostart) {
+        int ret;
+        ret = conn->networkDriver->networkGetAutostart (network, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
     return -1;
 }
 
@@ -4192,17 +5135,30 @@ virNetworkSetAutostart(virNetworkPtr net
     virConnectPtr conn;
     DEBUG("network=%p, autostart=%d", network, autostart);
 
-    if (!VIR_IS_NETWORK(network)) {
-        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_NETWORK(network)) {
+        virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     conn = network->conn;
 
-    if (conn->networkDriver && conn->networkDriver->networkSetAutostart)
-        return conn->networkDriver->networkSetAutostart (network, autostart);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->networkDriver && conn->networkDriver->networkSetAutostart) {
+        int ret;
+        ret = conn->networkDriver->networkSetAutostart (network, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(network->conn);
     return -1;
 }
 
@@ -4226,8 +5182,12 @@ virStoragePoolGetConnect (virStoragePool
 {
     DEBUG("pool=%p", pool);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_POOL (pool)) {
         virLibStoragePoolError (NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
     return pool->conn;
@@ -4246,15 +5206,28 @@ virConnectNumOfStoragePools	(virConnectP
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->numOfPools)
-        return conn->storageDriver->numOfPools (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    if (conn->storageDriver && conn->storageDriver->numOfPools) {
+        int ret;
+        ret = conn->storageDriver->numOfPools (conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -4277,22 +5250,34 @@ virConnectListStoragePools	(virConnectPt
 {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->listPools)
-        return conn->storageDriver->listPools (conn, names, maxnames);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return -1;
-
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->listPools) {
+        int ret;
+        ret = conn->storageDriver->listPools (conn, names, maxnames);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return -1;
 }
 
 
@@ -4309,15 +5294,28 @@ virConnectNumOfDefinedStoragePools(virCo
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->numOfDefinedPools)
-        return conn->storageDriver->numOfDefinedPools (conn);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    if (conn->storageDriver && conn->storageDriver->numOfDefinedPools) {
+        int ret;
+        ret = conn->storageDriver->numOfDefinedPools (conn);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -4341,20 +5339,33 @@ virConnectListDefinedStoragePools(virCon
 {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->listDefinedPools)
-        return conn->storageDriver->listDefinedPools (conn, names, maxnames);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->listDefinedPools) {
+        int ret;
+        ret = conn->storageDriver->listDefinedPools (conn, names, maxnames);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -4386,19 +5397,34 @@ virConnectFindStoragePoolSources(virConn
                                  const char *srcSpec,
                                  unsigned int flags)
 {
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    DEBUG("conn=%p, type=%s, src=%s, flags=%u", conn, type ? type : "", srcSpec ? srcSpec : "", flags);
+
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
     if (type == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return NULL;
-    }
-
-    if (conn->storageDriver && conn->storageDriver->findPoolSources)
-        return conn->storageDriver->findPoolSources(conn, type, srcSpec, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->findPoolSources) {
+        char *ret;
+        ret = conn->storageDriver->findPoolSources(conn, type, srcSpec, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -4418,19 +5444,32 @@ virStoragePoolLookupByName(virConnectPtr
 {
     DEBUG("conn=%p, name=%s", conn, name);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (name == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolLookupByName)
-        return conn->storageDriver->poolLookupByName (conn, name);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolLookupByName) {
+        virStoragePoolPtr ret;
+        ret = conn->storageDriver->poolLookupByName (conn, name);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -4450,21 +5489,33 @@ virStoragePoolLookupByUUID(virConnectPtr
 {
     DEBUG("conn=%p, uuid=%s", conn, uuid);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (uuid == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolLookupByUUID)
-        return conn->storageDriver->poolLookupByUUID (conn, uuid);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return NULL;
-
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolLookupByUUID) {
+        virStoragePoolPtr ret;
+        ret = conn->storageDriver->poolLookupByUUID (conn, uuid);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return NULL;
 }
 
 
@@ -4479,26 +5530,35 @@ virStoragePoolLookupByUUID(virConnectPtr
  */
 virStoragePoolPtr
 virStoragePoolLookupByUUIDString(virConnectPtr conn,
-                                                                 const char *uuidstr)
+                                 const char *uuidstr)
 {
     unsigned char uuid[VIR_UUID_BUFLEN];
     DEBUG("conn=%p, uuidstr=%s", conn, uuidstr);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (uuidstr == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
     if (virUUIDParse(uuidstr, uuid) < 0) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
     return virStoragePoolLookupByUUID(conn, uuid);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return NULL;
 }
 
 
@@ -4515,17 +5575,29 @@ virStoragePoolLookupByVolume(virStorageV
 {
     DEBUG("vol=%p", vol);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (vol->conn->storageDriver && vol->conn->storageDriver->poolLookupByVolume)
-        return vol->conn->storageDriver->poolLookupByVolume (vol);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (NULL);
+    }
+
+    if (vol->conn->storageDriver && vol->conn->storageDriver->poolLookupByVolume) {
+        virStoragePoolPtr ret;
+        ret = vol->conn->storageDriver->poolLookupByVolume (vol);
+        if (!ret)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (vol->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return NULL;
-
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(vol->conn);
+    return NULL;
 }
 
 /**
@@ -4547,23 +5619,36 @@ virStoragePoolCreateXML(virConnectPtr co
 {
     DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (xmlDesc == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
     if (conn->flags & VIR_CONNECT_RO) {
         virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolCreateXML)
-        return conn->storageDriver->poolCreateXML (conn, xmlDesc, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolCreateXML) {
+        virStoragePoolPtr ret;
+        ret = conn->storageDriver->poolCreateXML (conn, xmlDesc, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -4585,25 +5670,37 @@ virStoragePoolDefineXML(virConnectPtr co
 {
     DEBUG("conn=%p, xml=%s", conn, xml);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (conn->flags & VIR_CONNECT_RO) {
         virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
     if (xml == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolDefineXML)
-        return conn->storageDriver->poolDefineXML (conn, xml, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return NULL;
-
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolDefineXML) {
+        virStoragePoolPtr ret;
+        ret = conn->storageDriver->poolDefineXML (conn, xml, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return NULL;
 }
 
 /**
@@ -4622,22 +5719,34 @@ virStoragePoolBuild(virStoragePoolPtr po
     virConnectPtr conn;
     DEBUG("pool=%p, flags=%u", pool, flags);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolBuild)
-        return conn->storageDriver->poolBuild (pool, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return -1;
-
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolBuild) {
+        int ret;
+        ret = conn->storageDriver->poolBuild (pool, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -4654,23 +5763,35 @@ virStoragePoolUndefine(virStoragePoolPtr
 {
     virConnectPtr conn;
     DEBUG("pool=%p", pool);
+
+    virThreadResetLastError();
 
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolUndefine)
-        return conn->storageDriver->poolUndefine (pool);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return -1;
-
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolUndefine) {
+        int ret;
+        ret = conn->storageDriver->poolUndefine (pool);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -4690,26 +5811,34 @@ virStoragePoolCreate(virStoragePoolPtr p
     virConnectPtr conn;
     DEBUG("pool=%p", pool);
 
-    if (pool == NULL) {
-        TODO;
-        return (-1);
-    }
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolCreate)
-        return conn->storageDriver->poolCreate (pool, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return -1;
-
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolCreate) {
+        int ret;
+        ret = conn->storageDriver->poolCreate (pool, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -4731,21 +5860,34 @@ virStoragePoolDestroy(virStoragePoolPtr 
     virConnectPtr conn;
     DEBUG("pool=%p", pool);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolDestroy)
-        return conn->storageDriver->poolDestroy (pool);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolDestroy) {
+        int ret;
+        ret = conn->storageDriver->poolDestroy (pool);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return -1;
 }
 
@@ -4767,21 +5909,34 @@ virStoragePoolDelete(virStoragePoolPtr p
     virConnectPtr conn;
     DEBUG("pool=%p, flags=%u", pool, flags);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolDelete)
-        return conn->storageDriver->poolDelete (pool, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolDelete) {
+        int ret;
+        ret = conn->storageDriver->poolDelete (pool, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return -1;
 }
 
@@ -4800,12 +5955,19 @@ virStoragePoolFree(virStoragePoolPtr poo
 {
     DEBUG("pool=%p", pool);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
-        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
-        return (-1);
-    }
-    if (virUnrefStoragePool(pool) < 0)
-        return (-1);
+    virThreadResetLastError();
+
+    if (!VIR_IS_STORAGE_POOL(pool)) {
+        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (virUnrefStoragePool(pool) < 0) {
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
     return(0);
 
 }
@@ -4829,21 +5991,34 @@ virStoragePoolRefresh(virStoragePoolPtr 
     virConnectPtr conn;
     DEBUG("pool=%p flags=%u", pool, flags);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->poolRefresh)
-        return conn->storageDriver->poolRefresh (pool, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->poolRefresh) {
+        int ret;
+        ret = conn->storageDriver->poolRefresh (pool, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return -1;
 }
 
@@ -4861,12 +6036,15 @@ virStoragePoolGetName(virStoragePoolPtr 
 {
     DEBUG("pool=%p", pool);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
-        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_STORAGE_POOL(pool)) {
+        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     return (pool->name);
-
 }
 
 
@@ -4885,19 +6063,27 @@ virStoragePoolGetUUID(virStoragePoolPtr 
 {
     DEBUG("pool=%p, uuid=%p", pool, uuid);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
-        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_STORAGE_POOL(pool)) {
+        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (uuid == NULL) {
         virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     memcpy(uuid, &pool->uuid[0], VIR_UUID_BUFLEN);
 
     return (0);
 
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
+    return -1;
 }
 
 /**
@@ -4916,21 +6102,29 @@ virStoragePoolGetUUIDString(virStoragePo
     unsigned char uuid[VIR_UUID_BUFLEN];
     DEBUG("pool=%p, buf=%p", pool, buf);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
-        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_STORAGE_POOL(pool)) {
+        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (buf == NULL) {
         virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     if (virStoragePoolGetUUID(pool, &uuid[0]))
-        return (-1);
+        goto error;
 
     virUUIDFormat(uuid, buf);
     return (0);
 
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -4951,25 +6145,37 @@ virStoragePoolGetInfo(virStoragePoolPtr 
     virConnectPtr conn;
     DEBUG("pool=%p, info=%p", pool, info);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (info == NULL) {
         virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     memset(info, 0, sizeof(virStoragePoolInfo));
 
     conn = pool->conn;
 
-    if (conn->storageDriver->poolGetInfo)
-        return conn->storageDriver->poolGetInfo (pool, info);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return -1;
-
+    if (conn->storageDriver->poolGetInfo) {
+        int ret;
+        ret = conn->storageDriver->poolGetInfo (pool, info);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -4991,23 +6197,35 @@ virStoragePoolGetXMLDesc(virStoragePoolP
     virConnectPtr conn;
     DEBUG("pool=%p, flags=%u", pool, flags);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
-        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_STORAGE_POOL(pool)) {
+        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (flags != 0) {
         virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    conn = pool->conn;
-
-    if (conn->storageDriver && conn->storageDriver->poolGetXMLDesc)
-        return conn->storageDriver->poolGetXMLDesc (pool, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return NULL;
-
+        goto error;
+    }
+
+    conn = pool->conn;
+
+    if (conn->storageDriver && conn->storageDriver->poolGetXMLDesc) {
+        char *ret;
+        ret = conn->storageDriver->poolGetXMLDesc (pool, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
+    return NULL;
 }
 
 
@@ -5028,21 +6246,34 @@ virStoragePoolGetAutostart(virStoragePoo
     virConnectPtr conn;
     DEBUG("pool=%p, autostart=%p", pool, autostart);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
-        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_STORAGE_POOL(pool)) {
+        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (!autostart) {
         virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = pool->conn;
-
-    if (conn->storageDriver && conn->storageDriver->poolGetAutostart)
-        return conn->storageDriver->poolGetAutostart (pool, autostart);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    conn = pool->conn;
+
+    if (conn->storageDriver && conn->storageDriver->poolGetAutostart) {
+        int ret;
+        ret = conn->storageDriver->poolGetAutostart (pool, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return -1;
 }
 
@@ -5063,17 +6294,30 @@ virStoragePoolSetAutostart(virStoragePoo
     virConnectPtr conn;
     DEBUG("pool=%p, autostart=%d", pool, autostart);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
-        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
-        return (-1);
-    }
-
-    conn = pool->conn;
-
-    if (conn->storageDriver && conn->storageDriver->poolSetAutostart)
-        return conn->storageDriver->poolSetAutostart (pool, autostart);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_STORAGE_POOL(pool)) {
+        virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    conn = pool->conn;
+
+    if (conn->storageDriver && conn->storageDriver->poolSetAutostart) {
+        int ret;
+        ret = conn->storageDriver->poolSetAutostart (pool, autostart);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return -1;
 }
 
@@ -5091,15 +6335,28 @@ virStoragePoolNumOfVolumes(virStoragePoo
 {
     DEBUG("pool=%p", pool);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
-        return (-1);
-    }
-
-    if (pool->conn->storageDriver && pool->conn->storageDriver->poolNumOfVolumes)
-        return pool->conn->storageDriver->poolNumOfVolumes (pool);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+
+    if (pool->conn->storageDriver && pool->conn->storageDriver->poolNumOfVolumes) {
+        int ret;
+        ret = pool->conn->storageDriver->poolNumOfVolumes (pool);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return -1;
 }
 
@@ -5122,20 +6379,33 @@ virStoragePoolListVolumes(virStoragePool
 {
     DEBUG("pool=%p, names=%p, maxnames=%d", pool, names, maxnames);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (pool->conn->storageDriver && pool->conn->storageDriver->poolListVolumes)
-        return pool->conn->storageDriver->poolListVolumes (pool, names, maxnames);
+        goto error;
+    }
+
+    if (pool->conn->storageDriver && pool->conn->storageDriver->poolListVolumes) {
+        int ret;
+        ret = pool->conn->storageDriver->poolListVolumes (pool, names, maxnames);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return -1;
 }
 
@@ -5159,8 +6429,12 @@ virStorageVolGetConnect (virStorageVolPt
 {
     DEBUG("vol=%p", vol);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_VOL (vol)) {
         virLibStoragePoolError (NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
     return vol->conn;
@@ -5183,19 +6457,32 @@ virStorageVolLookupByName(virStoragePool
 {
     DEBUG("pool=%p, name=%s", pool, name);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_STORAGE_POOL(pool)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (name == NULL) {
         virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (pool->conn->storageDriver && pool->conn->storageDriver->volLookupByName)
-        return pool->conn->storageDriver->volLookupByName (pool, name);
+        goto error;
+    }
+
+    if (pool->conn->storageDriver && pool->conn->storageDriver->volLookupByName) {
+        virStorageVolPtr ret;
+        ret = pool->conn->storageDriver->volLookupByName (pool, name);
+        if (!ret)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return NULL;
 }
 
@@ -5217,19 +6504,32 @@ virStorageVolLookupByKey(virConnectPtr c
 {
     DEBUG("conn=%p, key=%s", conn, key);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (key == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->volLookupByKey)
-        return conn->storageDriver->volLookupByKey (conn, key);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->volLookupByKey) {
+        virStorageVolPtr ret;
+        ret = conn->storageDriver->volLookupByKey (conn, key);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -5249,19 +6549,32 @@ virStorageVolLookupByPath(virConnectPtr 
 {
     DEBUG("conn=%p, path=%s", conn, path);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (path == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->volLookupByPath)
-        return conn->storageDriver->volLookupByPath (conn, path);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->volLookupByPath) {
+        virStorageVolPtr ret;
+        ret = conn->storageDriver->volLookupByPath (conn, path);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -5280,8 +6593,12 @@ virStorageVolGetName(virStorageVolPtr vo
 {
     DEBUG("vol=%p", vol);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     return (vol->name);
@@ -5303,8 +6620,12 @@ virStorageVolGetKey(virStorageVolPtr vol
 {
     DEBUG("vol=%p", vol);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     return (vol->key);
@@ -5330,20 +6651,33 @@ virStorageVolCreateXML(virStoragePoolPtr
 {
     DEBUG("pool=%p, flags=%u", pool, flags);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
 
     if (pool->conn->flags & VIR_CONNECT_RO) {
         virLibConnError(pool->conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (NULL);
-    }
-
-    if (pool->conn->storageDriver && pool->conn->storageDriver->volCreateXML)
-        return pool->conn->storageDriver->volCreateXML (pool, xmldesc, flags);
+        goto error;
+    }
+
+    if (pool->conn->storageDriver && pool->conn->storageDriver->volCreateXML) {
+        virStorageVolPtr ret;
+        ret = pool->conn->storageDriver->volCreateXML (pool, xmldesc, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(pool->conn);
     return NULL;
 }
 
@@ -5364,21 +6698,34 @@ virStorageVolDelete(virStorageVolPtr vol
     virConnectPtr conn;
     DEBUG("vol=%p, flags=%u", vol, flags);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
 
     conn = vol->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStorageVolError(vol, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->storageDriver && conn->storageDriver->volDelete)
-        return conn->storageDriver->volDelete (vol, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->storageDriver && conn->storageDriver->volDelete) {
+        int ret;
+        ret = conn->storageDriver->volDelete (vol, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(vol->conn);
     return -1;
 }
 
@@ -5397,12 +6744,19 @@ virStorageVolFree(virStorageVolPtr vol)
 {
     DEBUG("vol=%p", vol);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
-        return (-1);
-    }
-    if (virUnrefStorageVol(vol) < 0)
-        return (-1);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (virUnrefStorageVol(vol) < 0) {
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
     return(0);
 }
 
@@ -5424,23 +6778,36 @@ virStorageVolGetInfo(virStorageVolPtr vo
     virConnectPtr conn;
     DEBUG("vol=%p, info=%p", vol, info);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (info == NULL) {
         virLibStorageVolError(vol, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     memset(info, 0, sizeof(virStorageVolInfo));
 
     conn = vol->conn;
 
-    if (conn->storageDriver->volGetInfo)
-        return conn->storageDriver->volGetInfo (vol, info);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->storageDriver->volGetInfo){
+        int ret;
+        ret = conn->storageDriver->volGetInfo (vol, info);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(vol->conn);
     return -1;
 }
 
@@ -5462,23 +6829,35 @@ virStorageVolGetXMLDesc(virStorageVolPtr
     virConnectPtr conn;
     DEBUG("vol=%p, flags=%u", vol, flags);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
     if (flags != 0) {
         virLibStorageVolError(vol, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
     conn = vol->conn;
 
-    if (conn->storageDriver && conn->storageDriver->volGetXMLDesc)
-        return conn->storageDriver->volGetXMLDesc (vol, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-    return NULL;
-
+    if (conn->storageDriver && conn->storageDriver->volGetXMLDesc) {
+        char *ret;
+        ret = conn->storageDriver->volGetXMLDesc (vol, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(vol->conn);
+    return NULL;
 }
 
 
@@ -5500,17 +6879,30 @@ virStorageVolGetPath(virStorageVolPtr vo
     virConnectPtr conn;
     DEBUG("vol=%p", vol);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+        /* Copy to global error object for back compatability */
+        virThreadSetGlobalError();
         return (NULL);
     }
 
     conn = vol->conn;
 
-    if (conn->storageDriver && conn->storageDriver->volGetPath)
-        return conn->storageDriver->volGetPath (vol);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    if (conn->storageDriver && conn->storageDriver->volGetPath) {
+        char *ret;
+        ret = conn->storageDriver->volGetPath (vol);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(vol->conn);
     return NULL;
 }
 
@@ -5535,19 +6927,32 @@ virNodeNumOfDevices(virConnectPtr conn, 
 {
     DEBUG("conn=%p, cap=%s, flags=%d", conn, cap, flags);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (flags != 0) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->deviceMonitor && conn->deviceMonitor->numOfDevices)
-        return conn->deviceMonitor->numOfDevices (conn, cap, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->deviceMonitor && conn->deviceMonitor->numOfDevices) {
+        int ret;
+        ret = conn->deviceMonitor->numOfDevices (conn, cap, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -5576,19 +6981,32 @@ virNodeListDevices(virConnectPtr conn,
     DEBUG("conn=%p, cap=%s, names=%p, maxnames=%d, flags=%d",
           conn, cap, names, maxnames, flags);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if ((flags != 0) || (names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if (conn->deviceMonitor && conn->deviceMonitor->listDevices)
-        return conn->deviceMonitor->listDevices (conn, cap, names, maxnames, flags);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->deviceMonitor && conn->deviceMonitor->listDevices) {
+        int ret;
+        ret = conn->deviceMonitor->listDevices (conn, cap, names, maxnames, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -5606,20 +7024,33 @@ virNodeDevicePtr virNodeDeviceLookupByNa
 {
     DEBUG("conn=%p, name=%p", conn, name);
 
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
 
     if (name == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return NULL;
-    }
-
-    if (conn->deviceMonitor && conn->deviceMonitor->deviceLookupByName)
-        return conn->deviceMonitor->deviceLookupByName (conn, name);
-
-    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+        goto error;
+    }
+
+    if (conn->deviceMonitor && conn->deviceMonitor->deviceLookupByName) {
+        virNodeDevicePtr ret;
+        ret = conn->deviceMonitor->deviceLookupByName (conn, name);
+        if (!ret)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return NULL;
 }
 
@@ -5638,15 +7069,28 @@ char *virNodeDeviceGetXMLDesc(virNodeDev
 {
     DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) {
         virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__);
-        return NULL;
-    }
-
-    if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceDumpXML)
-        return dev->conn->deviceMonitor->deviceDumpXML (dev, flags);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return NULL;
+    }
+
+    if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceDumpXML) {
+        char *ret;
+        ret = dev->conn->deviceMonitor->deviceDumpXML (dev, flags);
+        if (!ret)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dev->conn);
     return NULL;
 }
 
@@ -5684,8 +7128,12 @@ const char *virNodeDeviceGetParent(virNo
 {
     DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) {
         virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return NULL;
     }
 
@@ -5712,15 +7160,28 @@ int virNodeDeviceNumOfCaps(virNodeDevice
 {
     DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) {
         virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__);
-        return -1;
-    }
-
-    if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceNumOfCaps)
-        return dev->conn->deviceMonitor->deviceNumOfCaps (dev);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
+
+    if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceNumOfCaps) {
+        int ret;
+        ret = dev->conn->deviceMonitor->deviceNumOfCaps (dev);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dev->conn);
     return -1;
 }
 
@@ -5741,15 +7202,28 @@ int virNodeDeviceListCaps(virNodeDeviceP
     DEBUG("dev=%p, conn=%p, names=%p, maxnames=%d",
           dev, dev ? dev->conn : NULL, names, maxnames);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) {
         virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__);
-        return -1;
-    }
-
-    if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceListCaps)
-        return dev->conn->deviceMonitor->deviceListCaps (dev, names, maxnames);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return -1;
+    }
+
+    if (dev->conn->deviceMonitor && dev->conn->deviceMonitor->deviceListCaps) {
+        int ret;
+        ret = dev->conn->deviceMonitor->deviceListCaps (dev, names, maxnames);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
 
     virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(dev->conn);
     return -1;
 }
 
@@ -5767,12 +7241,19 @@ int virNodeDeviceFree(virNodeDevicePtr d
 {
     DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
 
+    virThreadResetLastError();
+
     if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) {
         virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__);
-        return (-1);
-    }
-    if (virUnrefNodeDevice(dev) < 0)
-        return (-1);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
+    if (virUnrefNodeDevice(dev) < 0) {
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
+        return (-1);
+    }
     return(0);
 }
 
@@ -5799,18 +7280,32 @@ virConnectDomainEventRegister(virConnect
                               void *opaque,
                               virFreeCallback freecb)
 {
-
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    DEBUG("conn=%p, cb=%p, opaque=%p, freecb=%p", conn, cb, opaque, freecb);
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (cb == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-
-    if ((conn->driver) && (conn->driver->domainEventRegister))
-        return conn->driver->domainEventRegister (conn, cb, opaque, freecb);
+        goto error;
+    }
+
+    if ((conn->driver) && (conn->driver->domainEventRegister)) {
+        int ret;
+        ret = conn->driver->domainEventRegister (conn, cb, opaque, freecb);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
     return -1;
 }
 
@@ -5829,19 +7324,33 @@ virConnectDomainEventDeregister(virConne
 virConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback cb)
 {
-
-    if (!VIR_IS_CONNECT(conn)) {
-        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+    DEBUG("conn=%p, cb=%p", conn, cb);
+
+    virThreadResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virThreadSetGlobalError();
         return (-1);
     }
     if (cb == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
-    }
-    if ((conn->driver) && (conn->driver->domainEventDeregister))
-        return conn->driver->domainEventDeregister (conn, cb);
-
-    return -1;
-}
-
-
+        goto error;
+    }
+    if ((conn->driver) && (conn->driver->domainEventDeregister)) {
+        int ret;
+        ret = conn->driver->domainEventDeregister (conn, cb);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    /* Copy to connection error object for back compatability */
+    virThreadSetConnError(conn);
+    return -1;
+}
+
+
diff --git a/src/libvirt_sym.version.in b/src/libvirt_sym.version.in
--- a/src/libvirt_sym.version.in
+++ b/src/libvirt_sym.version.in
@@ -249,7 +249,13 @@ LIBVIRT_0.5.0 {
 
 } LIBVIRT_0.4.5;
 
-/* no new entry point in 0.5.1 */
+LIBVIRT_0.5.2 {
+    global:
+	virThreadGetLastError;
+	virThreadCopyLastError;
+	virThreadResetLastError;
+} LIBVIRT_0.5.0;
+
 /* .... define new API here using predicted next version number .... */
 
 
diff --git a/src/virterror.c b/src/virterror.c
--- a/src/virterror.c
+++ b/src/virterror.c
@@ -17,11 +17,14 @@
 
 #include "virterror_internal.h"
 #include "datatypes.h"
+#include "memory.h"
 
-virError virLastErr =       /* the last error */
+static virError virLastErr =       /* the last error */
   { .code = 0, .domain = 0, .message = NULL, .level = VIR_ERR_NONE,
     .conn = NULL, .dom = NULL, .str1 = NULL, .str2 = NULL, .str3 = NULL,
     .int1 = 0, .int2 = 0, .net = NULL };
+static PTHREAD_MUTEX_T(virLastErrLock);
+
 virErrorFunc virErrorHandler = NULL;     /* global error handler */
 void *virUserData = NULL;        /* associated data */
 
@@ -62,12 +65,49 @@ void *virUserData = NULL;        /* asso
     }}								\
 }
 
-/*
+static int
+virCopyError(virErrorPtr from,
+             virErrorPtr to)
+{
+    int ret = 0;
+    if (!to)
+        return 0;
+    virResetError(to);
+    if (!from)
+        return 0;
+    to->code = from->code;
+    to->domain = from->domain;
+    to->level = from->level;
+    if (from->message && !(to->message = strdup(from->message)))
+        ret = -1;
+    if (from->str1 && !(to->str1 = strdup(from->str1)))
+        ret = -1;
+    if (from->str2 && !(to->str2 = strdup(from->str2)))
+        ret = -1;
+    if (from->str3 && !(to->str3 = strdup(from->str3)))
+        ret = -1;
+    to->int1 = from->int1;
+    to->int2 = from->int2;
+    /*
+     * Delibrately not setting 'conn', 'dom', 'net' references
+     */
+    return ret;
+}
+
+
+
+/**
  * virGetLastError:
  *
  * Provide a pointer to the last error caught at the library level
- * Simpler but may not be suitable for multithreaded accesses, in which
- * case use virCopyLastError()
+ *
+ * This function is not safe for use in a multi-threaded
+ * application. Use virThreadGetLastError() instead.
+ *
+ * This function is also not very suitable for single-threaded
+ * applications because for any API call, it is impossible
+ * to determine whether an error was set globally or on the
+ * connection. Always use virThreadGetLastError()
  *
  * Returns a pointer to the last error or NULL if none occurred.
  */
@@ -79,11 +119,20 @@ virGetLastError(void)
     return (&virLastErr);
 }
 
-/*
+/**
  * virCopyLastError:
  * @to: target to receive the copy
  *
  * Copy the content of the last error caught at the library level
+ *
+ * This function is not safe for use in a multi-threaded
+ * application. Use virThreadCopyLastError() instead.
+ *
+ * This function is also not very suitable for single-threaded
+ * applications because for any API call, it is impossible
+ * to determine whether an error was set globally or on the
+ * connection. Always use virThreadCopyLastError()
+ *
  * One will need to free the result with virResetError()
  *
  * Returns 0 if no error was found and the error code otherwise and -1 in case
@@ -92,12 +141,8 @@ int
 int
 virCopyLastError(virErrorPtr to)
 {
-    if (to == NULL)
-        return (-1);
-    if (virLastErr.code == VIR_ERR_OK)
-        return (0);
-    memcpy(to, &virLastErr, sizeof(virError));
-    return (virLastErr.code);
+    virCopyError(&virLastErr, to);
+    return to->code;
 }
 
 /**
@@ -118,10 +163,19 @@ virResetError(virErrorPtr err)
     memset(err, 0, sizeof(virError));
 }
 
+
 /**
  * virResetLastError:
  *
  * Reset the last error caught at the library level.
+ *
+ * This function is not safe for use in a multi-threaded
+ * application. Use virThreadResetLastError() instead.
+ *
+ * This function is also not very suitable for single-threaded
+ * applications because for any API call, it is impossible
+ * to determine whether an error was set globally or on the
+ * connection. Always use virThreadResetLastError()
  */
 void
 virResetLastError(void)
@@ -134,8 +188,14 @@ virResetLastError(void)
  * @conn: pointer to the hypervisor connection
  *
  * Provide a pointer to the last error caught on that connection
- * Simpler but may not be suitable for multithreaded accesses, in which
- * case use virConnCopyLastError()
+ *
+ * This function is not safe for use in a multi-threaded
+ * application. Use virThreadGetLastError() instead.
+ *
+ * This function is also not very suitable for single-threaded
+ * applications because for any API call, it is impossible
+ * to determine whether an error was set globally or on the
+ * connection. Always use virThreadGetLastError()
  *
  * Returns a pointer to the last error or NULL if none occurred.
  */
@@ -153,6 +213,15 @@ virConnGetLastError(virConnectPtr conn)
  * @to: target to receive the copy
  *
  * Copy the content of the last error caught on that connection
+ *
+ * This function is not safe for use in a multi-threaded
+ * application. Use virThreadCopyLastError() instead.
+ *
+ * This function is also not very suitable for single-threaded
+ * applications because for any API call, it is impossible
+ * to determine whether an error was set globally or on the
+ * connection. Always use virThreadCopyLastError()
+ *
  * One will need to free the result with virResetError()
  *
  * Returns 0 if no error was found and the error code otherwise and -1 in case
@@ -163,17 +232,21 @@ virConnCopyLastError(virConnectPtr conn,
 {
     if (conn == NULL)
         return (-1);
-    if (to == NULL)
-        return (-1);
-    if (conn->err.code == VIR_ERR_OK)
-        return (0);
-    memcpy(to, &conn->err, sizeof(virError));
-    return (conn->err.code);
+    virCopyError(&conn->err, to);
+    return to->code;
 }
 
 /**
  * virConnResetLastError:
  * @conn: pointer to the hypervisor connection
+ *
+ * This function is not safe for use in a multi-threaded
+ * application. Use virThreadResetLastError() instead.
+ *
+ * This function is also not very suitable for single-threaded
+ * applications because for any API call, it is impossible
+ * to determine whether an error was set globally or on the
+ * connection. Always use virThreadResetLastError()
  *
  * Reset the last error caught on that connection
  */
@@ -217,8 +290,10 @@ virConnSetErrorFunc(virConnectPtr conn, 
 {
     if (conn == NULL)
         return;
+    pthread_mutex_lock(&conn->lock);
     conn->handler = handler;
     conn->userData = userData;
+    pthread_mutex_unlock(&conn->lock);
 }
 
 /**
@@ -338,6 +413,146 @@ virDefaultErrorFunc(virErrorPtr err)
                 dom, lvl, domain, network, err->message);
 }
 
+
+pthread_once_t virErrorKeyInit = PTHREAD_ONCE_INIT;
+pthread_key_t virErrorKey;
+
+static void
+virErrorKeyFreeData(void *data)
+{
+    virErrorPtr err = data;
+    virResetError(err);
+    VIR_FREE(err);
+}
+
+static void
+virErrorKeyCreate(void)
+{
+    pthread_key_create(&virErrorKey, virErrorKeyFreeData);
+}
+
+
+static void
+virErrorGenericFailure(virErrorPtr err)
+{
+    err->code = VIR_ERR_INTERNAL_ERROR;
+    err->domain = VIR_FROM_NONE;
+    err->level = VIR_ERR_ERROR;
+    err->message = strdup(_("Unknown failure"));
+}
+
+/**
+ * virThreadGetLastError:
+ *
+ * Provide a pointer to the last error caught during an API
+ * call in this thread.
+ *
+ * The contents of the returned error object are only valid
+ * until the next API call is made, or until the thread exits
+ *
+ * Returns a pointer to the last error or NULL if none occurred.
+ */
+virErrorPtr
+virThreadGetLastError(void)
+{
+    virErrorPtr err;
+    pthread_once(&virErrorKeyInit, virErrorKeyCreate);
+    err = pthread_getspecific(virErrorKey);
+    if (!err) {
+        if (VIR_ALLOC(err) < 0)
+            return NULL;
+        pthread_setspecific(virErrorKey, err);
+    }
+    return err;
+}
+
+
+/**
+ * virThreadCopyLastError:
+ * @to: target to receive the copy
+ *
+ * Copy the content of the last error caught during an API
+ * call in this thread.
+ *
+ * One will need to free the result with virResetError()
+ *
+ * Returns 0 if no error was found and the error code otherwise and -1 in case
+ *         of parameter error.
+ */
+int
+virThreadCopyLastError (virErrorPtr to)
+{
+    virErrorPtr err;
+
+    err = virThreadGetLastError();
+    if (virCopyError(err, to) < 0)
+        return -1;
+
+    return to->code;
+}
+
+
+/**
+ * virThreadResetLastError:
+ *
+ * Reset the last error caught during an API call
+ * in this thread
+ */
+void
+virThreadResetLastError (void)
+{
+    virErrorPtr err;
+
+    err = virThreadGetLastError();
+    if (err)
+        virResetError(err);
+}
+
+
+/**
+ * virThreadSetConnError:
+ *
+ * Initialize the global error with the contents of the
+ * the thread local error
+ */
+void
+virThreadSetGlobalError(void)
+{
+    virErrorPtr err;
+
+    err = virThreadGetLastError();
+
+    if (err && err->code == VIR_ERR_OK)
+        virErrorGenericFailure(err);
+
+    pthread_mutex_lock(&virLastErrLock);
+    virCopyError(err, &virLastErr);
+    pthread_mutex_unlock(&virLastErrLock);
+}
+
+/**
+ * virThreadSetConnError:
+ *
+ * Initialize the connection error with the contents of the
+ * the thread local error
+ */
+void
+virThreadSetConnError(virConnectPtr conn)
+{
+    virErrorPtr err;
+
+    err = virThreadGetLastError();
+
+    if (err && err->code == VIR_ERR_OK)
+        virErrorGenericFailure(err);
+
+    pthread_mutex_lock(&conn->lock);
+    virCopyError(err, &conn->err);
+    pthread_mutex_unlock(&conn->lock);
+}
+
+
+
 /**
  * virRaiseError:
  * @conn: the connection to the hypervisor if available
@@ -358,15 +573,29 @@ virDefaultErrorFunc(virErrorPtr err)
  * immediately if a callback is found and store it for later handling.
  */
 void
-virRaiseError(virConnectPtr conn, virDomainPtr dom, virNetworkPtr net,
+virRaiseError(virConnectPtr conn,
+              virDomainPtr dom ATTRIBUTE_UNUSED,
+              virNetworkPtr net ATTRIBUTE_UNUSED,
               int domain, int code, virErrorLevel level,
               const char *str1, const char *str2, const char *str3,
               int int1, int int2, const char *msg, ...)
 {
-    virErrorPtr to = &virLastErr;
+    virErrorPtr to;
     void *userData = virUserData;
     virErrorFunc handler = virErrorHandler;
     char *str;
+
+    /*
+     * All errors are recorded in thread local storage
+     * For compatability, public API calls will copy them
+     * to the global or per-connection error object when
+     * neccessary
+     */
+    to = virThreadGetLastError();
+    if (!to)
+        return; /* Hit OOM allocating thread error object, sod all we can do now */
+
+    virResetError(to);
 
     if (code == VIR_ERR_OK)
         return;
@@ -375,11 +604,12 @@ virRaiseError(virConnectPtr conn, virDom
      * try to find the best place to save and report the error
      */
     if (conn != NULL) {
-        to = &conn->err;
+        pthread_mutex_lock(&conn->lock);
         if (conn->handler != NULL) {
             handler = conn->handler;
             userData = conn->userData;
         }
+        pthread_mutex_unlock(&conn->lock);
     }
 
     /*
@@ -395,9 +625,10 @@ virRaiseError(virConnectPtr conn, virDom
      * Save the information about the error
      */
     virResetError(to);
-    to->conn = conn;
-    to->dom = dom;
-    to->net = net;
+    /*
+     * Delibrately not setting conn, dom & net fields since
+     * they're utterly unsafe
+     */
     to->domain = domain;
     to->code = code;
     to->message = str;
diff --git a/src/virterror_internal.h b/src/virterror_internal.h
--- a/src/virterror_internal.h
+++ b/src/virterror_internal.h
@@ -24,7 +24,6 @@
 
 #include "internal.h"
 
-extern virError virLastErr;
 extern virErrorFunc virErrorHandler;
 extern void *virUserData;
 
@@ -53,4 +52,7 @@ void virReportErrorHelper(virConnectPtr 
   ATTRIBUTE_FORMAT(printf, 7, 8);
 
 
+void virThreadSetGlobalError(void);
+void virThreadSetConnError(virConnectPtr conn);
+
 #endif

-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list