e942243
diff -rup libvirt-0.7.1/src/libvirt.c new/src/libvirt.c
e942243
--- libvirt-0.7.1/src/libvirt.c	2010-06-03 15:30:32.615164000 -0400
e942243
+++ new/src/libvirt.c	2010-06-03 15:33:22.863409000 -0400
e942243
@@ -3054,6 +3054,7 @@ virDomainMigrateVersion2 (virDomainPtr d
e942243
     char *cookie = NULL;
e942243
     char *dom_xml = NULL;
e942243
     int cookielen = 0, ret;
e942243
+    virErrorPtr orig_err = NULL;
e942243
 
e942243
     /* Prepare the migration.
e942243
      *
e942243
@@ -3102,6 +3103,10 @@ virDomainMigrateVersion2 (virDomainPtr d
e942243
     ret = domain->conn->driver->domainMigratePerform
e942243
         (domain, cookie, cookielen, uri, flags, dname, bandwidth);
e942243
 
e942243
+    /* Perform failed. Make sure Finish doesn't overwrite the error */
e942243
+    if (ret < 0)
e942243
+        orig_err = virSaveLastError();
e942243
+
e942243
     /* In version 2 of the migration protocol, we pass the
e942243
      * status code from the sender to the destination host,
e942243
      * so it can do any cleanup if the migration failed.
e942243
@@ -3111,6 +3116,10 @@ virDomainMigrateVersion2 (virDomainPtr d
e942243
         (dconn, dname, cookie, cookielen, uri, flags, ret);
e942243
 
e942243
  done:
e942243
+    if (orig_err) {
e942243
+        virSetError(orig_err);
e942243
+        virFreeError(orig_err);
e942243
+    }
e942243
     VIR_FREE (uri_out);
e942243
     VIR_FREE (cookie);
e942243
     return ddomain;
e942243
@@ -3222,7 +3231,7 @@ virDomainMigrate (virDomainPtr domain,
e942243
 
e942243
 error:
e942243
     /* Copy to connection error object for back compatability */
e942243
-    virSetConnError(domain->conn);
e942243
+    virDispatchError(domain->conn);
e942243
     return NULL;
e942243
 }
e942243
 
e942243
@@ -3269,8 +3278,7 @@ virDomainMigratePrepare (virConnectPtr d
e942243
     virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
e942243
 
e942243
 error:
e942243
-    /* Copy to connection error object for back compatability */
e942243
-    virSetConnError(dconn);
e942243
+    virDispatchError(dconn);
e942243
     return -1;
e942243
 }
e942243
 
e942243
@@ -3318,8 +3326,7 @@ virDomainMigratePerform (virDomainPtr do
e942243
     virLibDomainError (domain, VIR_ERR_NO_SUPPORT, __FUNCTION__);
e942243
 
e942243
 error:
e942243
-    /* Copy to connection error object for back compatability */
e942243
-    virSetConnError(domain->conn);
e942243
+    virDispatchError(domain->conn);
e942243
     return -1;
e942243
 }
e942243
 
e942243
@@ -3364,8 +3371,7 @@ virDomainMigrateFinish (virConnectPtr dc
e942243
     virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
e942243
 
e942243
 error:
e942243
-    /* Copy to connection error object for back compatability */
e942243
-    virSetConnError(dconn);
e942243
+    virDispatchError(dconn);
e942243
     return NULL;
e942243
 }
e942243
 
e942243
@@ -3416,8 +3422,7 @@ virDomainMigratePrepare2 (virConnectPtr 
e942243
     virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
e942243
 
e942243
 error:
e942243
-    /* Copy to connection error object for back compatability */
e942243
-    virSetConnError(dconn);
e942243
+    virDispatchError(dconn);
e942243
     return -1;
e942243
 }
e942243
 
