2006-02-24 22:36:10 +00:00
|
|
|
/*
|
|
|
|
* virterror.c: implements error handling and reporting code for libvirt
|
|
|
|
*
|
|
|
|
* Copy: Copyright (C) 2006 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* See COPYING.LIB for the License of this software
|
|
|
|
*
|
|
|
|
* Author: Daniel Veillard <veillard@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2008-01-29 18:15:54 +00:00
|
|
|
#include <config.h>
|
2007-12-05 21:40:15 +00:00
|
|
|
|
2006-02-24 22:36:10 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2006-02-27 16:27:18 +00:00
|
|
|
#include <stdarg.h>
|
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 08:24:41 +00:00
|
|
|
|
2006-02-24 22:36:10 +00:00
|
|
|
#include "internal.h"
|
Standardize use of header files, making internal.h primary.
* qemud/internal.h, qemud/qemud.h: Rename this file so it
doesn't conflict with src/internal.h.
* HACKING: Document how header files should be used.
* qemud/Makefile.am: Add src/ directory to includes.
* qemud/event.c, qemud/mdns.c, qemud/qemud.c, qemud/remote.c,
qemud/remote_protocol.c, qemud/remote_protocol.h,
qemud/remote_protocol.x, src/buf.c, src/libvirt.c,
src/nodeinfo.c, src/qemu_conf.c, src/qemu_driver.c,
src/stats_linux.c, src/storage_backend.c, src/storage_backend_fs.c,
src/storage_backend_iscsi.c, src/storage_backend_logical.c,
src/storage_conf.c, src/storage_driver.c, src/util.c,
src/util.h, src/virsh.c, src/virterror.c, src/xend_internal.c,
src/xml.c, tests/reconnect.c, tests/xmlrpctest.c,
tests/qparamtest.c: Standardize use of header files.
* docs/*, po/*: Rebuild docs.
2008-05-23 08:24:41 +00:00
|
|
|
#include "libvirt/virterror.h"
|
2006-02-24 22:36:10 +00:00
|
|
|
|
2008-03-31 14:38:12 +00:00
|
|
|
virError __lastErr = /* the last error */
|
2008-04-02 16:22:34 +00:00
|
|
|
{ .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 };
|
2008-02-27 10:37:19 +00:00
|
|
|
static virErrorFunc virErrorHandler = NULL; /* global error handler */
|
2006-03-15 12:13:25 +00:00
|
|
|
static void *virUserData = NULL; /* associated data */
|
2006-02-24 22:36:10 +00:00
|
|
|
|
2006-02-27 16:27:18 +00:00
|
|
|
/*
|
|
|
|
* Macro used to format the message as a string in __virRaiseError
|
|
|
|
* and borrowed from libxml2.
|
|
|
|
*/
|
|
|
|
#define VIR_GET_VAR_STR(msg, str) { \
|
|
|
|
int size, prev_size = -1; \
|
|
|
|
int chars; \
|
|
|
|
char *larger; \
|
|
|
|
va_list ap; \
|
2008-04-10 16:54:54 +00:00
|
|
|
\
|
2006-02-27 16:27:18 +00:00
|
|
|
str = (char *) malloc(150); \
|
|
|
|
if (str != NULL) { \
|
2008-04-10 16:54:54 +00:00
|
|
|
\
|
2006-02-27 16:27:18 +00:00
|
|
|
size = 150; \
|
2008-04-10 16:54:54 +00:00
|
|
|
\
|
2006-02-27 16:27:18 +00:00
|
|
|
while (1) { \
|
2008-04-10 16:54:54 +00:00
|
|
|
va_start(ap, msg); \
|
|
|
|
chars = vsnprintf(str, size, msg, ap); \
|
|
|
|
va_end(ap); \
|
|
|
|
if ((chars > -1) && (chars < size)) { \
|
|
|
|
if (prev_size == chars) { \
|
|
|
|
break; \
|
|
|
|
} else { \
|
|
|
|
prev_size = chars; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
if (chars > -1) \
|
|
|
|
size += chars + 1; \
|
|
|
|
else \
|
|
|
|
size += 100; \
|
|
|
|
if ((larger = (char *) realloc(str, size)) == NULL) { \
|
|
|
|
break; \
|
|
|
|
} \
|
|
|
|
str = larger; \
|
2006-02-27 16:27:18 +00:00
|
|
|
}} \
|
|
|
|
}
|
|
|
|
|
2006-02-24 22:36:10 +00:00
|
|
|
/*
|
|
|
|
* 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()
|
|
|
|
*
|
2008-02-27 10:37:19 +00:00
|
|
|
* Returns a pointer to the last error or NULL if none occurred.
|
2006-02-24 22:36:10 +00:00
|
|
|
*/
|
|
|
|
virErrorPtr
|
2006-03-15 12:13:25 +00:00
|
|
|
virGetLastError(void)
|
|
|
|
{
|
2008-03-31 14:38:12 +00:00
|
|
|
if (__lastErr.code == VIR_ERR_OK)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
2008-03-31 14:38:12 +00:00
|
|
|
return (&__lastErr);
|
2006-02-24 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* virCopyLastError:
|
|
|
|
* @to: target to receive the copy
|
|
|
|
*
|
|
|
|
* Copy the content of the last error caught at the library level
|
|
|
|
* One will need to free the result with virResetError()
|
|
|
|
*
|
|
|
|
* Returns 0 if no error was found and the error code otherwise and -1 in case
|
|
|
|
* of parameter error.
|
|
|
|
*/
|
|
|
|
int
|
2006-03-15 12:13:25 +00:00
|
|
|
virCopyLastError(virErrorPtr to)
|
|
|
|
{
|
2006-02-24 22:36:10 +00:00
|
|
|
if (to == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
2008-03-31 14:38:12 +00:00
|
|
|
if (__lastErr.code == VIR_ERR_OK)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2008-03-31 14:38:12 +00:00
|
|
|
memcpy(to, &__lastErr, sizeof(virError));
|
|
|
|
return (__lastErr.code);
|
2006-02-24 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virResetError:
|
|
|
|
* @err: pointer to the virError to clean up
|
2008-02-05 19:27:37 +00:00
|
|
|
*
|
2006-02-24 22:36:10 +00:00
|
|
|
* Reset the error being pointed to
|
|
|
|
*/
|
|
|
|
void
|
2006-03-15 12:13:25 +00:00
|
|
|
virResetError(virErrorPtr err)
|
|
|
|
{
|
2006-02-24 22:36:10 +00:00
|
|
|
if (err == NULL)
|
|
|
|
return;
|
2008-01-29 17:41:07 +00:00
|
|
|
free(err->message);
|
|
|
|
free(err->str1);
|
|
|
|
free(err->str2);
|
|
|
|
free(err->str3);
|
2006-02-24 22:36:10 +00:00
|
|
|
memset(err, 0, sizeof(virError));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virResetLastError:
|
2008-02-05 19:27:37 +00:00
|
|
|
*
|
2006-02-24 22:36:10 +00:00
|
|
|
* Reset the last error caught at the library level.
|
|
|
|
*/
|
|
|
|
void
|
2006-03-15 12:13:25 +00:00
|
|
|
virResetLastError(void)
|
|
|
|
{
|
2008-03-31 14:38:12 +00:00
|
|
|
virResetError(&__lastErr);
|
2006-02-24 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConnGetLastError:
|
|
|
|
* @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()
|
|
|
|
*
|
2008-02-27 10:37:19 +00:00
|
|
|
* Returns a pointer to the last error or NULL if none occurred.
|
2006-02-24 22:36:10 +00:00
|
|
|
*/
|
|
|
|
virErrorPtr
|
2006-03-15 12:13:25 +00:00
|
|
|
virConnGetLastError(virConnectPtr conn)
|
|
|
|
{
|
2006-02-24 22:36:10 +00:00
|
|
|
if (conn == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
|
|
|
return (&conn->err);
|
2006-02-24 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConnCopyLastError:
|
|
|
|
* @conn: pointer to the hypervisor connection
|
|
|
|
* @to: target to receive the copy
|
|
|
|
*
|
|
|
|
* Copy the content of the last error caught on that connection
|
|
|
|
* One will need to free the result with virResetError()
|
|
|
|
*
|
|
|
|
* Returns 0 if no error was found and the error code otherwise and -1 in case
|
|
|
|
* of parameter error.
|
|
|
|
*/
|
|
|
|
int
|
2006-03-15 12:13:25 +00:00
|
|
|
virConnCopyLastError(virConnectPtr conn, virErrorPtr to)
|
|
|
|
{
|
2006-02-24 22:36:10 +00:00
|
|
|
if (conn == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
2006-02-24 22:36:10 +00:00
|
|
|
if (to == NULL)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (-1);
|
2006-02-24 22:36:10 +00:00
|
|
|
if (conn->err.code == VIR_ERR_OK)
|
2006-03-15 12:13:25 +00:00
|
|
|
return (0);
|
2006-02-24 22:36:10 +00:00
|
|
|
memcpy(to, &conn->err, sizeof(virError));
|
2006-03-15 12:13:25 +00:00
|
|
|
return (conn->err.code);
|
2006-02-24 22:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConnResetLastError:
|
|
|
|
* @conn: pointer to the hypervisor connection
|
|
|
|
*
|
|
|
|
* Reset the last error caught on that connection
|
|
|
|
*/
|
|
|
|
void
|
2006-03-15 12:13:25 +00:00
|
|
|
virConnResetLastError(virConnectPtr conn)
|
|
|
|
{
|
2006-02-24 22:36:10 +00:00
|
|
|
if (conn == NULL)
|
|
|
|
return;
|
|
|
|
virResetError(&conn->err);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virSetErrorFunc:
|
|
|
|
* @userData: pointer to the user data provided in the handler callback
|
|
|
|
* @handler: the function to get called in case of error or NULL
|
|
|
|
*
|
|
|
|
* Set a library global error handling function, if @handler is NULL,
|
|
|
|
* it will reset to default printing on stderr. The error raised there
|
|
|
|
* are those for which no handler at the connection level could caught.
|
|
|
|
*/
|
|
|
|
void
|
2006-03-15 12:13:25 +00:00
|
|
|
virSetErrorFunc(void *userData, virErrorFunc handler)
|
|
|
|
{
|
2006-02-24 22:36:10 +00:00
|
|
|
virErrorHandler = handler;
|
|
|
|
virUserData = userData;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virConnSetErrorFunc:
|
|
|
|
* @conn: pointer to the hypervisor connection
|
|
|
|
* @userData: pointer to the user data provided in the handler callback
|
|
|
|
* @handler: the function to get called in case of error or NULL
|
|
|
|
*
|
|
|
|
* Set a connection error handling function, if @handler is NULL
|
|
|
|
* it will reset to default which is to pass error back to the global
|
|
|
|
* library handler.
|
|
|
|
*/
|
|
|
|
void
|
2006-03-15 12:13:25 +00:00
|
|
|
virConnSetErrorFunc(virConnectPtr conn, void *userData,
|
|
|
|
virErrorFunc handler)
|
|
|
|
{
|
2006-02-24 22:36:10 +00:00
|
|
|
if (conn == NULL)
|
|
|
|
return;
|
|
|
|
conn->handler = handler;
|
|
|
|
conn->userData = userData;
|
|
|
|
}
|
|
|
|
|
2006-02-27 16:27:18 +00:00
|
|
|
/**
|
2006-02-27 21:34:28 +00:00
|
|
|
* virDefaultErrorFunc:
|
2006-02-27 16:27:18 +00:00
|
|
|
* @err: pointer to the error.
|
|
|
|
*
|
2006-02-27 21:34:28 +00:00
|
|
|
* Default routine reporting an error to stderr.
|
2006-02-27 16:27:18 +00:00
|
|
|
*/
|
2006-02-27 21:34:28 +00:00
|
|
|
void
|
2006-03-15 12:13:25 +00:00
|
|
|
virDefaultErrorFunc(virErrorPtr err)
|
|
|
|
{
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
const char *lvl = "", *dom = "", *domain = "", *network = "";
|
2006-02-27 16:27:18 +00:00
|
|
|
int len;
|
|
|
|
|
|
|
|
if ((err == NULL) || (err->code == VIR_ERR_OK))
|
|
|
|
return;
|
|
|
|
switch (err->level) {
|
|
|
|
case VIR_ERR_NONE:
|
2006-03-15 12:13:25 +00:00
|
|
|
lvl = "";
|
|
|
|
break;
|
2006-02-27 16:27:18 +00:00
|
|
|
case VIR_ERR_WARNING:
|
2006-09-21 15:24:37 +00:00
|
|
|
lvl = _("warning");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
2006-02-27 16:27:18 +00:00
|
|
|
case VIR_ERR_ERROR:
|
2006-09-21 15:24:37 +00:00
|
|
|
lvl = _("error");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-02-27 16:27:18 +00:00
|
|
|
switch (err->domain) {
|
|
|
|
case VIR_FROM_NONE:
|
2006-03-15 12:13:25 +00:00
|
|
|
dom = "";
|
|
|
|
break;
|
2006-02-27 16:27:18 +00:00
|
|
|
case VIR_FROM_XEN:
|
2006-03-15 12:13:25 +00:00
|
|
|
dom = "Xen ";
|
|
|
|
break;
|
2006-11-08 16:55:20 +00:00
|
|
|
case VIR_FROM_XML:
|
|
|
|
dom = "XML ";
|
|
|
|
break;
|
2006-02-27 16:27:18 +00:00
|
|
|
case VIR_FROM_XEND:
|
2006-03-15 12:13:25 +00:00
|
|
|
dom = "Xen Daemon ";
|
|
|
|
break;
|
2006-03-23 15:42:10 +00:00
|
|
|
case VIR_FROM_XENSTORE:
|
|
|
|
dom = "Xen Store ";
|
|
|
|
break;
|
2006-02-27 16:27:18 +00:00
|
|
|
case VIR_FROM_DOM:
|
2006-03-15 12:13:25 +00:00
|
|
|
dom = "Domain ";
|
|
|
|
break;
|
2006-05-10 14:48:20 +00:00
|
|
|
case VIR_FROM_RPC:
|
|
|
|
dom = "XML-RPC ";
|
|
|
|
break;
|
2007-02-14 01:40:09 +00:00
|
|
|
case VIR_FROM_QEMU:
|
|
|
|
dom = "QEMU ";
|
|
|
|
break;
|
2007-02-14 15:37:18 +00:00
|
|
|
case VIR_FROM_NET:
|
|
|
|
dom = "Network ";
|
|
|
|
break;
|
2007-04-18 10:14:07 +00:00
|
|
|
case VIR_FROM_TEST:
|
|
|
|
dom = "Test ";
|
|
|
|
break;
|
2007-05-03 14:00:18 +00:00
|
|
|
case VIR_FROM_REMOTE:
|
|
|
|
dom = "Remote ";
|
|
|
|
break;
|
2007-11-20 10:15:38 +00:00
|
|
|
case VIR_FROM_SEXPR:
|
|
|
|
dom = "S-Expr ";
|
|
|
|
break;
|
|
|
|
case VIR_FROM_PROXY:
|
|
|
|
dom = "PROXY ";
|
|
|
|
break;
|
|
|
|
case VIR_FROM_CONF:
|
|
|
|
dom = "Config ";
|
|
|
|
break;
|
|
|
|
case VIR_FROM_OPENVZ:
|
|
|
|
dom = "OpenVZ ";
|
|
|
|
break;
|
|
|
|
case VIR_FROM_XENXM:
|
|
|
|
dom = "Xen XM ";
|
|
|
|
break;
|
2007-11-20 10:58:21 +00:00
|
|
|
case VIR_FROM_STATS_LINUX:
|
2007-11-20 10:15:38 +00:00
|
|
|
dom = "Linux Stats ";
|
|
|
|
break;
|
2008-03-21 15:03:37 +00:00
|
|
|
case VIR_FROM_LXC:
|
|
|
|
dom = "Linux Container ";
|
|
|
|
break;
|
2008-02-20 15:06:53 +00:00
|
|
|
case VIR_FROM_STORAGE:
|
|
|
|
dom = "Storage ";
|
|
|
|
break;
|
2007-11-20 10:15:38 +00:00
|
|
|
|
2006-02-27 16:27:18 +00:00
|
|
|
}
|
|
|
|
if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
|
|
|
|
domain = err->dom->name;
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
} else if ((err->net != NULL) && (err->code != VIR_ERR_INVALID_NETWORK)) {
|
|
|
|
network = err->net->name;
|
2006-02-27 16:27:18 +00:00
|
|
|
}
|
|
|
|
len = strlen(err->message);
|
2006-11-08 16:55:20 +00:00
|
|
|
if ((err->domain == VIR_FROM_XML) && (err->code == VIR_ERR_XML_DETAIL) &&
|
|
|
|
(err->int1 != 0))
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
fprintf(stderr, "libvir: %s%s %s%s: line %d: %s",
|
|
|
|
dom, lvl, domain, network, err->int1, err->message);
|
2006-11-08 16:55:20 +00:00
|
|
|
else if ((len == 0) || (err->message[len - 1] != '\n'))
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
fprintf(stderr, "libvir: %s%s %s%s: %s\n",
|
|
|
|
dom, lvl, domain, network, err->message);
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
fprintf(stderr, "libvir: %s%s %s%s: %s",
|
|
|
|
dom, lvl, domain, network, err->message);
|
2006-02-27 16:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* __virRaiseError:
|
|
|
|
* @conn: the connection to the hypervisor if available
|
|
|
|
* @dom: the domain if available
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
* @net: the network if available
|
2006-02-27 16:27:18 +00:00
|
|
|
* @domain: the virErrorDomain indicating where it's coming from
|
|
|
|
* @code: the virErrorNumber code for the error
|
|
|
|
* @level: the virErrorLevel for the error
|
|
|
|
* @str1: extra string info
|
|
|
|
* @str2: extra string info
|
|
|
|
* @str3: extra string info
|
|
|
|
* @int1: extra int info
|
|
|
|
* @int2: extra int info
|
|
|
|
* @msg: the message to display/transmit
|
|
|
|
* @...: extra parameters for the message display
|
|
|
|
*
|
|
|
|
* Internal routine called when an error is detected. It will raise it
|
|
|
|
* immediately if a callback is found and store it for later handling.
|
|
|
|
*/
|
|
|
|
void
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
__virRaiseError(virConnectPtr conn, virDomainPtr dom, virNetworkPtr net,
|
2006-02-27 16:27:18 +00:00
|
|
|
int domain, int code, virErrorLevel level,
|
|
|
|
const char *str1, const char *str2, const char *str3,
|
2006-03-15 12:13:25 +00:00
|
|
|
int int1, int int2, const char *msg, ...)
|
|
|
|
{
|
2008-03-31 14:38:12 +00:00
|
|
|
virErrorPtr to = &__lastErr;
|
2006-02-27 16:27:18 +00:00
|
|
|
void *userData = virUserData;
|
|
|
|
virErrorFunc handler = virErrorHandler;
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
if (code == VIR_ERR_OK)
|
2006-03-15 12:13:25 +00:00
|
|
|
return;
|
2006-02-27 16:27:18 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* try to find the best place to save and report the error
|
|
|
|
*/
|
|
|
|
if (conn != NULL) {
|
|
|
|
to = &conn->err;
|
2006-03-15 12:13:25 +00:00
|
|
|
if (conn->handler != NULL) {
|
|
|
|
handler = conn->handler;
|
|
|
|
userData = conn->userData;
|
|
|
|
}
|
2006-02-27 16:27:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* formats the message
|
|
|
|
*/
|
|
|
|
if (msg == NULL) {
|
2006-09-21 15:24:37 +00:00
|
|
|
str = strdup(_("No error message provided"));
|
2006-02-27 16:27:18 +00:00
|
|
|
} else {
|
|
|
|
VIR_GET_VAR_STR(msg, str);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save the information about the error
|
|
|
|
*/
|
|
|
|
virResetError(to);
|
|
|
|
to->conn = conn;
|
|
|
|
to->dom = dom;
|
Tue Feb 14 15:37:17 EST 2007 Mark McLoughlin <markmc@redhat.com>
Note: potential ABI break here, but people should
only really be using virError structs returned from
libvirt itself.
* include/libvirt/virterror.h: add virNetwork
to virError
* src/internal.h, src/virterror.c: add network param
to __virRaiseError()
* src/conf.c, src/hash.c, src/libvirt.c, src/proxy_internal.c,
src/qemu_internal.c, src/sexpr.c, src/test.c, src/xen_internal.c,
src/xend_internal.c, src/xm_internal.c, src/xml.c, src/xmlrpc.c,
src/xs_internal.c: update.
2007-02-14 15:40:53 +00:00
|
|
|
to->net = net;
|
2006-02-27 16:27:18 +00:00
|
|
|
to->domain = domain;
|
|
|
|
to->code = code;
|
|
|
|
to->message = str;
|
|
|
|
to->level = level;
|
|
|
|
if (str1 != NULL)
|
|
|
|
to->str1 = strdup(str1);
|
|
|
|
if (str2 != NULL)
|
|
|
|
to->str2 = strdup(str2);
|
|
|
|
if (str3 != NULL)
|
|
|
|
to->str3 = strdup(str3);
|
|
|
|
to->int1 = int1;
|
|
|
|
to->int2 = int2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* now, report it
|
|
|
|
*/
|
|
|
|
if (handler != NULL) {
|
|
|
|
handler(userData, to);
|
|
|
|
} else {
|
2006-02-27 21:34:28 +00:00
|
|
|
virDefaultErrorFunc(to);
|
2006-02-27 16:27:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* __virErrorMsg:
|
|
|
|
* @error: the virErrorNumber
|
2008-02-27 10:37:19 +00:00
|
|
|
* @info: usually the first parameter string
|
2006-02-27 16:27:18 +00:00
|
|
|
*
|
|
|
|
* Internal routine to get the message associated to an error raised
|
|
|
|
* from the library
|
|
|
|
*
|
|
|
|
* Returns the constant string associated to @error
|
|
|
|
*/
|
|
|
|
const char *
|
2006-03-15 12:13:25 +00:00
|
|
|
__virErrorMsg(virErrorNumber error, const char *info)
|
|
|
|
{
|
2006-02-27 16:27:18 +00:00
|
|
|
const char *errmsg = NULL;
|
|
|
|
|
|
|
|
switch (error) {
|
|
|
|
case VIR_ERR_OK:
|
2006-03-15 12:13:25 +00:00
|
|
|
return (NULL);
|
|
|
|
case VIR_ERR_INTERNAL_ERROR:
|
|
|
|
if (info != NULL)
|
2008-04-10 16:54:54 +00:00
|
|
|
errmsg = _("internal error %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2008-04-10 16:54:54 +00:00
|
|
|
errmsg = _("internal error");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_MEMORY:
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("out of memory");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_SUPPORT:
|
2007-06-20 17:25:39 +00:00
|
|
|
if (info == NULL)
|
2008-04-10 16:54:54 +00:00
|
|
|
errmsg = _("this function is not supported by the hypervisor");
|
|
|
|
else
|
|
|
|
errmsg = _("this function is not supported by the hypervisor: %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_CONNECT:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("could not connect to hypervisor");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("could not connect to %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_INVALID_CONN:
|
2006-07-28 15:10:18 +00:00
|
|
|
if (info == NULL)
|
2008-04-10 16:54:54 +00:00
|
|
|
errmsg = _("invalid connection pointer in");
|
|
|
|
else
|
|
|
|
errmsg = _("invalid connection pointer in %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_INVALID_DOMAIN:
|
2006-07-28 15:10:18 +00:00
|
|
|
if (info == NULL)
|
2008-04-10 16:54:54 +00:00
|
|
|
errmsg = _("invalid domain pointer in");
|
|
|
|
else
|
|
|
|
errmsg = _("invalid domain pointer in %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_INVALID_ARG:
|
2006-07-28 15:10:18 +00:00
|
|
|
if (info == NULL)
|
2008-04-10 16:54:54 +00:00
|
|
|
errmsg = _("invalid argument in");
|
|
|
|
else
|
|
|
|
errmsg = _("invalid argument in %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_OPERATION_FAILED:
|
|
|
|
if (info != NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("operation failed: %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("operation failed");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_GET_FAILED:
|
|
|
|
if (info != NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("GET operation failed: %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("GET operation failed");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_POST_FAILED:
|
|
|
|
if (info != NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("POST operation failed: %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("POST operation failed");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_HTTP_ERROR:
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("got unknown HTTP error code %d");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_UNKNOWN_HOST:
|
2006-07-28 15:10:18 +00:00
|
|
|
if (info != NULL)
|
2008-04-10 16:54:54 +00:00
|
|
|
errmsg = _("unknown host %s");
|
|
|
|
else
|
|
|
|
errmsg = _("unknown host");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_SEXPR_SERIAL:
|
|
|
|
if (info != NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("failed to serialize S-Expr: %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("failed to serialize S-Expr");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_XEN:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("could not use Xen hypervisor entry");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("could not use Xen hypervisor entry %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
2008-04-10 16:54:54 +00:00
|
|
|
case VIR_ERR_NO_XENSTORE:
|
2006-03-25 10:38:30 +00:00
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("could not connect to Xen Store");
|
2006-03-25 10:38:30 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("could not connect to Xen Store %s");
|
2006-03-25 10:38:30 +00:00
|
|
|
break;
|
2006-03-15 12:13:25 +00:00
|
|
|
case VIR_ERR_XEN_CALL:
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("failed Xen syscall %s %d");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_OS_TYPE:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("unknown OS type");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("unknown OS type %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_KERNEL:
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing kernel information");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_ROOT:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing root device information");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing root device information in %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_SOURCE:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing source information for device");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing source information for device %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_TARGET:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing target information for device");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing target information for device %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_NAME:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing domain name information");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing domain name information in %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_OS:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing operating system information");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing operating system information for %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_DEVICE:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing devices information");
|
2006-03-15 12:13:25 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("missing devices information for %s");
|
2006-03-15 12:13:25 +00:00
|
|
|
break;
|
2006-03-27 15:24:36 +00:00
|
|
|
case VIR_ERR_DRIVER_FULL:
|
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("too many drivers registered");
|
2006-03-27 15:24:36 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("too many drivers registered in %s");
|
2006-03-27 15:24:36 +00:00
|
|
|
break;
|
2007-06-20 17:25:39 +00:00
|
|
|
case VIR_ERR_CALL_FAILED: /* DEPRECATED, use VIR_ERR_NO_SUPPORT */
|
2006-03-29 12:46:03 +00:00
|
|
|
if (info == NULL)
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("library call failed, possibly not supported");
|
2006-03-29 12:46:03 +00:00
|
|
|
else
|
2006-09-21 15:24:37 +00:00
|
|
|
errmsg = _("library call %s failed, possibly not supported");
|
2006-03-29 12:46:03 +00:00
|
|
|
break;
|
2008-04-10 16:54:54 +00:00
|
|
|
case VIR_ERR_XML_ERROR:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("XML description not well formed or invalid");
|
|
|
|
else
|
|
|
|
errmsg = _("XML description for %s is not well formed or invalid");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_DOM_EXIST:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("this domain exists already");
|
|
|
|
else
|
|
|
|
errmsg = _("domain %s exists already");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_OPERATION_DENIED:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("operation forbidden for read only access");
|
|
|
|
else
|
|
|
|
errmsg = _("operation %s forbidden for read only access");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_OPEN_FAILED:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("failed to open configuration file for reading");
|
|
|
|
else
|
|
|
|
errmsg = _("failed to open %s for reading");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_READ_FAILED:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("failed to read configuration file");
|
|
|
|
else
|
|
|
|
errmsg = _("failed to read configuration file %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_PARSE_FAILED:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("failed to parse configuration file");
|
|
|
|
else
|
|
|
|
errmsg = _("failed to parse configuration file %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_CONF_SYNTAX:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("configuration file syntax error");
|
|
|
|
else
|
|
|
|
errmsg = _("configuration file syntax error: %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_WRITE_FAILED:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("failed to write configuration file");
|
|
|
|
else
|
|
|
|
errmsg = _("failed to write configuration file: %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_XML_DETAIL:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("parser error");
|
|
|
|
else
|
|
|
|
errmsg = "%s";
|
2006-11-08 16:55:20 +00:00
|
|
|
break;
|
2007-02-14 15:37:18 +00:00
|
|
|
case VIR_ERR_INVALID_NETWORK:
|
|
|
|
if (info == NULL)
|
2008-04-10 16:54:54 +00:00
|
|
|
errmsg = _("invalid network pointer in");
|
|
|
|
else
|
|
|
|
errmsg = _("invalid network pointer in %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_NETWORK_EXIST:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("this network exists already");
|
|
|
|
else
|
|
|
|
errmsg = _("network %s exists already");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_SYSTEM_ERROR:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("system call error");
|
|
|
|
else
|
|
|
|
errmsg = "%s";
|
|
|
|
break;
|
|
|
|
case VIR_ERR_RPC:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("RPC error");
|
|
|
|
else
|
|
|
|
errmsg = "%s";
|
|
|
|
break;
|
|
|
|
case VIR_ERR_GNUTLS_ERROR:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("GNUTLS call error");
|
|
|
|
else
|
|
|
|
errmsg = "%s";
|
|
|
|
break;
|
|
|
|
case VIR_WAR_NO_NETWORK:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("Failed to find the network");
|
|
|
|
else
|
|
|
|
errmsg = _("Failed to find the network: %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_DOMAIN:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("Domain not found");
|
|
|
|
else
|
|
|
|
errmsg = _("Domain not found: %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_NETWORK:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("Network not found");
|
|
|
|
else
|
|
|
|
errmsg = _("Network not found: %s");
|
|
|
|
break;
|
2007-07-13 08:26:57 +00:00
|
|
|
case VIR_ERR_INVALID_MAC:
|
2008-04-10 16:54:54 +00:00
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("invalid MAC address");
|
|
|
|
else
|
|
|
|
errmsg = _("invalid MAC address: %s");
|
|
|
|
break;
|
2007-12-05 15:24:15 +00:00
|
|
|
case VIR_ERR_AUTH_FAILED:
|
2008-04-10 16:54:54 +00:00
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("authentication failed");
|
|
|
|
else
|
|
|
|
errmsg = _("authentication failed: %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_STORAGE_POOL:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("Storage pool not found");
|
|
|
|
else
|
|
|
|
errmsg = _("Storage pool not found: %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_NO_STORAGE_VOL:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("Storage volume not found");
|
|
|
|
else
|
|
|
|
errmsg = _("Storage volume not found: %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_INVALID_STORAGE_POOL:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("invalid storage pool pointer in");
|
|
|
|
else
|
|
|
|
errmsg = _("invalid storage pool pointer in %s");
|
|
|
|
break;
|
|
|
|
case VIR_ERR_INVALID_STORAGE_VOL:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("invalid storage volume pointer in");
|
|
|
|
else
|
|
|
|
errmsg = _("invalid storage volume pointer in %s");
|
|
|
|
break;
|
|
|
|
case VIR_WAR_NO_STORAGE:
|
|
|
|
if (info == NULL)
|
|
|
|
errmsg = _("Failed to find a storage driver");
|
|
|
|
else
|
|
|
|
errmsg = _("Failed to find a storage driver: %s");
|
|
|
|
break;
|
2006-02-27 16:27:18 +00:00
|
|
|
}
|
2006-03-15 12:13:25 +00:00
|
|
|
return (errmsg);
|
2006-02-27 16:27:18 +00:00
|
|
|
}
|