From 596b601021ec190f3eb7d4ed25f2a170e03badb8 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Mon, 27 Feb 2006 16:27:18 +0000 Subject: [PATCH] * TODO: updated * include/virterror.h src/internal.h src/libvirt.c src/virterror.c src/xend_internal.c: commiting a first pass at adding error handling in the code, not finished, but it starts to work, need more coverage and testing. Daniel --- ChangeLog | 8 ++ TODO | 1 + include/libvirt/virterror.h | 12 +- include/virterror.h | 12 +- src/internal.h | 15 +++ src/libvirt.c | 224 +++++++++++++++++++++++++++++------- src/virterror.c | 216 ++++++++++++++++++++++++++++++++++ src/xend_internal.c | 45 +++++++- 8 files changed, 485 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index cddb4a66f1..19d36a2130 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Mon Feb 27 17:25:48 CET 2006 Daniel Veillard + + * TODO: updated + * include/virterror.h src/internal.h src/libvirt.c src/virterror.c + src/xend_internal.c: commiting a first pass at adding error handling + in the code, not finished, but it starts to work, need more coverage + and testing. + Fri Feb 24 23:33:55 CET 2006 Daniel Veillard * src/Makefile.am src/internal.h src/libvirt.c src/libvirt_sym.version diff --git a/TODO b/TODO index b5548c2947..82e47dc4fc 100644 --- a/TODO +++ b/TODO @@ -12,6 +12,7 @@ TODO: - DTD/RNG/XSD schemas for the XML Domain descriptions - in python bindings raise an exception if a lookup or connection fails to return a non-None object +- Add uuid to XML format virsh TODO: - decide where will be default directory for domains configurations (/etc/xen/domains/* ?) diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index bd5e2acd02..d9d3972f59 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -53,7 +53,7 @@ typedef enum { typedef struct _virError virError; typedef virError *virErrorPtr; struct _virError { - int code; /* The error code, e.g. an virParserError */ + int code; /* The error code, a virErrorNumber */ int domain; /* What part of the library raised this error */ char *message;/* human-readable informative error message */ virErrorLevel level;/* how consequent is the error */ @@ -73,8 +73,14 @@ struct _virError { */ typedef enum { VIR_ERR_OK = 0, - VIR_ERR_INTERNAL_ERROR, /* 1 */ - VIR_ERR_NO_MEMORY /* 2 */ + VIR_ERR_INTERNAL_ERROR, /* internal error */ + VIR_ERR_NO_MEMORY, /* memory allocation failure */ + VIR_ERR_NO_SUPPORT, /* no support for this connection */ + VIR_ERR_NO_CONNECT, /* can't connect to hypervisor */ + VIR_ERR_INVALID_CONN,/* invalid connection object */ + VIR_ERR_INVALID_DOMAIN,/* invalid domain object */ + VIR_ERR_INVALID_ARG,/* invalid function argument */ + VIR_ERR_OPERATION_FAILED,/* a command to hypervisor failed */ } virErrorNumber; /** diff --git a/include/virterror.h b/include/virterror.h index bd5e2acd02..d9d3972f59 100644 --- a/include/virterror.h +++ b/include/virterror.h @@ -53,7 +53,7 @@ typedef enum { typedef struct _virError virError; typedef virError *virErrorPtr; struct _virError { - int code; /* The error code, e.g. an virParserError */ + int code; /* The error code, a virErrorNumber */ int domain; /* What part of the library raised this error */ char *message;/* human-readable informative error message */ virErrorLevel level;/* how consequent is the error */ @@ -73,8 +73,14 @@ struct _virError { */ typedef enum { VIR_ERR_OK = 0, - VIR_ERR_INTERNAL_ERROR, /* 1 */ - VIR_ERR_NO_MEMORY /* 2 */ + VIR_ERR_INTERNAL_ERROR, /* internal error */ + VIR_ERR_NO_MEMORY, /* memory allocation failure */ + VIR_ERR_NO_SUPPORT, /* no support for this connection */ + VIR_ERR_NO_CONNECT, /* can't connect to hypervisor */ + VIR_ERR_INVALID_CONN,/* invalid connection object */ + VIR_ERR_INVALID_DOMAIN,/* invalid domain object */ + VIR_ERR_INVALID_ARG,/* invalid function argument */ + VIR_ERR_OPERATION_FAILED,/* a command to hypervisor failed */ } virErrorNumber; /** diff --git a/src/internal.h b/src/internal.h index d9c89c469e..1df8c388bf 100644 --- a/src/internal.h +++ b/src/internal.h @@ -129,6 +129,21 @@ char * virDomainGetVMInfo (virDomainPtr domain, const char *vm, const char *name); +void __virRaiseError (virConnectPtr conn, + virDomainPtr dom, + int domain, + int code, + virErrorLevel level, + const char *str1, + const char *str2, + const char *str3, + int int1, + int int2, + const char *msg, + ...); +const char * __virErrorMsg (virErrorNumber error, + const char *info); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/libvirt.c b/src/libvirt.c index 7b8325a49f..102d18d8a7 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -33,6 +33,50 @@ * - memory wrappers for malloc/free ? */ +/** + * virLibConnError: + * @conn: the connection if available + * @error: the error noumber + * @info: extra information string + * + * Handle an error at the connection level + */ +static void +virLibConnError(virConnectPtr conn, virErrorNumber error, const char *info) { + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + __virRaiseError(conn, NULL, VIR_FROM_NONE, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +/** + * virLibConnError: + * @conn: the connection if available + * @error: the error noumber + * @info: extra information string + * + * Handle an error at the connection level + */ +static void +virLibDomainError(virDomainPtr domain, virErrorNumber error, const char *info) { + virConnectPtr conn = NULL; + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + if (error != VIR_ERR_INVALID_DOMAIN) { + conn = domain->conn; + } + __virRaiseError(conn, domain, VIR_FROM_DOM, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + /** * virGetVersion: * @libVer: return value for the library version (OUT) @@ -68,6 +112,7 @@ virGetVersion(unsigned long *libVer, const char *type, unsigned long *typeVer) { } } else { *typeVer = 0; + virLibConnError(NULL, VIR_ERR_NO_SUPPORT, "type"); return(-1); } } @@ -90,19 +135,26 @@ virConnectOpen(const char *name) { struct xs_handle *xshandle = NULL; /* we can only talk to the local Xen supervisor ATM */ - if (name != NULL) + if (name != NULL) { + virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name); return(NULL); + } handle = xenHypervisorOpen(); - if (handle == -1) + if (handle == -1) { goto failed; + } xshandle = xs_daemon_open(); - if (xshandle == NULL) + if (xshandle == NULL) { + virLibConnError(NULL, VIR_ERR_NO_CONNECT, "XenStore"); goto failed; + } ret = (virConnectPtr) malloc(sizeof(virConnect)); - if (ret == NULL) + if (ret == NULL) { + virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection"); goto failed; + } memset(ret, 0, sizeof(virConnect)); ret->magic = VIR_CONNECT_MAGIC; ret->handle = handle; @@ -143,8 +195,10 @@ virConnectOpenReadOnly(const char *name) { struct xs_handle *xshandle = NULL; /* we can only talk to the local Xen supervisor ATM */ - if (name != NULL) + if (name != NULL) { + virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name); return(NULL); + } handle = xenHypervisorOpen(); if (handle >= 0) @@ -157,8 +211,10 @@ virConnectOpenReadOnly(const char *name) { method++; ret = (virConnectPtr) malloc(sizeof(virConnect)); - if (ret == NULL) + if (ret == NULL) { + virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection"); goto failed; + } memset(ret, 0, sizeof(virConnect)); ret->magic = VIR_CONNECT_MAGIC; ret->handle = handle; @@ -166,9 +222,14 @@ virConnectOpenReadOnly(const char *name) { if (xend_setup(ret) == 0) method++; ret->domains = virHashCreate(20); + if (ret->domains == NULL) + goto failed; ret->flags = VIR_CONNECT_RO; - if ((ret->domains == NULL) || (method == 0)) + if (method == 0) { + virLibConnError(NULL, VIR_ERR_NO_CONNECT, + "could not connect to Xen Daemon nor Xen Store"); goto failed; + } return(ret); failed: @@ -259,8 +320,10 @@ virConnectClose(virConnectPtr conn) { */ const char * virConnectGetType(virConnectPtr conn) { - if (!VIR_IS_CONNECT(conn)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, "in virConnectGetType"); return(NULL); + } return("Xen"); } @@ -281,11 +344,15 @@ int virConnectGetVersion(virConnectPtr conn, unsigned long *hvVer) { unsigned long ver; - if (!VIR_IS_CONNECT(conn)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); return(-1); + } - if (hvVer == NULL) + if (hvVer == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); + } /* this can't be extracted from the Xenstore */ if (conn->handle < 0) { @@ -315,11 +382,15 @@ virConnectListDomains(virConnectPtr conn, int *ids, int maxids) { long id; char **idlist = NULL, *endptr; - if (!VIR_IS_CONNECT(conn)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); return(-1); + } - if ((ids == NULL) || (maxids <= 0)) + if ((ids == NULL) || (maxids <= 0)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); + } idlist = xend_get_domains(conn); if (idlist != NULL) { @@ -368,8 +439,10 @@ virConnectNumOfDomains(virConnectPtr conn) { unsigned int num; char **idlist = NULL; - if (!VIR_IS_CONNECT(conn)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); return(-1); + } /* * try first with Xend interface @@ -415,10 +488,15 @@ virDomainCreateLinux(virConnectPtr conn, char *name = NULL; virDomainPtr dom; - if (!VIR_IS_CONNECT(conn)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); return(NULL); - if (xmlDesc == NULL) + } + if (xmlDesc == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(NULL); + } + sexpr = virDomainParseXMLDesc(xmlDesc, &name); if ((sexpr == NULL) || (name == NULL)) { if (sexpr != NULL) @@ -614,10 +692,14 @@ virDomainLookupByID(virConnectPtr conn, int id) { char *name = NULL; unsigned char uuid[16]; - if (!VIR_IS_CONNECT(conn)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); return(NULL); - if (id < 0) + } + if (id < 0) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(NULL); + } /* lookup is easier with the Xen store so try it first */ if (conn->xshandle != NULL) { @@ -690,10 +772,14 @@ virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) { unsigned char ident[16]; int id = -1; - if (!VIR_IS_CONNECT(conn)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); return(NULL); - if (uuid == NULL) + } + if (uuid == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(NULL); + } names = xend_get_domains(conn); tmp = names; @@ -753,10 +839,14 @@ virDomainLookupByName(virConnectPtr conn, const char *name) { int found = 0; struct xend_domain *xenddomain = NULL; - if (!VIR_IS_CONNECT(conn)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); return(NULL); - if (name == NULL) + } + if (name == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); return(NULL); + } /* try first though Xend */ xenddomain = xend_get_domain(conn, name); @@ -834,8 +924,10 @@ int virDomainDestroy(virDomainPtr domain) { int ret; - if (!VIR_IS_CONNECTED_DOMAIN(domain)) + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(-1); + } /* * try first with the xend method @@ -865,8 +957,10 @@ virDomainDestroy(virDomainPtr domain) { */ int virDomainFree(virDomainPtr domain) { - if (!VIR_IS_DOMAIN(domain)) + if (!VIR_IS_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(-1); + } domain->magic = -1; domain->handle = -1; if (domain->path != NULL) @@ -893,8 +987,11 @@ int virDomainSuspend(virDomainPtr domain) { int ret; - if (!VIR_IS_CONNECTED_DOMAIN(domain)) + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(-1); + } + /* first try though the Xen daemon */ ret = xend_pause(domain->conn, domain->name); if (ret == 0) @@ -918,8 +1015,11 @@ int virDomainResume(virDomainPtr domain) { int ret; - if (!VIR_IS_CONNECTED_DOMAIN(domain)) + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(-1); + } + /* first try though the Xen daemon */ ret = xend_unpause(domain->conn, domain->name); if (ret == 0) @@ -946,8 +1046,14 @@ virDomainSave(virDomainPtr domain, const char *to) { int ret; char filepath[4096]; - if ((!VIR_IS_CONNECTED_DOMAIN(domain)) || (to == NULL)) + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(-1); + } + if (to == NULL) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } /* * We must absolutize the file path as the save is done out of process @@ -987,8 +1093,15 @@ virDomainRestore(virConnectPtr conn, const char *from) { int ret; char filepath[4096]; - if ((!VIR_IS_CONNECT(conn)) || (from == NULL)) + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__); return(-1); + } + if (from == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + /* * We must absolutize the file path as the restore is done out of process * TODO: check for URI when libxml2 is linked in. @@ -1029,8 +1142,10 @@ int virDomainShutdown(virDomainPtr domain) { int ret; - if (!VIR_IS_CONNECTED_DOMAIN(domain)) + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(-1); + } /* * try first with the xend daemon @@ -1061,8 +1176,10 @@ virDomainShutdown(virDomainPtr domain) { */ const char * virDomainGetName(virDomainPtr domain) { - if (!VIR_IS_DOMAIN(domain)) + if (!VIR_IS_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(NULL); + } return(domain->name); } @@ -1077,11 +1194,18 @@ virDomainGetName(virDomainPtr domain) { */ int virDomainGetUUID(virDomainPtr domain, unsigned char *uuid) { - if ((!VIR_IS_DOMAIN(domain)) || (uuid == NULL)) + if (!VIR_IS_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + return(-1); + } + if (uuid == NULL) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); - if (domain->handle == 0) + } + + if (domain->handle == 0) { memset(uuid, 0, 16); - else { + } else { if ((domain->uuid[0] == 0) && (domain->uuid[1] == 0) && (domain->uuid[2] == 0) && (domain->uuid[3] == 0) && (domain->uuid[4] == 0) && (domain->uuid[5] == 0) && @@ -1106,8 +1230,10 @@ virDomainGetUUID(virDomainPtr domain, unsigned char *uuid) { */ unsigned int virDomainGetID(virDomainPtr domain) { - if (!VIR_IS_DOMAIN(domain)) + if (!VIR_IS_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return((unsigned int) -1); + } return(domain->handle); } @@ -1123,8 +1249,10 @@ char * virDomainGetOSType(virDomainPtr domain) { char *vm, *str = NULL; - if (!VIR_IS_DOMAIN(domain)) + if (!VIR_IS_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(NULL); + } vm = virDomainGetVM(domain); if (vm) { @@ -1151,8 +1279,10 @@ unsigned long virDomainGetMaxMemory(virDomainPtr domain) { unsigned long ret = 0; - if (!VIR_IS_CONNECTED_DOMAIN(domain)) + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(0); + } if (domain->conn->flags & VIR_CONNECT_RO) { char *tmp; @@ -1192,10 +1322,14 @@ virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory) { int ret; char s[256], v[30]; - if (!VIR_IS_CONNECTED_DOMAIN(domain)) + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(-1); - if (memory < 4096) + } + if (memory < 4096) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); + } if (domain->conn->flags & VIR_CONNECT_RO) return(-1); if (domain->conn->xshandle==NULL) @@ -1240,10 +1374,14 @@ virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) { char request[200]; - if (!VIR_IS_CONNECTED_DOMAIN(domain)) + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(-1); - if (info == NULL) + } + if (info == NULL) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); return(-1); + } memset(info, 0, sizeof(virDomainInfo)); @@ -1352,10 +1490,14 @@ xend_info: */ char * virDomainGetXMLDesc(virDomainPtr domain, int flags) { - if (!VIR_IS_DOMAIN(domain)) + if (!VIR_IS_DOMAIN(domain)) { + virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); return(NULL); - if (flags != 0) + } + if (flags != 0) { + virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__); return(NULL); + } return(xend_get_domain_xml(domain)); } diff --git a/src/virterror.c b/src/virterror.c index ebb90a588c..8e6fc51b17 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "libvirt.h" #include "virterror.h" #include "internal.h" @@ -20,6 +21,43 @@ static virError lastErr = /* the last error */ static virErrorFunc virErrorHandler = NULL;/* global error handlet */ static void *virUserData = NULL; /* associated data */ +/* + * 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; \ + \ + str = (char *) malloc(150); \ + if (str != NULL) { \ + \ + size = 150; \ + \ + while (1) { \ + 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; \ + }} \ +} + /* * virGetLastError: * @@ -173,3 +211,181 @@ virConnSetErrorFunc(virConnectPtr conn, void *userData, virErrorFunc handler) { conn->userData = userData; } +/** + * virReportError: + * @err: pointer to the error. + * + * Internal routine reporting an error to stderr. + */ +static void +virReportError(virErrorPtr err) { + const char *lvl = "", *dom = "", *domain = ""; + int len; + + if ((err == NULL) || (err->code == VIR_ERR_OK)) + return; + switch (err->level) { + case VIR_ERR_NONE: + lvl = ""; + break; + case VIR_ERR_WARNING: + lvl = "warning"; + break; + case VIR_ERR_ERROR: + lvl = "error"; + break; + } + switch (err->domain) { + case VIR_FROM_NONE: + dom = ""; + break; + case VIR_FROM_XEN: + dom = "Xen "; + break; + case VIR_FROM_XEND: + dom = "Xen Daemon "; + break; + case VIR_FROM_DOM: + dom = "Domain "; + break; + } + if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) { + domain = err->dom->name; + } + len = strlen(err->message); + if ((len == 0) || (err->message[len - 1] != '\n')) + fprintf(stderr, "libvir: %s%s %s: %s\n", + dom, lvl, domain, err->message); + else + fprintf(stderr, "libvir: %s%s %s: %s", + dom, lvl, domain, err->message); +} + +/** + * __virRaiseError: + * @conn: the connection to the hypervisor if available + * @dom: the domain if available + * @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 +__virRaiseError(virConnectPtr conn, virDomainPtr dom, + int domain, int code, virErrorLevel level, + const char *str1, const char *str2, const char *str3, + int int1, int int2, const char *msg, ...) { + virErrorPtr to = &lastErr; + void *userData = virUserData; + virErrorFunc handler = virErrorHandler; + char *str; + + if (code == VIR_ERR_OK) + return; + + /* + * try to find the best place to save and report the error + */ + if (conn != NULL) { + to = &conn->err; + if (conn->handler != NULL) { + handler = conn->handler; + userData = conn->userData; + } + } + + /* + * formats the message + */ + if (msg == NULL) { + str = strdup("No error message provided"); + } else { + VIR_GET_VAR_STR(msg, str); + } + + /* + * Save the information about the error + */ + virResetError(to); + to->conn = conn; + to->dom = dom; + 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 { + virReportError(to); + } +} + +/** + * __virErrorMsg: + * @error: the virErrorNumber + * @info: usually the first paprameter string + * + * Internal routine to get the message associated to an error raised + * from the library + * + * Returns the constant string associated to @error + */ +const char * +__virErrorMsg(virErrorNumber error, const char *info) { + const char *errmsg = NULL; + + switch (error) { + case VIR_ERR_OK: + return(NULL); + case VIR_ERR_INTERNAL_ERROR: + if (info != NULL) + errmsg = "internal error %s"; + else + errmsg = "internal error"; + break; + case VIR_ERR_NO_MEMORY: + errmsg = "out of memory"; + break; + case VIR_ERR_NO_SUPPORT: + errmsg = "no support for hypervisor %s"; + break; + case VIR_ERR_NO_CONNECT: + if (info == NULL) + errmsg = "could not connect to hypervisor"; + else + errmsg = "could not connect to %s"; + break; + case VIR_ERR_INVALID_CONN: + errmsg = "invalid connection pointer in"; + break; + case VIR_ERR_INVALID_DOMAIN: + errmsg = "invalid domain pointer in"; + break; + case VIR_ERR_INVALID_ARG: + errmsg = "invalid domain pointer in"; + break; + } + return(errmsg); +} + diff --git a/src/xend_internal.c b/src/xend_internal.c index 2a3dfdd8d6..06bf4d6dc3 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -57,6 +57,28 @@ struct xend { struct sockaddr_in addr_in; }; + +/** + * virXendError: + * @conn: the connection if available + * @error: the error noumber + * @info: extra information string + * + * Handle an error at the xend daemon interface + */ +static void +virXendError(virConnectPtr conn, virErrorNumber error, const char *info) { + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + __virRaiseError(conn, NULL, VIR_FROM_XEND, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + + #define foreach(iterator, start) \ for (_for_i = (start), *iterator = (start)->car; \ _for_i->kind == SEXPR_CONS; \ @@ -81,10 +103,14 @@ do_connect(virConnectPtr xend) int serrno; s = socket(xend->type, SOCK_STREAM, 0); - if (s == -1) + if (s == -1) { + virXendError(xend, VIR_ERR_INTERNAL_ERROR, + "failed to create a socket"); return -1; + } if (connect(s, xend->addr, xend->len) == -1) { + virXendError(xend, VIR_ERR_NO_CONNECT, "Xen Daemon"); serrno = errno; close(s); errno = serrno; @@ -131,6 +157,13 @@ wr_sync(int fd, void *buffer, size_t size, int do_read) /* unrecoverable error */ if (len == -1) { + if (do_read) + virXendError(NULL, VIR_ERR_INTERNAL_ERROR, + "faid to read from Xen Daemon"); + else + virXendError(NULL, VIR_ERR_INTERNAL_ERROR, + "faid to read from Xen Daemon"); + return(-1); } @@ -309,6 +342,11 @@ xend_get(virConnectPtr xend, const char *path, ret = xend_req(s, content, n_content); close(s); + if ((ret < 0) || (ret >= 300)) { + virXendError(NULL, VIR_ERR_OPERATION_FAILED, + content); + } + return ret; } @@ -353,6 +391,11 @@ xend_post(virConnectPtr xend, const char *path, const char *ops, ret = xend_req(s, content, n_content); close(s); + if ((ret < 0) || (ret >= 300)) { + virXendError(NULL, VIR_ERR_OPERATION_FAILED, + content); + } + return ret; } -- GitLab