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