]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Thread local error reporting
authorDaniel P. Berrange <berrange@redhat.com>
Tue, 20 Jan 2009 12:01:45 +0000 (12:01 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Tue, 20 Jan 2009 12:01:45 +0000 (12:01 +0000)
ChangeLog
src/datatypes.c
src/datatypes.h
src/libvirt.c
src/virterror.c
src/virterror_internal.h

index d961b59425b5010836c9df0d3ee84c2479d40b36..9a0c3f4c029a747d0cc2c49c8e8860b3751a96b6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+Tue Jan 20 12:01:53 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
+
+       Thread local error handling
+       * src/datatypes.c: Don't reference global error object directly
+       now that it is thread-local. Avoid passing 'conn' arg to error
+       routines if we just determined that the pointer is invalid
+       * src/datatypes.h: Add note about rules for locking when using
+       virConnectPtr members
+       * src/libvirt.c: Initialize error handling routines at startup.
+       Adapt driver API methods to reset last error upon entry, and
+       copy the global thread local error to the per-connection error
+       upon exit
+       * src/virterror.c, src/virterror_internal.h: Store the global
+       error object in a thread local variable. Provide a API to copy
+       the global error into a per-connection error object. Add an
+       initialization routine to setup the thread local
+
 Tue Jan 20 11:43:53 GMT 2009 Daniel P. Berrange <berrange@redhat.com>
 
        * src/remote_internal.c: Disable event watch when doing an
index f602ef230ecb21b11458be314b9d2713e1a461a2..d59c5b4bc23e6fe92bc37384372b0c0545f51b49 100644 (file)
@@ -195,8 +195,6 @@ virReleaseConnect(virConnectPtr conn) {
         virHashFree(conn->nodeDevices, (virHashDeallocator) virNodeDeviceFree);
 
     virResetError(&conn->err);
-    if (virLastErr.conn == conn)
-        virLastErr.conn = NULL;
 
     xmlFreeURI(conn->uri);
 
@@ -219,7 +217,7 @@ virUnrefConnect(virConnectPtr conn) {
     int refs;
 
     if ((!VIR_IS_CONNECT(conn))) {
-        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(-1);
     }
     virMutexLock(&conn->lock);
@@ -253,7 +251,7 @@ virGetDomain(virConnectPtr conn, const char *name, const unsigned char *uuid) {
     virDomainPtr ret = NULL;
 
     if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
-        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(NULL);
     }
     virMutexLock(&conn->lock);
@@ -323,10 +321,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);
@@ -358,7 +352,7 @@ virUnrefDomain(virDomainPtr domain) {
     int refs;
 
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
-        virLibConnError(domain->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(-1);
     }
     virMutexLock(&domain->conn->lock);
@@ -393,7 +387,7 @@ virGetNetwork(virConnectPtr conn, const char *name, const unsigned char *uuid) {
     virNetworkPtr ret = NULL;
 
     if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
-        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(NULL);
     }
     virMutexLock(&conn->lock);
@@ -459,11 +453,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);
@@ -494,7 +483,7 @@ virUnrefNetwork(virNetworkPtr network) {
     int refs;
 
     if (!VIR_IS_CONNECTED_NETWORK(network)) {
-        virLibConnError(network->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(-1);
     }
     virMutexLock(&network->conn->lock);
@@ -530,7 +519,7 @@ virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uui
     virStoragePoolPtr ret = NULL;
 
     if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) {
-        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(NULL);
     }
     virMutexLock(&conn->lock);
@@ -627,7 +616,7 @@ virUnrefStoragePool(virStoragePoolPtr pool) {
     int refs;
 
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
-        virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(-1);
     }
     virMutexLock(&pool->conn->lock);
@@ -664,7 +653,7 @@ virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const c
     virStorageVolPtr ret = NULL;
 
     if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (key == NULL)) {
-        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(NULL);
     }
     virMutexLock(&conn->lock);
@@ -765,7 +754,7 @@ virUnrefStorageVol(virStorageVolPtr vol) {
     int refs;
 
     if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) {
-        virLibConnError(vol->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(-1);
     }
     virMutexLock(&vol->conn->lock);
@@ -801,7 +790,7 @@ virGetNodeDevice(virConnectPtr conn, const char *name)
     virNodeDevicePtr ret = NULL;
 
     if ((!VIR_IS_CONNECT(conn)) || (name == NULL)) {
-        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
         return(NULL);
     }
     virMutexLock(&conn->lock);
index d1bc88f7610a698989ed16ac7936945c59635dd5..5956c5daea61423576efce40c19fd1d3d2fc38a3 100644 (file)
  * 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
      */
     virMutex 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 */
index 900bc62d876598d942dabf22273d4347d6779a95..ae1a04e3cc0267f2e6195ac8a12522e410b03095 100644 (file)
@@ -256,7 +256,8 @@ virInitialize(void)
 
     initialized = 1;
 
-    if (virThreadInitialize() < 0)
+    if (virThreadInitialize() < 0 ||
+        virErrorInitialize() < 0)
         return -1;
 
 #ifdef ENABLE_DEBUG
@@ -847,6 +848,8 @@ do_open (const char *name,
     int i, res;
     virConnectPtr ret;
 
+    virResetLastError();
+
     ret = virGetConnect();
     if (ret == NULL)
         return NULL;
@@ -1000,17 +1003,8 @@ do_open (const char *name,
 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"));
+    /* Ensure a global error is set in case driver forgot */
+    virSetGlobalError();
 
     virUnrefConnect(ret);
 
@@ -1105,8 +1099,12 @@ virConnectClose(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
-    if (!VIR_IS_CONNECT(conn))
+    virResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
+    }
 
     if (conn->networkDriver)
         conn->networkDriver->close (conn);
@@ -1128,12 +1126,20 @@ virConnectClose(virConnectPtr conn)
 int
 virDrvSupportsFeature (virConnectPtr conn, int feature)
 {
+    int ret;
     DEBUG("conn=%p, feature=%d", conn, feature);
 
-    if (!VIR_IS_CONNECT(conn))
+    virResetLastError();
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
+    }
 
-    return VIR_DRV_SUPPORTS_FEATURE (conn->driver, conn, feature);
+    ret = VIR_DRV_SUPPORTS_FEATURE (conn->driver, conn, feature);
+    /* Copy to connection error object for back compatability */
+    virSetConnError(conn);
+    return ret;
 }
 
 /**
@@ -1153,6 +1159,8 @@ virConnectGetType(virConnectPtr conn)
     const char *ret;
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
@@ -1183,20 +1191,30 @@ virConnectGetVersion(virConnectPtr conn, unsigned long *hvVer)
 {
     DEBUG("conn=%p, hvVer=%p", conn, hvVer);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
+        return -1;
     }
 
     if (hvVer == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->version)
-        return conn->driver->version (conn, hvVer);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -1217,15 +1235,25 @@ virConnectGetHostname (virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return NULL;
     }
 
-    if (conn->driver->getHostname)
-        return conn->driver->getHostname (conn);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -1248,9 +1276,10 @@ char *
 virConnectGetURI (virConnectPtr conn)
 {
     char *name;
-
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return NULL;
@@ -1259,15 +1288,23 @@ virConnectGetURI (virConnectPtr conn)
     /* 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 */
+    virSetConnError(conn);
+    return NULL;
 }
 
 /**
@@ -1287,15 +1324,24 @@ virConnectGetMaxVcpus(virConnectPtr conn,
 {
     DEBUG("conn=%p, type=%s", conn, type);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
+        return -1;
     }
 
-    if (conn->driver->getMaxVcpus)
-        return conn->driver->getMaxVcpus (conn, type);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -1314,20 +1360,29 @@ virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
 {
     DEBUG("conn=%p, ids=%p, maxids=%d", conn, ids, maxids);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
+        return -1;
     }
 
     if ((ids == NULL) || (maxids < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->listDomains)
-        return conn->driver->listDomains (conn, ids, maxids);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -1344,15 +1399,24 @@ virConnectNumOfDomains(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->numOfDomains)
-        return conn->driver->numOfDomains (conn);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -1375,7 +1439,9 @@ virDomainGetConnect (virDomainPtr dom)
 {
     DEBUG("dom=%p", dom);
 
-    if (!VIR_IS_DOMAIN (dom)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return NULL;
     }
@@ -1403,23 +1469,33 @@ virDomainCreateXML(virConnectPtr conn, const char *xmlDesc,
 {
     DEBUG("conn=%p, xmlDesc=%s, flags=%d", conn, xmlDesc, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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);
+        goto error;
     }
 
-    if (conn->driver->domainCreateXML)
-        return conn->driver->domainCreateXML (conn, xmlDesc, flags);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -1459,19 +1535,30 @@ virDomainLookupByID(virConnectPtr conn, int id)
 {
     DEBUG("conn=%p, id=%d", conn, id);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (id < 0) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (conn->driver->domainLookupByID)
-        return conn->driver->domainLookupByID (conn, id);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -1490,19 +1577,30 @@ virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
 {
     DEBUG("conn=%p, uuid=%s", conn, uuid);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (uuid == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (conn->driver->domainLookupByUUID)
-        return conn->driver->domainLookupByUUID (conn, uuid);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -1525,14 +1623,15 @@ virDomainLookupByUUIDString(virConnectPtr conn, const char *uuidstr)
 
     DEBUG("conn=%p, uuidstr=%s", conn, uuidstr);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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?
@@ -1550,12 +1649,17 @@ virDomainLookupByUUIDString(virConnectPtr conn, const char *uuidstr)
 
     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 */
+    virSetConnError(conn);
+    return NULL;
 }
 
 /**
@@ -1573,19 +1677,30 @@ virDomainLookupByName(virConnectPtr conn, const char *name)
 {
     DEBUG("conn=%p, name=%s", conn, name);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (name == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (conn->driver->domainLookupByName)
-        return conn->driver->domainLookupByName (conn, name);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -1607,6 +1722,8 @@ virDomainDestroy(virDomainPtr domain)
 
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
@@ -1615,13 +1732,22 @@ virDomainDestroy(virDomainPtr domain)
     conn = domain->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->domainDestroy)
-        return conn->driver->domainDestroy (domain);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -1639,12 +1765,14 @@ virDomainFree(virDomainPtr domain)
 {
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_DOMAIN(domain)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
     }
     if (virUnrefDomain(domain) < 0)
-        return (-1);
+        return -1;
     return(0);
 }
 
@@ -1666,21 +1794,32 @@ virDomainSuspend(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     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);
+        goto error;
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainSuspend)
-        return conn->driver->domainSuspend (domain);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -1700,21 +1839,32 @@ virDomainResume(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     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);
+        goto error;
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainResume)
-        return conn->driver->domainResume (domain);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -1737,18 +1887,20 @@ virDomainSave(virDomainPtr domain, const char *to)
     virConnectPtr conn;
     DEBUG("domain=%p, to=%s", domain, to);
 
+    virResetLastError();
+
     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);
+        goto error;
     }
     conn = domain->conn;
     if (to == NULL) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     /*
@@ -1771,10 +1923,19 @@ virDomainSave(virDomainPtr domain, const char *to)
 
     }
 
-    if (conn->driver->domainSave)
-        return conn->driver->domainSave (domain, to);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -1793,17 +1954,19 @@ virDomainRestore(virConnectPtr conn, const char *from)
     char filepath[4096];
     DEBUG("conn=%p, from=%s", conn, from);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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;
     }
 
     /*
@@ -1814,21 +1977,36 @@ virDomainRestore(virConnectPtr conn, const char *from)
         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);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -1851,18 +2029,20 @@ virDomainCoreDump(virDomainPtr domain, const char *to, int flags)
     virConnectPtr conn;
     DEBUG("domain=%p, to=%s, flags=%d", domain, to, flags);
 
+    virResetLastError();
+
     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);
+        goto error;
     }
     conn = domain->conn;
     if (to == NULL) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     /*
@@ -1873,22 +2053,37 @@ virDomainCoreDump(virDomainPtr domain, const char *to, int flags)
         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);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -1911,21 +2106,32 @@ virDomainShutdown(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     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);
+        goto error;
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainShutdown)
-        return conn->driver->domainShutdown (domain);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -1946,21 +2152,32 @@ virDomainReboot(virDomainPtr domain, unsigned int flags)
     virConnectPtr conn;
     DEBUG("domain=%p, flags=%u", domain, flags);
 
+    virResetLastError();
+
     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);
+        goto error;
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainReboot)
-        return conn->driver->domainReboot (domain, flags);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -1978,6 +2195,8 @@ virDomainGetName(virDomainPtr domain)
 {
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     if (!VIR_IS_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (NULL);
@@ -1999,12 +2218,16 @@ virDomainGetUUID(virDomainPtr domain, unsigned char *uuid)
 {
     DEBUG("domain=%p, uuid=%p", domain, uuid);
 
+    virResetLastError();
+
     if (!VIR_IS_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
     }
     if (uuid == NULL) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        /* Copy to connection error object for back compatability */
+        virSetConnError(domain->conn);
         return (-1);
     }
 
@@ -2029,20 +2252,27 @@ virDomainGetUUIDString(virDomainPtr domain, char *buf)
     unsigned char uuid[VIR_UUID_BUFLEN];
     DEBUG("domain=%p, buf=%p", domain, buf);
 
+    virResetLastError();
+
     if (!VIR_IS_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         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 */
+    virSetConnError(domain->conn);
+    return -1;
 }
 
 /**
@@ -2058,6 +2288,8 @@ virDomainGetID(virDomainPtr domain)
 {
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     if (!VIR_IS_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return ((unsigned int) -1);
@@ -2080,17 +2312,28 @@ virDomainGetOSType(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (!VIR_IS_DOMAIN(domain)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (NULL);
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainGetOSType)
-        return conn->driver->domainGetOSType (domain);
+    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 */
+    virSetConnError(domain->conn);
     return NULL;
 }
 