e942243
@@ -3464,8 +3469,7 @@ virDomainMigrateFinish2 (virConnectPtr d
e942243
     virLibConnError (dconn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
e942243
 
e942243
 error:
e942243
-    /* Copy to connection error object for back compatability */
e942243
-    virSetConnError(dconn);
e942243
+    virDispatchError(dconn);
e942243
     return NULL;
e942243
 }
e942243
 
e942243
diff -rup libvirt-0.7.1/src/libvirt_private.syms new/src/libvirt_private.syms
e942243
--- libvirt-0.7.1/src/libvirt_private.syms	2010-06-03 15:30:33.051186000 -0400
e942243
+++ new/src/libvirt_private.syms	2010-06-03 15:33:22.869400000 -0400
e942243
@@ -461,6 +461,7 @@ virRaiseErrorFull;
e942243
 virReportSystemErrorFull;
e942243
 virReportOOMErrorFull;
e942243
 virStrerror;
e942243
+virSetError;
e942243
 
e942243
 
e942243
 # xml.h
e942243
diff -rup libvirt-0.7.1/src/qemu_driver.c new/src/qemu_driver.c
e942243
--- libvirt-0.7.1/src/qemu_driver.c	2010-06-03 15:30:33.111159000 -0400
e942243
+++ new/src/qemu_driver.c	2010-06-03 15:35:22.809404000 -0400
e942243
@@ -2297,12 +2297,17 @@ static void qemudShutdownVMDaemon(virCon
e942243
                                   virDomainObjPtr vm) {
e942243
     int ret;
e942243
     int retries = 0;
e942243
+    virErrorPtr orig_err;
e942243
 
e942243
     if (!virDomainIsActive(vm))
e942243
         return;
e942243
 
e942243
     VIR_DEBUG(_("Shutting down VM '%s'\n"), vm->def->name);
e942243
 
e942243
+    /* This method is routinely used in clean up paths. Disable error
e942243
+     * reporting so we don't squash a legit error. */
e942243
+    orig_err = virSaveLastError();
e942243
+
e942243
     if (virKillProcess(vm->pid, 0) == 0 &&
e942243
         virKillProcess(vm->pid, SIGTERM) < 0)
e942243
         virReportSystemError(conn, errno,
e942243
@@ -2377,6 +2382,11 @@ retry:
e942243
         vm->def->id = -1;
e942243
         vm->newDef = NULL;
e942243
     }
e942243
+
e942243
+    if (orig_err) {
e942243
+        virSetError(orig_err);
e942243
+        virFreeError(orig_err);
e942243
+    }
e942243
 }
e942243
 
e942243
 
e942243
@@ -7497,6 +7507,10 @@ qemudDomainMigrateFinish2 (virConnectPtr
e942243
     virDomainObjPtr vm;
e942243
     virDomainPtr dom = NULL;
e942243
     virDomainEventPtr event = NULL;
e942243
+    virErrorPtr orig_err;
e942243
+
e942243
+    /* Migration failed. Save the current error so nothing squashes it */
e942243
+    orig_err = virSaveLastError();
e942243
 
e942243
     qemuDriverLock(driver);
e942243
     vm = virDomainFindByName(&driver->domains, dname);
e942243
@@ -7540,6 +7554,10 @@ qemudDomainMigrateFinish2 (virConnectPtr
e942243
     }
e942243
 
e942243
 cleanup:
e942243
+    if (orig_err) {
e942243
+        virSetError(orig_err);
e942243
+        virFreeError(orig_err);
e942243
+    }
e942243
     if (vm)
e942243
         virDomainObjUnlock(vm);
e942243
     if (event)
e942243
diff -rup libvirt-0.7.1/src/util.c new/src/util.c
e942243
--- libvirt-0.7.1/src/util.c	2010-06-03 15:30:33.064159000 -0400
e942243
+++ new/src/util.c	2010-06-03 15:33:22.881417000 -0400
e942243
@@ -1764,31 +1764,82 @@ int virDiskNameToIndex(const char *name)
e942243
 #define AI_CANONIDN 0
e942243
 #endif
e942243
 
e942243
-char *virGetHostname(void)
e942243
+/* Who knew getting a hostname could be so delicate.  In Linux (and Unices
e942243
+ * in general), many things depend on "hostname" returning a value that will
e942243
+ * resolve one way or another.  In the modern world where networks frequently
e942243
+ * come and go this is often being hard-coded to resolve to "localhost".  If
e942243
+ * it *doesn't* resolve to localhost, then we would prefer to have the FQDN.
e942243
+ * That leads us to 3 possibilities:
e942243
+ *
e942243
+ * 1)  gethostname() returns an FQDN (not localhost) - we return the string
e942243
+ *     as-is, it's all of the information we want
e942243
+ * 2)  gethostname() returns "localhost" - we return localhost; doing further
e942243
+ *     work to try to resolve it is pointless
e942243
+ * 3)  gethostname() returns a shortened hostname - in this case, we want to
e942243
+ *     try to resolve this to a fully-qualified name.  Therefore we pass it
e942243
+ *     to getaddrinfo().  There are two possible responses:
e942243
+ *     a)  getaddrinfo() resolves to a FQDN - return the FQDN
e942243
+ *     b)  getaddrinfo() resolves to localhost - in this case, the data we got
e942243
+ *         from gethostname() is actually more useful than what we got from
e942243
+ *         getaddrinfo().  Return the value from gethostname() and hope for
e942243
+ *         the best.
e942243
+ */
e942243
+char *virGetHostname()
e942243
 {
e942243
     int r;
e942243
     char hostname[HOST_NAME_MAX+1], *result;
e942243
     struct addrinfo hints, *info;
e942243
 
e942243
     r = gethostname (hostname, sizeof(hostname));
e942243
-    if (r == -1)
e942243
+    if (r == -1) {
e942243
+        virReportSystemError(NULL, errno,
e942243
+                             "%s", _("failed to determine host name"));
e942243
         return NULL;
e942243
+    }
e942243
     NUL_TERMINATE(hostname);
e942243
 
e942243
+    if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) {
e942243
+        /* in this case, gethostname returned localhost (meaning we can't
e942243
+         * do any further canonicalization), or it returned an FQDN (and
e942243
+         * we don't need to do any further canonicalization).  Return the
e942243
+         * string as-is; it's up to callers to check whether "localhost"
e942243
+         * is allowed.
e942243
+         */
e942243
+        result = strdup(hostname);
e942243
+        goto check_and_return;
e942243
+    }
e942243
+
e942243
+    /* otherwise, it's a shortened, non-localhost, hostname.  Attempt to
e942243
+     * canonicalize the hostname by running it through getaddrinfo
e942243
+     */
e942243
+
e942243
     memset(&hints, 0, sizeof(hints));
e942243
     hints.ai_flags = AI_CANONNAME|AI_CANONIDN;
e942243
     hints.ai_family = AF_UNSPEC;
e942243
     r = getaddrinfo(hostname, NULL, &hints, &info;;
e942243
-    if (r != 0)
e942243
-        return NULL;
e942243
-    if (info->ai_canonname == NULL) {
e942243
-        freeaddrinfo(info);
e942243
+    if (r != 0) {
e942243
+        ReportError(NULL, VIR_ERR_INTERNAL_ERROR,
e942243
+                    _("getaddrinfo failed for '%s': %s"),
e942243
+                    hostname, gai_strerror(r));
e942243
         return NULL;
e942243
     }
e942243
 
e942243
-    /* Caller frees this string. */
e942243
-    result = strdup (info->ai_canonname);
e942243
+    if (info->ai_canonname == NULL ||
e942243
+        STRPREFIX(info->ai_canonname, "localhost"))
e942243
+        /* in this case, we tried to canonicalize and we ended up back with
e942243
+         * localhost.  Ignore the canonicalized name and just return the
e942243
+         * original hostname
e942243
+         */
e942243
+        result = strdup(hostname);
e942243
+    else
e942243
+        /* Caller frees this string. */
e942243
+        result = strdup (info->ai_canonname);
e942243
+
e942243
     freeaddrinfo(info);
e942243
+
e942243
+check_and_return:
e942243
+    if (result == NULL)
e942243
+        virReportOOMError(NULL);
e942243
     return result;
e942243
 }
e942243
 
e942243
diff -rup libvirt-0.7.1/src/virterror.c new/src/virterror.c
e942243
--- libvirt-0.7.1/src/virterror.c	2009-09-14 06:12:53.000000000 -0400
e942243
+++ new/src/virterror.c	2010-06-03 15:33:22.886409000 -0400
e942243
@@ -287,6 +287,28 @@ virGetLastError(void)
e942243
 }
e942243
 
e942243
 /**
e942243
+ * virSetError:
e942243
+ *
e942243
+ * Set the current error from a previously saved error object
e942243
+ *
e942243
+ * Can be used to re-set an old error, which may have been squashed by
e942243
+ * other functions (like cleanup routines).
e942243
+ *
e942243
+ * Returns 0 on success, 1 on failure
e942243
+ */
e942243
+int
e942243
+virSetError(virErrorPtr newerr)
e942243
+{
e942243
+    virErrorPtr err;
e942243
+    err = virGetLastError();
e942243
+    if (!err)
e942243
+        return -1;
e942243
+
e942243
+    virResetError(err);
e942243
+    return virCopyError(newerr, err);
e942243
+}
e942243
+
e942243
+/**
e942243
  * virCopyLastError:
e942243
  * @to: target to receive the copy
e942243
  *
e942243
@@ -596,6 +618,52 @@ virSetConnError(virConnectPtr conn)
e942243
     }
e942243
 }
e942243
 
e942243
+/**
e942243
+ * virDispatchError:
e942243
+ * @conn: pointer to the hypervisor connection
e942243
+ *
e942243
+ * Internal helper to do final stage of error
e942243
+ * reporting in public APIs.
e942243
+ *
e942243
+ *  - Copy the global error to per-connection error if needed
e942243
+ *  - Set a generic error message if none is already set
e942243
+ *  - Invoke the error callback functions
e942243
+ */
e942243
+void
e942243
+virDispatchError(virConnectPtr conn)
e942243
+{
e942243
+    virErrorPtr err = virLastErrorObject();
e942243
+    virErrorFunc handler = virErrorHandler;
e942243
+    void *userData = virUserData;
e942243
+
e942243
+    /* Should never happen, but doesn't hurt to check */
e942243
+    if (!err)
e942243
+        return;
e942243
+
e942243
+    /* Set a generic error message if none is already set */
e942243
+    if (err->code == VIR_ERR_OK)
e942243
+        virErrorGenericFailure(err);
e942243
+
e942243
+    /* Copy the global error to per-connection error if needed */
e942243
+    if (conn) {
e942243
+        virMutexLock(&conn->lock);
e942243
+        virCopyError(err, &conn->err);
e942243
+
e942243
+        if (conn->handler != NULL) {
e942243
+            handler = conn->handler;
e942243
+            userData = conn->userData;
e942243
+        }
e942243
+        virMutexUnlock(&conn->lock);
e942243
+    }
e942243
+
e942243
+    /* Invoke the error callback functions */
e942243
+    if (handler != NULL) {
e942243
+        (handler)(userData, err);
e942243
+    } else {
e942243
+        virDefaultErrorFunc(err);
e942243
+    }
e942243
+}
e942243
+
e942243
 
e942243
 
e942243
 /**
e942243
@@ -634,8 +702,6 @@ virRaiseErrorFull(virConnectPtr conn,
e942243
                   const char *fmt, ...)
e942243
 {
e942243
     virErrorPtr to;
e942243
-    void *userData = virUserData;
e942243
-    virErrorFunc handler = virErrorHandler;
e942243
     char *str;
e942243
 
e942243
     /*
e942243
@@ -653,18 +719,6 @@ virRaiseErrorFull(virConnectPtr conn,
e942243
         return;
e942243
 
e942243
     /*
e942243
-     * try to find the best place to save and report the error
e942243
-     */
e942243
-    if (conn != NULL) {
e942243
-        virMutexLock(&conn->lock);
e942243
-        if (conn->handler != NULL) {
e942243
-            handler = conn->handler;
e942243
-            userData = conn->userData;
e942243
-        }
e942243
-        virMutexUnlock(&conn->lock);
e942243
-    }
e942243
-
e942243
-    /*
e942243
      * formats the message
e942243
      */
e942243
     if (fmt == NULL) {
e942243
@@ -683,7 +737,6 @@ virRaiseErrorFull(virConnectPtr conn,
e942243
     /*
e942243
      * Save the information about the error
e942243
      */
e942243
-    virResetError(to);
e942243
     /*
e942243
      * Delibrately not setting conn, dom & net fields since
e942243
      * they're utterly unsafe
e942243
@@ -701,14 +754,7 @@ virRaiseErrorFull(virConnectPtr conn,
e942243
     to->int1 = int1;
e942243
     to->int2 = int2;
e942243
 
e942243
-    /*
e942243
-     * now, report it
e942243
-     */
e942243
-    if (handler != NULL) {
e942243
-        handler(userData, to);
e942243
-    } else {
e942243
-        virDefaultErrorFunc(to);
e942243
-    }
e942243
+    virDispatchError(conn);
e942243
 }
e942243
 
e942243
 /**
e942243
diff -rup libvirt-0.7.1/src/virterror_internal.h new/src/virterror_internal.h
e942243
--- libvirt-0.7.1/src/virterror_internal.h	2009-07-23 12:33:02.000000000 -0400
e942243
+++ new/src/virterror_internal.h	2010-06-03 15:33:22.890402000 -0400
e942243
@@ -89,6 +89,8 @@ void virReportOOMErrorFull(virConnectPtr
e942243
 
e942243
 void virSetGlobalError(void);
e942243
 void virSetConnError(virConnectPtr conn);
e942243
+int virSetError(virErrorPtr newerr);
e942243
+void virDispatchError(virConnectPtr conn);
e942243
 const char *virStrerror(int theerrno, char *errBuf, size_t errBufLen);
e942243
 
e942243
 #endif