|
|
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
|