@@ -2110,6 +2353,8 @@ virDomainGetMaxMemory(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (0);
@@ -2117,10 +2362,19 @@ virDomainGetMaxMemory(virDomainPtr domain)
 
     conn = domain->conn;
 
-    if (conn->driver->domainGetMaxMemory)
-        return conn->driver->domainGetMaxMemory (domain);
+    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 */
+    virSetConnError(domain->conn);
     return 0;
 }
 
@@ -2142,28 +2396,35 @@ virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
     virConnectPtr conn;
     DEBUG("domain=%p, memory=%lu", domain, memory);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
+    virResetLastError();
+
     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);
+        goto error;
     }
     if (memory < 4096) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
     conn = domain->conn;
 
-    if (conn->driver->domainSetMaxMemory)
-        return conn->driver->domainSetMaxMemory (domain, memory);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -2185,29 +2446,36 @@ virDomainSetMemory(virDomainPtr domain, unsigned long memory)
     virConnectPtr conn;
     DEBUG("domain=%p, memory=%lu", domain, memory);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
+    virResetLastError();
+
     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);
+        goto error;
     }
     if (memory < 4096) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainSetMemory)
-        return conn->driver->domainSetMemory (domain, memory);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -2228,23 +2496,34 @@ virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
     virConnectPtr conn;
     DEBUG("domain=%p, info=%p", domain, info);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         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);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -2265,17 +2544,28 @@ virDomainGetXMLDesc(virDomainPtr domain, int flags)
     virConnectPtr conn;
     DEBUG("domain=%p, flags=%d", domain, flags);
 
-    if (!VIR_IS_DOMAIN(domain)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (NULL);
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainDumpXML)
-        return conn->driver->domainDumpXML (domain, flags);
+    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 */
+    virSetConnError(domain->conn);
     return NULL;
 }
 
@@ -2344,24 +2634,26 @@ virDomainMigrate (virDomainPtr domain,
     DEBUG("domain=%p, dconn=%p, flags=%lu, dname=%s, uri=%s, bandwidth=%lu",
           domain, dconn, flags, dname, uri, bandwidth);
 
-    if (!VIR_IS_DOMAIN (domain)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN (domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return NULL;
     }
     conn = domain->conn;        /* Source connection. */
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return NULL;
+        goto error;
     }
 
     if (domain->conn->flags & VIR_CONNECT_RO) {
         virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return NULL;
+        goto error;
     }
     if (dconn->flags & VIR_CONNECT_RO) {
         /* NB, delibrately report error against source object, not dest here */
         virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return NULL;
+        goto error;
     }
 
     /* Check that migration is supported by both drivers. */
@@ -2377,7 +2669,7 @@ virDomainMigrate (virDomainPtr domain,
         version = 2;
     else {
         virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
-        return NULL;
+        goto error;
     }
 
     /* Prepare the migration.
@@ -2412,13 +2704,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,
@@ -2468,6 +2760,11 @@ virDomainMigrate (virDomainPtr domain,
     free (uri_out);
     free (cookie);
     return ddomain;
+
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(domain->conn);
+    return NULL;
 }
 
 /*
@@ -2486,6 +2783,8 @@ virDomainMigratePrepare (virConnectPtr dconn,
 {
     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);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return -1;
@@ -2493,15 +2792,24 @@ virDomainMigratePrepare (virConnectPtr dconn,
 
     if (dconn->flags & VIR_CONNECT_RO) {
         virLibConnError(dconn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return -1;
+        goto error;
     }
 
-    if (dconn->driver->domainMigratePrepare)
-        return dconn->driver->domainMigratePrepare (dconn, cookie, cookielen,
-                                                    uri_in, uri_out,
-                                                    flags, dname, bandwidth);
+    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 */
+    virSetConnError(dconn);
     return -1;
 }
 
@@ -2521,7 +2829,9 @@ virDomainMigratePerform (virDomainPtr domain,
     virConnectPtr conn;
     DEBUG("domain=%p, cookie=%p, cookielen=%d, uri=%s, flags=%lu, dname=%s, bandwidth=%lu", domain, cookie, cookielen, uri, flags, dname, bandwidth);
 
-    if (!VIR_IS_DOMAIN (domain)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN (domain)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return -1;
     }
@@ -2529,15 +2839,24 @@ virDomainMigratePerform (virDomainPtr domain,
 
     if (domain->conn->flags & VIR_CONNECT_RO) {
         virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return -1;
+        goto error;
     }
 
-    if (conn->driver->domainMigratePerform)
-        return conn->driver->domainMigratePerform (domain, cookie, cookielen,
-                                                   uri,
-                                                   flags, dname, bandwidth);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -2555,6 +2874,8 @@ virDomainMigrateFinish (virConnectPtr dconn,
 {
     DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, flags=%lu", dconn, dname, cookie, cookielen, uri, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return NULL;
@@ -2562,15 +2883,24 @@ virDomainMigrateFinish (virConnectPtr dconn,
 
     if (dconn->flags & VIR_CONNECT_RO) {
         virLibConnError(dconn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return NULL;
+        goto error;
     }
 
-    if (dconn->driver->domainMigrateFinish)
-        return dconn->driver->domainMigrateFinish (dconn, dname,
-                                                   cookie, cookielen,
-                                                   uri, flags);
+    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 */
+    virSetConnError(dconn);
     return NULL;
 }
 
@@ -2592,6 +2922,8 @@ virDomainMigratePrepare2 (virConnectPtr dconn,
 {
     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);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return -1;
@@ -2599,16 +2931,25 @@ virDomainMigratePrepare2 (virConnectPtr dconn,
 
     if (dconn->flags & VIR_CONNECT_RO) {
         virLibConnError(dconn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return -1;
+        goto error;
     }
 
-    if (dconn->driver->domainMigratePrepare2)
-        return dconn->driver->domainMigratePrepare2 (dconn, cookie, cookielen,
-                                                     uri_in, uri_out,
-                                                     flags, dname, bandwidth,
-                                                     dom_xml);
+    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 */
+    virSetConnError(dconn);
     return -1;
 }
 
@@ -2627,6 +2968,8 @@ virDomainMigrateFinish2 (virConnectPtr dconn,
 {
     DEBUG("dconn=%p, dname=%s, cookie=%p, cookielen=%d, uri=%s, flags=%lu, retcode=%d", dconn, dname, cookie, cookielen, uri, flags, retcode);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT (dconn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return NULL;
@@ -2634,16 +2977,25 @@ virDomainMigrateFinish2 (virConnectPtr dconn,
 
     if (dconn->flags & VIR_CONNECT_RO) {
         virLibConnError(dconn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return NULL;
+        goto error;
     }
 
-    if (dconn->driver->domainMigrateFinish2)
-        return dconn->driver->domainMigrateFinish2 (dconn, dname,
-                                                    cookie, cookielen,
-                                                    uri, flags,
-                                                    retcode);
+    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 */
+    virSetConnError(dconn);
     return NULL;
 }
 
@@ -2662,19 +3014,30 @@ virNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
 {
     DEBUG("conn=%p, info=%p", conn, info);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
     }
     if (info == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->nodeGetInfo)
-        return conn->driver->nodeGetInfo (conn, info);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -2693,15 +3056,26 @@ virConnectGetCapabilities (virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT (conn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return NULL;
     }
 
-    if (conn->driver->getCapabilities)
-        return conn->driver->getCapabilities (conn);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -2718,15 +3092,26 @@ virNodeGetFreeMemory(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT (conn)) {
         virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return 0;
     }
 
-    if (conn->driver->getFreeMemory)
-        return conn->driver->getFreeMemory (conn);
+    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 */
+    virSetConnError(conn);
     return 0;
 }
 
@@ -2746,6 +3131,8 @@ virDomainGetSchedulerType(virDomainPtr domain, int *nparams)
     char *schedtype;
     DEBUG("domain=%p, nparams=%p", domain, nparams);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return NULL;
@@ -2754,10 +3141,16 @@ virDomainGetSchedulerType(virDomainPtr domain, int *nparams)
 
     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 */
+    virSetConnError(domain->conn);
     return NULL;
 }
 
@@ -2783,16 +3176,27 @@ virDomainGetSchedulerParameters(virDomainPtr domain,
     virConnectPtr conn;
     DEBUG("domain=%p, params=%p, nparams=%p", domain, params, nparams);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -2815,20 +3219,31 @@ virDomainSetSchedulerParameters(virDomainPtr domain,
     virConnectPtr conn;
     DEBUG("domain=%p, params=%p, nparams=%d", domain, params, nparams);
 
+    virResetLastError();
+
     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;
+        goto error;
     }
     conn = domain->conn;
 
-    if (conn->driver->domainSetSchedulerParameters)
-        return conn->driver->domainSetSchedulerParameters (domain, params, nparams);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -2864,25 +3279,31 @@ virDomainBlockStats (virDomainPtr dom, const char *path,
     struct _virDomainBlockStats stats2 = { -1, -1, -1, -1, -1 };
     DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size);
 
-    if (!stats || size > sizeof stats2) {
-        virLibDomainError (dom, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return -1;
-    }
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return -1;
     }
+    if (!stats || size > sizeof stats2) {
+        virLibDomainError (dom, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        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 */
+    virSetConnError(dom->conn);
     return -1;
 }
 
@@ -2916,25 +3337,31 @@ virDomainInterfaceStats (virDomainPtr dom, const char *path,
                                                -1, -1, -1, -1 };
     DEBUG("domain=%p, path=%s, stats=%p, size=%zi", dom, path, stats, size);
 
-    if (!stats || size > sizeof stats2) {
-        virLibDomainError (dom, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return -1;
-    }
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return -1;
     }
+    if (!stats || size > sizeof stats2) {
+        virLibDomainError (dom, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        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 */
+    virSetConnError(dom->conn);
     return -1;
 }
 
@@ -2989,6 +3416,8 @@ virDomainBlockPeek (virDomainPtr dom,
     DEBUG("domain=%p, path=%s, offset=%lld, size=%zi, buffer=%p",
           dom, path, offset, size, buffer);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return -1;
@@ -2997,33 +3426,42 @@ virDomainBlockPeek (virDomainPtr dom,
 
     if (dom->conn->flags & VIR_CONNECT_RO) {
         virLibDomainError(dom, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     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;
+        goto error;
     }
 
-    if (conn->driver->domainBlockPeek)
-        return conn->driver->domainBlockPeek (dom, path, offset, size,
-                                              buffer, flags);
+    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 */
+    virSetConnError(dom->conn);
     return -1;
 }
 
@@ -3069,6 +3507,8 @@ virDomainMemoryPeek (virDomainPtr dom,
     DEBUG ("domain=%p, start=%lld, size=%zi, buffer=%p, flags=%d",
            dom, start, size, buffer, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
         virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return -1;
@@ -3077,7 +3517,7 @@ virDomainMemoryPeek (virDomainPtr dom,
 
     if (dom->conn->flags & VIR_CONNECT_RO) {
         virLibDomainError(dom, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     /* Flags must be VIR_MEMORY_VIRTUAL at the moment.
@@ -3104,21 +3544,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;
+        goto error;
     }
 
-    if (conn->driver->domainMemoryPeek)
-        return conn->driver->domainMemoryPeek (dom, start, size,
-                                               buffer, flags);
+    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 */
+    virSetConnError(dom->conn);
     return -1;
 }
 
@@ -3144,23 +3593,34 @@ virDomainPtr
 virDomainDefineXML(virConnectPtr conn, const char *xml) {
     DEBUG("conn=%p, xml=%s", conn, xml);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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);
+        goto error;
     }
 
-    if (conn->driver->domainDefineXML)
-        return conn->driver->domainDefineXML (conn, xml);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -3177,6 +3637,8 @@ virDomainUndefine(virDomainPtr domain) {
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
@@ -3184,13 +3646,22 @@ virDomainUndefine(virDomainPtr domain) {
     conn = domain->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->domainUndefine)
-        return conn->driver->domainUndefine (domain);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3207,15 +3678,26 @@ virConnectNumOfDefinedDomains(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
     }
 
-    if (conn->driver->numOfDefinedDomains)
-        return conn->driver->numOfDefinedDomains (conn);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -3235,6 +3717,8 @@ virConnectListDefinedDomains(virConnectPtr conn, char **const names,
                              int maxnames) {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
@@ -3242,13 +3726,22 @@ virConnectListDefinedDomains(virConnectPtr conn, char **const names,
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->listDefinedDomains)
-        return conn->driver->listDefinedDomains (conn, names, maxnames);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -3266,10 +3759,8 @@ virDomainCreate(virDomainPtr domain) {
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
@@ -3277,13 +3768,22 @@ virDomainCreate(virDomainPtr domain) {
     conn = domain->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->domainCreate)
-        return conn->driver->domainCreate (domain);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3305,21 +3805,32 @@ virDomainGetAutostart(virDomainPtr domain,
     virConnectPtr conn;
     DEBUG("domain=%p, autostart=%p", domain, autostart);
 
-    if (!VIR_IS_DOMAIN(domain)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
     }
     if (!autostart) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainGetAutostart)
-        return conn->driver->domainGetAutostart (domain, autostart);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3340,7 +3851,9 @@ virDomainSetAutostart(virDomainPtr domain,
     virConnectPtr conn;
     DEBUG("domain=%p, autostart=%d", domain, autostart);
 
-    if (!VIR_IS_DOMAIN(domain)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
     }
@@ -3349,13 +3862,22 @@ virDomainSetAutostart(virDomainPtr domain,
 
     if (domain->conn->flags & VIR_CONNECT_RO) {
         virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->domainSetAutostart)
-        return conn->driver->domainSetAutostart (domain, autostart);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3378,29 +3900,36 @@ virDomainSetVcpus(virDomainPtr domain, unsigned int nvcpus)
     virConnectPtr conn;
     DEBUG("domain=%p, nvcpus=%u", domain, nvcpus);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
+    virResetLastError();
+
     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);
+        goto error;
     }
 
     if (nvcpus < 1) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
     conn = domain->conn;
 
-    if (conn->driver->domainSetVcpus)
-        return conn->driver->domainSetVcpus (domain, nvcpus);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3429,30 +3958,37 @@ virDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
     virConnectPtr conn;
     DEBUG("domain=%p, vcpu=%u, cpumap=%p, maplen=%d", domain, vcpu, cpumap, maplen);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
+    virResetLastError();
+
     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);
+        goto error;
     }
 
     if ((vcpu > 32000) || (cpumap == NULL) || (maplen < 1)) {
         virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+       goto error;
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainPinVcpu)
-        return conn->driver->domainPinVcpu (domain, vcpu, cpumap, maplen);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3484,30 +4020,37 @@ virDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
     virConnectPtr conn;
     DEBUG("domain=%p, info=%p, maxinfo=%d, cpumaps=%p, maplen=%d", domain, info, maxinfo, cpumaps, maplen);
 
-    if (domain == NULL) {
-        TODO
-        return (-1);
-    }
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         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);
+        goto error;
     }
 
     conn = domain->conn;
 
-    if (conn->driver->domainGetVcpus)
-        return conn->driver->domainGetVcpus (domain, info, maxinfo,
-                                             cpumaps, maplen);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3529,6 +4072,8 @@ virDomainGetMaxVcpus(virDomainPtr domain)
     virConnectPtr conn;
     DEBUG("domain=%p", domain);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
         virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
         return (-1);
@@ -3536,10 +4081,19 @@ virDomainGetMaxVcpus(virDomainPtr domain)
 
     conn = domain->conn;
 
-    if (conn->driver->domainGetMaxVcpus)
-        return conn->driver->domainGetMaxVcpus (domain);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3559,20 +4113,31 @@ virDomainAttachDevice(virDomainPtr domain, const char *xml)
     virConnectPtr conn;
     DEBUG("domain=%p, xml=%s", domain, xml);
 
+    virResetLastError();
+
     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);
+        goto error;
     }
     conn = domain->conn;
 
-    if (conn->driver->domainAttachDevice)
-        return conn->driver->domainAttachDevice (domain, xml);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3591,20 +4156,31 @@ virDomainDetachDevice(virDomainPtr domain, const char *xml)
     virConnectPtr conn;
     DEBUG("domain=%p, xml=%s", domain, xml);
 
+    virResetLastError();
+
     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);
+        goto error;
     }
     conn = domain->conn;
 
-    if (conn->driver->domainDetachDevice)
-        return conn->driver->domainDetachDevice (domain, xml);
+    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 */
+    virSetConnError(domain->conn);
     return -1;
 }
 
@@ -3633,6 +4209,8 @@ virNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems,
     DEBUG("conn=%p, freeMems=%p, startCell=%d, maxCells=%d",
           conn, freeMems, startCell, maxCells);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
@@ -3640,13 +4218,22 @@ virNodeGetCellsFreeMemory(virConnectPtr conn, unsigned long long *freeMems,
 
     if ((freeMems == NULL) || (maxCells <= 0) || (startCell < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->driver->nodeGetCellsFreeMemory)
-        return conn->driver->nodeGetCellsFreeMemory (conn, freeMems, startCell, maxCells);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -3669,7 +4256,9 @@ virNetworkGetConnect (virNetworkPtr net)
 {
     DEBUG("net=%p", net);
 
-    if (!VIR_IS_NETWORK (net)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_NETWORK (net)) {
         virLibNetworkError (NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return NULL;
     }
@@ -3689,15 +4278,26 @@ virConnectNumOfNetworks(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -3716,6 +4316,8 @@ virConnectListNetworks(virConnectPtr conn, char **const names, int maxnames)
 {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
@@ -3723,13 +4325,22 @@ virConnectListNetworks(virConnectPtr conn, char **const names, int maxnames)
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->listNetworks)
-        return conn->networkDriver->listNetworks (conn, names, maxnames);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -3746,15 +4357,26 @@ virConnectNumOfDefinedNetworks(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -3774,6 +4396,8 @@ virConnectListDefinedNetworks(virConnectPtr conn, char **const names,
 {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
@@ -3781,14 +4405,23 @@ virConnectListDefinedNetworks(virConnectPtr conn, char **const names,
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->listDefinedNetworks)
-        return conn->networkDriver->listDefinedNetworks (conn,
-                                                         names, maxnames);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -3807,19 +4440,30 @@ virNetworkLookupByName(virConnectPtr conn, const char *name)
 {
     DEBUG("conn=%p, name=%s", conn, name);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (name == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto  error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->networkLookupByName)
-        return conn->networkDriver->networkLookupByName (conn, name);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -3838,19 +4482,30 @@ virNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
 {
     DEBUG("conn=%p, uuid=%s", conn, uuid);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (uuid == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->networkLookupByUUID)
-        return conn->networkDriver->networkLookupByUUID (conn, uuid);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -3872,13 +4527,15 @@ virNetworkLookupByUUIDString(virConnectPtr conn, const char *uuidstr)
     int ret;
     DEBUG("conn=%p, uuidstr=%s", conn, uuidstr);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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.
@@ -3897,12 +4554,17 @@ virNetworkLookupByUUIDString(virConnectPtr conn, const char *uuidstr)
 
     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 */
+    virSetConnError(conn);
+    return NULL;
 }
 
 /**
@@ -3920,23 +4582,34 @@ virNetworkCreateXML(virConnectPtr conn, const char *xmlDesc)
 {
     DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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);
+        goto error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->networkCreateXML)
-        return conn->networkDriver->networkCreateXML (conn, xmlDesc);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -3954,23 +4627,34 @@ virNetworkDefineXML(virConnectPtr conn, const char *xml)
 {
     DEBUG("conn=%p, xml=%s", conn, xml);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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);
+        goto error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->networkDefineXML)
-        return conn->networkDriver->networkDefineXML (conn, xml);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -3987,6 +4671,8 @@ virNetworkUndefine(virNetworkPtr network) {
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
@@ -3994,13 +4680,22 @@ virNetworkUndefine(virNetworkPtr network) {
     conn = network->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->networkUndefine)
-        return conn->networkDriver->networkUndefine (network);
+    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 */
+    virSetConnError(network->conn);
     return -1;
 }
 
@@ -4019,10 +4714,8 @@ virNetworkCreate(virNetworkPtr network)
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
-    if (network == NULL) {
-        TODO
-        return (-1);
-    }
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
@@ -4030,13 +4723,22 @@ virNetworkCreate(virNetworkPtr network)
     conn = network->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->networkCreate)
-        return conn->networkDriver->networkCreate (network);
+    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 */
+    virSetConnError(network->conn);
     return -1;
 }
 
@@ -4057,6 +4759,8 @@ virNetworkDestroy(virNetworkPtr network)
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
@@ -4065,13 +4769,22 @@ virNetworkDestroy(virNetworkPtr network)
     conn = network->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->networkDriver && conn->networkDriver->networkDestroy)
-        return conn->networkDriver->networkDestroy (network);
+    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 */
+    virSetConnError(network->conn);
     return -1;
 }
 
@@ -4089,7 +4802,9 @@ virNetworkFree(virNetworkPtr network)
 {
     DEBUG("network=%p", network);
 
-    if (!VIR_IS_NETWORK(network)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
     }
@@ -4112,6 +4827,8 @@ virNetworkGetName(virNetworkPtr network)
 {
     DEBUG("network=%p", network);
 
+    virResetLastError();
+
     if (!VIR_IS_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (NULL);
@@ -4133,18 +4850,25 @@ virNetworkGetUUID(virNetworkPtr network, unsigned char *uuid)
 {
     DEBUG("network=%p, uuid=%p", network, uuid);
 
+    virResetLastError();
+
     if (!VIR_IS_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         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 */
+    virSetConnError(network->conn);
+    return -1;
 }
 
 /**
@@ -4163,13 +4887,15 @@ virNetworkGetUUIDString(virNetworkPtr network, char *buf)
     unsigned char uuid[VIR_UUID_BUFLEN];
     DEBUG("network=%p, buf=%p", network, buf);
 
+    virResetLastError();
+
     if (!VIR_IS_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
     }
     if (buf == NULL) {
         virLibNetworkError(network, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     if (virNetworkGetUUID(network, &uuid[0]))
@@ -4177,6 +4903,11 @@ virNetworkGetUUIDString(virNetworkPtr network, char *buf)
 
     virUUIDFormat(uuid, buf);
     return (0);
+
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(network->conn);
+    return -1;
 }
 
 /**
@@ -4196,21 +4927,32 @@ virNetworkGetXMLDesc(virNetworkPtr network, int flags)
     virConnectPtr conn;
     DEBUG("network=%p, flags=%d", network, flags);
 
-    if (!VIR_IS_NETWORK(network)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         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);
+    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 */
+    virSetConnError(network->conn);
     return NULL;
 }
 
@@ -4230,17 +4972,28 @@ virNetworkGetBridgeName(virNetworkPtr network)
     virConnectPtr conn;
     DEBUG("network=%p", network);
 
-    if (!VIR_IS_NETWORK(network)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (NULL);
     }
 
     conn = network->conn;
 
-    if (conn->networkDriver && conn->networkDriver->networkGetBridgeName)
-        return conn->networkDriver->networkGetBridgeName (network);
+    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 */
+    virSetConnError(network->conn);
     return NULL;
 }
 
@@ -4262,21 +5015,32 @@ virNetworkGetAutostart(virNetworkPtr network,
     virConnectPtr conn;
     DEBUG("network=%p, autostart=%p", network, autostart);
 
-    if (!VIR_IS_NETWORK(network)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         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);
+    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 */
+    virSetConnError(network->conn);
     return -1;
 }
 
@@ -4297,22 +5061,33 @@ virNetworkSetAutostart(virNetworkPtr network,
     virConnectPtr conn;
     DEBUG("network=%p, autostart=%d", network, autostart);
 
-    if (!VIR_IS_NETWORK(network)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_NETWORK(network)) {
         virLibNetworkError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
     }
 
     if (network->conn->flags & VIR_CONNECT_RO) {
         virLibNetworkError(network, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     conn = network->conn;
 
-    if (conn->networkDriver && conn->networkDriver->networkSetAutostart)
-        return conn->networkDriver->networkSetAutostart (network, autostart);
+    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 */
+    virSetConnError(network->conn);
     return -1;
 }
 
@@ -4336,7 +5111,9 @@ virStoragePoolGetConnect (virStoragePoolPtr pool)
 {
     DEBUG("pool=%p", pool);
 
-    if (!VIR_IS_STORAGE_POOL (pool)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_STORAGE_POOL (pool)) {
         virLibStoragePoolError (NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return NULL;
     }
@@ -4356,15 +5133,26 @@ virConnectNumOfStoragePools     (virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -4387,6 +5175,8 @@ virConnectListStoragePools        (virConnectPtr conn,
 {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
@@ -4394,15 +5184,23 @@ virConnectListStoragePools      (virConnectPtr conn,
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->listPools)
-        return conn->storageDriver->listPools (conn, names, maxnames);
+    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__);
-    return -1;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(conn);
+    return -1;
 }
 
 
@@ -4419,15 +5217,26 @@ virConnectNumOfDefinedStoragePools(virConnectPtr conn)
 {
     DEBUG("conn=%p", conn);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -4451,6 +5260,8 @@ virConnectListDefinedStoragePools(virConnectPtr conn,
 {
     DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
@@ -4458,13 +5269,22 @@ virConnectListDefinedStoragePools(virConnectPtr conn,
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->listDefinedPools)
-        return conn->storageDriver->listDefinedPools (conn, names, maxnames);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -4496,24 +5316,37 @@ virConnectFindStoragePoolSources(virConnectPtr conn,
                                  const char *srcSpec,
                                  unsigned int flags)
 {
+    DEBUG("conn=%p, type=%s, src=%s, flags=%u", conn, type ? type : "", srcSpec ? srcSpec : "", flags);
+
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
-        return NULL;
+        goto error;
     }
     if (type == 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;
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->findPoolSources)
-        return conn->storageDriver->findPoolSources(conn, type, srcSpec, flags);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -4533,19 +5366,30 @@ virStoragePoolLookupByName(virConnectPtr conn,
 {
     DEBUG("conn=%p, name=%s", conn, name);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (name == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolLookupByName)
-        return conn->storageDriver->poolLookupByName (conn, name);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -4565,21 +5409,31 @@ virStoragePoolLookupByUUID(virConnectPtr conn,
 {
     DEBUG("conn=%p, uuid=%s", conn, uuid);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (uuid == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolLookupByUUID)
-        return conn->storageDriver->poolLookupByUUID (conn, uuid);
+    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__);
-    return NULL;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(conn);
+    return NULL;
 }
 
 
@@ -4594,26 +5448,33 @@ virStoragePoolLookupByUUID(virConnectPtr conn,
  */
 virStoragePoolPtr
 virStoragePoolLookupByUUIDString(virConnectPtr conn,
-                                                                 const char *uuidstr)
+                                 const char *uuidstr)
 {
     unsigned char uuid[VIR_UUID_BUFLEN];
     DEBUG("conn=%p, uuidstr=%s", conn, uuidstr);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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 */
+    virSetConnError(conn);
+    return NULL;
 }
 
 
@@ -4630,17 +5491,27 @@ virStoragePoolLookupByVolume(virStorageVolPtr vol)
 {
     DEBUG("vol=%p", vol);
 
-    if (!VIR_IS_STORAGE_VOL(vol)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_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);
+    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 */
+    virSetConnError(vol->conn);
+    return NULL;
 }
 
 /**
@@ -4662,23 +5533,34 @@ virStoragePoolCreateXML(virConnectPtr conn,
 {
     DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolCreateXML)
-        return conn->storageDriver->poolCreateXML (conn, xmlDesc, flags);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -4700,25 +5582,35 @@ virStoragePoolDefineXML(virConnectPtr conn,
 {
     DEBUG("conn=%p, xml=%s", conn, xml);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         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);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolDefineXML)
-        return conn->storageDriver->poolDefineXML (conn, xml, flags);
+    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__);
-    return NULL;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(conn);
+    return NULL;
 }
 
 /**
@@ -4737,6 +5629,8 @@ virStoragePoolBuild(virStoragePoolPtr pool,
     virConnectPtr conn;
     DEBUG("pool=%p, flags=%u", pool, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
@@ -4744,15 +5638,23 @@ virStoragePoolBuild(virStoragePoolPtr pool,
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolBuild)
-        return conn->storageDriver->poolBuild (pool, flags);
+    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__);
-    return -1;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -4770,6 +5672,8 @@ virStoragePoolUndefine(virStoragePoolPtr pool)
     virConnectPtr conn;
     DEBUG("pool=%p", pool);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__);
         return (-1);
@@ -4777,15 +5681,23 @@ virStoragePoolUndefine(virStoragePoolPtr pool)
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolUndefine)
-        return conn->storageDriver->poolUndefine (pool);
+    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__);
-    return -1;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -4805,10 +5717,8 @@ virStoragePoolCreate(virStoragePoolPtr pool,
     virConnectPtr conn;
     DEBUG("pool=%p", pool);
 
-    if (pool == NULL) {
-        TODO;
-        return (-1);
-    }
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (-1);
@@ -4816,15 +5726,23 @@ virStoragePoolCreate(virStoragePoolPtr pool,
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolCreate)
-        return conn->storageDriver->poolCreate (pool, flags);
+    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__);
-    return -1;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -4846,6 +5764,8 @@ virStoragePoolDestroy(virStoragePoolPtr pool)
     virConnectPtr conn;
     DEBUG("pool=%p", pool);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (-1);
@@ -4854,13 +5774,22 @@ virStoragePoolDestroy(virStoragePoolPtr pool)
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolDestroy)
-        return conn->storageDriver->poolDestroy (pool);
+    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 */
+    virSetConnError(pool->conn);
     return -1;
 }
 
@@ -4882,6 +5811,8 @@ virStoragePoolDelete(virStoragePoolPtr pool,
     virConnectPtr conn;
     DEBUG("pool=%p, flags=%u", pool, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (-1);
@@ -4890,13 +5821,22 @@ virStoragePoolDelete(virStoragePoolPtr pool,
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolDelete)
-        return conn->storageDriver->poolDelete (pool, flags);
+    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 */
+    virSetConnError(pool->conn);
     return -1;
 }
 
@@ -4915,7 +5855,9 @@ virStoragePoolFree(virStoragePoolPtr pool)
 {
     DEBUG("pool=%p", pool);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (-1);
     }
@@ -4944,6 +5886,8 @@ virStoragePoolRefresh(virStoragePoolPtr pool,
     virConnectPtr conn;
     DEBUG("pool=%p flags=%u", pool, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (-1);
@@ -4952,13 +5896,22 @@ virStoragePoolRefresh(virStoragePoolPtr pool,
     conn = pool->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->poolRefresh)
-        return conn->storageDriver->poolRefresh (pool, flags);
+    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 */
+    virSetConnError(pool->conn);
     return -1;
 }
 
@@ -4976,12 +5929,13 @@ virStoragePoolGetName(virStoragePoolPtr pool)
 {
     DEBUG("pool=%p", pool);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (NULL);
     }
     return (pool->name);
-
 }
 
 
@@ -5000,19 +5954,25 @@ virStoragePoolGetUUID(virStoragePoolPtr pool,
 {
     DEBUG("pool=%p, uuid=%p", pool, uuid);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         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 */
+    virSetConnError(pool->conn);
+    return -1;
 }
 
 /**
@@ -5031,21 +5991,27 @@ virStoragePoolGetUUIDString(virStoragePoolPtr pool,
     unsigned char uuid[VIR_UUID_BUFLEN];
     DEBUG("pool=%p, buf=%p", pool, buf);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         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 */
+    virSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -5066,25 +6032,35 @@ virStoragePoolGetInfo(virStoragePoolPtr pool,
     virConnectPtr conn;
     DEBUG("pool=%p, info=%p", pool, info);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         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);
+    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__);
-    return -1;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(pool->conn);
+    return -1;
 }
 
 
@@ -5106,23 +6082,33 @@ virStoragePoolGetXMLDesc(virStoragePoolPtr pool,
     virConnectPtr conn;
     DEBUG("pool=%p, flags=%u", pool, flags);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (NULL);
     }
     if (flags != 0) {
         virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
     conn = pool->conn;
 
-    if (conn->storageDriver && conn->storageDriver->poolGetXMLDesc)
-        return conn->storageDriver->poolGetXMLDesc (pool, flags);
+    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__);
-    return NULL;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(pool->conn);
+    return NULL;
 }
 
 
@@ -5143,21 +6129,32 @@ virStoragePoolGetAutostart(virStoragePoolPtr pool,
     virConnectPtr conn;
     DEBUG("pool=%p, autostart=%p", pool, autostart);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (-1);
     }
     if (!autostart) {
         virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     conn = pool->conn;
 
-    if (conn->storageDriver && conn->storageDriver->poolGetAutostart)
-        return conn->storageDriver->poolGetAutostart (pool, autostart);
+    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 */
+    virSetConnError(pool->conn);
     return -1;
 }
 
@@ -5178,22 +6175,33 @@ virStoragePoolSetAutostart(virStoragePoolPtr pool,
     virConnectPtr conn;
     DEBUG("pool=%p, autostart=%d", pool, autostart);
 
-    if (!VIR_IS_STORAGE_POOL(pool)) {
+    virResetLastError();
+
+    if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) {
         virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     if (pool->conn->flags & VIR_CONNECT_RO) {
         virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
     conn = pool->conn;
 
-    if (conn->storageDriver && conn->storageDriver->poolSetAutostart)
-        return conn->storageDriver->poolSetAutostart (pool, autostart);
+    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 */
+    virSetConnError(pool->conn);
     return -1;
 }
 
@@ -5211,15 +6219,26 @@ virStoragePoolNumOfVolumes(virStoragePoolPtr pool)
 {
     DEBUG("pool=%p", pool);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(pool->conn);
     return -1;
 }
 
@@ -5242,6 +6261,8 @@ virStoragePoolListVolumes(virStoragePoolPtr pool,
 {
     DEBUG("pool=%p, names=%p, maxnames=%d", pool, names, maxnames);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__);
         return (-1);
@@ -5249,13 +6270,22 @@ virStoragePoolListVolumes(virStoragePoolPtr pool,
 
     if ((names == NULL) || (maxnames < 0)) {
         virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (pool->conn->storageDriver && pool->conn->storageDriver->poolListVolumes)
-        return pool->conn->storageDriver->poolListVolumes (pool, names, maxnames);
+    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 */
+    virSetConnError(pool->conn);
     return -1;
 }
 
@@ -5279,6 +6309,8 @@ virStorageVolGetConnect (virStorageVolPtr vol)
 {
     DEBUG("vol=%p", vol);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_VOL (vol)) {
         virLibStoragePoolError (NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         return NULL;
@@ -5303,19 +6335,30 @@ virStorageVolLookupByName(virStoragePoolPtr pool,
 {
     DEBUG("pool=%p, name=%s", pool, name);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (name == NULL) {
         virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (pool->conn->storageDriver && pool->conn->storageDriver->volLookupByName)
-        return pool->conn->storageDriver->volLookupByName (pool, name);
+    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 */
+    virSetConnError(pool->conn);
     return NULL;
 }
 
@@ -5337,19 +6380,30 @@ virStorageVolLookupByKey(virConnectPtr conn,
 {
     DEBUG("conn=%p, key=%s", conn, key);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (key == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->volLookupByKey)
-        return conn->storageDriver->volLookupByKey (conn, key);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -5369,19 +6423,30 @@ virStorageVolLookupByPath(virConnectPtr conn,
 {
     DEBUG("conn=%p, path=%s", conn, path);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (NULL);
     }
     if (path == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->volLookupByPath)
-        return conn->storageDriver->volLookupByPath (conn, path);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -5400,6 +6465,8 @@ virStorageVolGetName(virStorageVolPtr vol)
 {
     DEBUG("vol=%p", vol);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         return (NULL);
@@ -5423,6 +6490,8 @@ virStorageVolGetKey(virStorageVolPtr vol)
 {
     DEBUG("vol=%p", vol);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         return (NULL);
@@ -5450,6 +6519,8 @@ virStorageVolCreateXML(virStoragePoolPtr pool,
 {
     DEBUG("pool=%p, flags=%u", pool, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_POOL(pool)) {
         virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         return (NULL);
@@ -5457,13 +6528,22 @@ virStorageVolCreateXML(virStoragePoolPtr pool,
 
     if (pool->conn->flags & VIR_CONNECT_RO) {
         virLibConnError(pool->conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (NULL);
+        goto error;
     }
 
-    if (pool->conn->storageDriver && pool->conn->storageDriver->volCreateXML)
-        return pool->conn->storageDriver->volCreateXML (pool, xmldesc, flags);
+    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 */
+    virSetConnError(pool->conn);
     return NULL;
 }
 
@@ -5484,6 +6564,8 @@ virStorageVolDelete(virStorageVolPtr vol,
     virConnectPtr conn;
     DEBUG("vol=%p, flags=%u", vol, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         return (-1);
@@ -5492,13 +6574,22 @@ virStorageVolDelete(virStorageVolPtr vol,
     conn = vol->conn;
     if (conn->flags & VIR_CONNECT_RO) {
         virLibStorageVolError(vol, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->storageDriver && conn->storageDriver->volDelete)
-        return conn->storageDriver->volDelete (vol, flags);
+    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 */
+    virSetConnError(vol->conn);
     return -1;
 }
 
@@ -5517,6 +6608,8 @@ virStorageVolFree(virStorageVolPtr vol)
 {
     DEBUG("vol=%p", vol);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         return (-1);
@@ -5544,23 +6637,34 @@ virStorageVolGetInfo(virStorageVolPtr vol,
     virConnectPtr conn;
     DEBUG("vol=%p, info=%p", vol, info);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         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);
+    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 */
+    virSetConnError(vol->conn);
     return -1;
 }
 
@@ -5582,23 +6686,33 @@ virStorageVolGetXMLDesc(virStorageVolPtr vol,
     virConnectPtr conn;
     DEBUG("vol=%p, flags=%u", vol, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         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);
+    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__);
-    return NULL;
 
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(vol->conn);
+    return NULL;
 }
 
 
@@ -5620,6 +6734,8 @@ virStorageVolGetPath(virStorageVolPtr vol)
     virConnectPtr conn;
     DEBUG("vol=%p", vol);
 
+    virResetLastError();
+
     if (!VIR_IS_STORAGE_VOL(vol)) {
         virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
         return (NULL);
@@ -5627,10 +6743,19 @@ virStorageVolGetPath(virStorageVolPtr vol)
 
     conn = vol->conn;
 
-    if (conn->storageDriver && conn->storageDriver->volGetPath)
-        return conn->storageDriver->volGetPath (vol);
+    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 */
+    virSetConnError(vol->conn);
     return NULL;
 }
 
@@ -5655,19 +6780,30 @@ virNodeNumOfDevices(virConnectPtr conn, const char *cap, unsigned int flags)
 {
     DEBUG("conn=%p, cap=%s, flags=%d", conn, cap, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
     }
     if (flags != 0) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->deviceMonitor && conn->deviceMonitor->numOfDevices)
-        return conn->deviceMonitor->numOfDevices (conn, cap, flags);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -5696,19 +6832,30 @@ virNodeListDevices(virConnectPtr conn,
     DEBUG("conn=%p, cap=%s, names=%p, maxnames=%d, flags=%d",
           conn, cap, names, maxnames, flags);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return (-1);
     }
     if ((flags != 0) || (names == NULL) || (maxnames < 0)) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if (conn->deviceMonitor && conn->deviceMonitor->listDevices)
-        return conn->deviceMonitor->listDevices (conn, cap, names, maxnames, flags);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -5726,6 +6873,8 @@ virNodeDevicePtr virNodeDeviceLookupByName(virConnectPtr conn, const char *name)
 {
     DEBUG("conn=%p, name=%p", conn, name);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
         return NULL;
@@ -5733,13 +6882,22 @@ virNodeDevicePtr virNodeDeviceLookupByName(virConnectPtr conn, const char *name)
 
     if (name == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return NULL;
+        goto error;
     }
 
-    if (conn->deviceMonitor && conn->deviceMonitor->deviceLookupByName)
-        return conn->deviceMonitor->deviceLookupByName (conn, name);
+    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 */
+    virSetConnError(conn);
     return NULL;
 }
 
@@ -5758,15 +6916,26 @@ char *virNodeDeviceGetXMLDesc(virNodeDevicePtr dev, unsigned int flags)
 {
     DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(dev->conn);
     return NULL;
 }
 
@@ -5804,6 +6973,8 @@ const char *virNodeDeviceGetParent(virNodeDevicePtr dev)
 {
     DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) {
         virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__);
         return NULL;
@@ -5814,6 +6985,7 @@ const char *virNodeDeviceGetParent(virNodeDevicePtr dev)
             dev->parent = dev->conn->deviceMonitor->deviceGetParent (dev);
         } else {
             virLibConnError (dev->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+            virSetConnError(dev->conn);
             return NULL;
         }
     }
@@ -5832,15 +7004,26 @@ int virNodeDeviceNumOfCaps(virNodeDevicePtr dev)
 {
     DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(dev->conn);
     return -1;
 }
 
@@ -5861,15 +7044,26 @@ int virNodeDeviceListCaps(virNodeDevicePtr dev,
     DEBUG("dev=%p, conn=%p, names=%p, maxnames=%d",
           dev, dev ? dev->conn : NULL, names, maxnames);
 
+    virResetLastError();
+
     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);
+    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 */
+    virSetConnError(dev->conn);
     return -1;
 }
 
@@ -5887,6 +7081,8 @@ int virNodeDeviceFree(virNodeDevicePtr dev)
 {
     DEBUG("dev=%p, conn=%p", dev, dev ? dev->conn : NULL);
 
+    virResetLastError();
+
     if (!VIR_IS_CONNECTED_NODE_DEVICE(dev)) {
         virLibNodeDeviceError(NULL, VIR_ERR_INVALID_NODE_DEVICE, __FUNCTION__);
         return (-1);
@@ -5919,6 +7115,8 @@ virConnectDomainEventRegister(virConnectPtr conn,
                               void *opaque,
                               virFreeCallback freecb)
 {
+    DEBUG("conn=%p, cb=%p, opaque=%p, freecb=%p", conn, cb, opaque, freecb);
+    virResetLastError();
 
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
@@ -5926,11 +7124,21 @@ virConnectDomainEventRegister(virConnectPtr conn,
     }
     if (cb == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        return (-1);
+        goto error;
     }
 
-    if ((conn->driver) && (conn->driver->domainEventRegister))
-        return conn->driver->domainEventRegister (conn, cb, opaque, freecb);
+    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 */
+    virSetConnError(conn);
     return -1;
 }
 
@@ -5949,6 +7157,9 @@ int
 virConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback cb)
 {
+    DEBUG("conn=%p, cb=%p", conn, cb);
+
+    virResetLastError();
 
     if (!VIR_IS_CONNECT(conn)) {
         virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
@@ -5956,11 +7167,20 @@ virConnectDomainEventDeregister(virConnectPtr conn,
     }
     if (cb == NULL) {
         virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
-        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;
     }
-    if ((conn->driver) && (conn->driver->domainEventDeregister))
-        return conn->driver->domainEventDeregister (conn, cb);
 
+    virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+error:
+    /* Copy to connection error object for back compatability */
+    virSetConnError(conn);
     return -1;
 }
 
index 5f9fb4150fef59cc0782d2794f23b3dc91dcc86f..0be442cd06d8a7143180407ae4e4cbaec6c2d792 100644 (file)
 #include "virterror_internal.h"
 #include "datatypes.h"
 #include "logging.h"
+#include "memory.h"
+#include "threads.h"
+
+virThreadLocal virLastErr;
 
-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 };
 virErrorFunc virErrorHandler = NULL;     /* global error handler */
 void *virUserData = NULL;        /* associated data */
 
@@ -154,28 +154,118 @@ static const char *virErrorDomainName(virErrorDomain domain) {
     return(dom);
 }
 
+
+/*
+ * Internal helper that is called when a thread exits, to
+ * release the error object stored in the thread local
+ */
+static void
+virLastErrFreeData(void *data)
+{
+    virErrorPtr err = data;
+    if (!err)
+        return;
+    virResetError(err);
+    VIR_FREE(err);
+}
+
+
+int
+virErrorInitialize(void)
+{
+    return virThreadLocalInit(&virLastErr, virLastErrFreeData);
+}
+
+
+/*
+ * Internal helper to ensure a generic error code is stored
+ * in case where API returns failure, but forgot to set an
+ * error
+ */
+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"));
+}
+
+
 /*
+ * Internal helper to perform a deep copy of the an error
+ */
+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;
+}
+
+static virErrorPtr
+virLastErrorObject(void)
+{
+    virErrorPtr err;
+    err = virThreadLocalGet(&virLastErr);
+    if (!err) {
+        if (VIR_ALLOC(err) < 0)
+            return NULL;
+        virThreadLocalSet(&virLastErr, err);
+    }
+    return err;
+}
+
+
+/**
  * 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()
+ *
+ * The error object is kept in thread local storage, so separate
+ * threads can safely access this concurrently.
  *
  * Returns a pointer to the last error or NULL if none occurred.
  */
 virErrorPtr
 virGetLastError(void)
 {
-    if (virLastErr.code == VIR_ERR_OK)
-        return (NULL);
-    return (&virLastErr);
+    virErrorPtr err = virLastErrorObject();
+    if (!err || err->code == VIR_ERR_OK)
+        return NULL;
+    return err;
 }
 
-/*
+/**
  * virCopyLastError:
  * @to: target to receive the copy
  *
  * Copy the content of the last error caught at the library level
+ *
+ * The error object is kept in thread local storage, so separate
+ * threads can safely access this concurrently.
+ *
  * 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
@@ -184,12 +274,14 @@ virGetLastError(void)
 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);
+    virErrorPtr err = virLastErrorObject();
+    /* We can't guarentee caller has initialized it to zero */
+    memset(to, 0, sizeof(*to));
+    if (err)
+        virCopyError(err, to);
+    else
+        virResetError(to);
+    return to->code;
 }
 
 /**
@@ -210,15 +302,22 @@ virResetError(virErrorPtr err)
     memset(err, 0, sizeof(virError));
 }
 
+
 /**
  * virResetLastError:
  *
  * Reset the last error caught at the library level.
+ *
+ * The error object is kept in thread local storage, so separate
+ * threads can safely access this concurrently, only resetting
+ * their own error object.
  */
 void
 virResetLastError(void)
 {
-    virResetError(&virLastErr);
+    virErrorPtr err = virLastErrorObject();
+    if (err)
+        virResetError(err);
 }
 
 /**
@@ -226,8 +325,20 @@ 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 method is not protected against access from multiple
+ * threads. In a multi-threaded application, always use the
+ * global virGetLastError() API which is backed by thread
+ * local storage.
+ *
+ * If the connection object was discovered to be invalid by
+ * an API call, then the error will be reported against the
+ * global error object.
+ * 
+ * Since 0.6.0, all errors reported in the per-connection object
+ * are also duplicated in the global error object. As such an
+ * application can always use virGetLastError(). This method
+ * remains for backwards compatability.
  *
  * Returns a pointer to the last error or NULL if none occurred.
  */
@@ -235,8 +346,8 @@ virErrorPtr
 virConnGetLastError(virConnectPtr conn)
 {
     if (conn == NULL)
-        return (NULL);
-    return (&conn->err);
+        return NULL;
+    return &conn->err;
 }
 
 /**
@@ -245,6 +356,21 @@ virConnGetLastError(virConnectPtr conn)
  * @to: target to receive the copy
  *
  * Copy the content of the last error caught on that connection
+ *
+ * This method is not protected against access from multiple
+ * threads. In a multi-threaded application, always use the
+ * global virGetLastError() API which is backed by thread
+ * local storage.
+ *
+ * If the connection object was discovered to be invalid by
+ * an API call, then the error will be reported against the
+ * global error object.
+ * 
+ * Since 0.6.0, all errors reported in the per-connection object
+ * are also duplicated in the global error object. As such an
+ * application can always use virGetLastError(). This method
+ * remains for backwards compatability.
+ *
  * 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
@@ -253,20 +379,27 @@ virConnGetLastError(virConnectPtr conn)
 int
 virConnCopyLastError(virConnectPtr conn, virErrorPtr to)
 {
+    /* We can't guarentee caller has initialized it to zero */
+    memset(to, 0, sizeof(*to));
+
     if (conn == NULL)
-        return (-1);
-    if (to == NULL)
-        return (-1);
+        return -1;
+    virMutexLock(&conn->lock);
     if (conn->err.code == VIR_ERR_OK)
-        return (0);
-    memcpy(to, &conn->err, sizeof(virError));
-    return (conn->err.code);
+        virResetError(to);
+    else
+        virCopyError(&conn->err, to);
+    virMutexUnlock(&conn->lock);
+    return to->code;
 }
 
 /**
  * virConnResetLastError:
  * @conn: pointer to the hypervisor connection
  *
+ * The error object is kept in thread local storage, so separate
+ * threads can safely access this concurrently.
+ *
  * Reset the last error caught on that connection
  */
 void
@@ -274,7 +407,9 @@ virConnResetLastError(virConnectPtr conn)
 {
     if (conn == NULL)
         return;
+    virMutexLock(&conn->lock);
     virResetError(&conn->err);
+    virMutexUnlock(&conn->lock);
 }
 
 /**
@@ -309,8 +444,10 @@ virConnSetErrorFunc(virConnectPtr conn, void *userData,
 {
     if (conn == NULL)
         return;
+    virMutexLock(&conn->lock);
     conn->handler = handler;
     conn->userData = userData;
+    virMutexUnlock(&conn->lock);
 }
 
 /**
@@ -357,6 +494,44 @@ virDefaultErrorFunc(virErrorPtr err)
                 dom, lvl, domain, network, err->message);
 }
 
+/*
+ * Internal helper to ensure the global error object
+ * is initialized with a generic message if not already
+ * set.
+ */
+void
+virSetGlobalError(void)
+{
+    virErrorPtr err = virLastErrorObject();
+
+    if (err && err->code == VIR_ERR_OK)
+        virErrorGenericFailure(err);
+}
+
+/*
+ * Internal helper to ensure the connection error object
+ * is initialized from the global object.
+ */
+void
+virSetConnError(virConnectPtr conn)
+{
+    virErrorPtr err = virLastErrorObject();
+
+    if (err && err->code == VIR_ERR_OK)
+        virErrorGenericFailure(err);
+
+    if (conn) {
+        virMutexLock(&conn->lock);
+        if (err)
+            virCopyError(err, &conn->err);
+        else
+            virErrorGenericFailure(&conn->err);
+        virMutexUnlock(&conn->lock);
+    }
+}
+
+
+
 /**
  * virRaiseError:
  * @conn: the connection to the hypervisor if available
@@ -377,16 +552,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 per-connection error object when neccessary
+     */
+    to = virLastErrorObject();
+    if (!to)
+        return; /* Hit OOM allocating thread error object, sod all we can do now */
+
+    virResetError(to);
+
     if (code == VIR_ERR_OK)
         return;
 
@@ -394,11 +582,12 @@ virRaiseError(virConnectPtr conn, virDomainPtr dom, virNetworkPtr net,
      * try to find the best place to save and report the error
      */
     if (conn != NULL) {
-        to = &conn->err;
+        virMutexLock(&conn->lock);
         if (conn->handler != NULL) {
             handler = conn->handler;
             userData = conn->userData;
         }
+        virMutexUnlock(&conn->lock);
     }
 
     /*
@@ -421,9 +610,10 @@ virRaiseError(virConnectPtr conn, virDomainPtr dom, virNetworkPtr net,
      * 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;
@@ -813,3 +1003,5 @@ void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
                   virerr, errorMessage, NULL, -1, -1, virerr, errorMessage);
 
 }
+
+
index a386f5ef67b72651f39b4bd6701261f4d2695ff6..0100c899f365c674bd6dd2ca757a507b68cf971f 100644 (file)
@@ -24,7 +24,6 @@
 
 #include "internal.h"
 
-extern virError virLastErr;
 extern virErrorFunc virErrorHandler;
 extern void *virUserData;
 
@@ -33,6 +32,7 @@ extern void *virUserData;
  *             API for error handling                                  *
  *                                                                     *
  ************************************************************************/
+int virErrorInitialize(void);
 void virRaiseError(virConnectPtr conn,
                    virDomainPtr dom,
                    virNetworkPtr net,
@@ -53,4 +53,7 @@ void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
   ATTRIBUTE_FORMAT(printf, 7, 8);
 
 
+void virSetGlobalError(void);
+void virSetConnError(virConnectPtr conn);
+
 #endif