]> xenbits.xensource.com Git - libvirt.git/commitdiff
* TODO: updated
authorDaniel Veillard <veillard@redhat.com>
Mon, 27 Feb 2006 16:27:18 +0000 (16:27 +0000)
committerDaniel Veillard <veillard@redhat.com>
Mon, 27 Feb 2006 16:27:18 +0000 (16:27 +0000)
* 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
TODO
include/libvirt/virterror.h
include/virterror.h
src/internal.h
src/libvirt.c
src/virterror.c
src/xend_internal.c

index cddb4a66f1a3167ed9b810260d8cf45d6c09a323..19d36a21303fef9ce16760dbf12b29d12882ab9c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Mon Feb 27 17:25:48 CET 2006 Daniel Veillard <veillard@redhat.com>
+
+       * 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 <veillard@redhat.com>
 
        * src/Makefile.am src/internal.h src/libvirt.c src/libvirt_sym.version
diff --git a/TODO b/TODO
index b5548c2947a27a9d400bf58f86df98f72d77b3f4..82e47dc4fc560e1f67d066e1e8f36bc02ccb538d 100644 (file)
--- 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/* ?)
index bd5e2acd02063aa95fe8a84ecdc518b40824161b..d9d3972f593cfdb89c1ca1fb04a20979d2f1a7fb 100644 (file)
@@ -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;
 
 /**
index bd5e2acd02063aa95fe8a84ecdc518b40824161b..d9d3972f593cfdb89c1ca1fb04a20979d2f1a7fb 100644 (file)
@@ -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;
 
 /**
index d9c89c469e8500c7f3747623e76b06958a0c75ce..1df8c388bfb4329fa50377e46fefe072875d8129 100644 (file)
@@ -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 */
index 7b8325a49fa60b7068ece2d972669ae4019a2a8f..102d18d8a78604ee1620f08aa1b88e99c82ee4be 100644 (file)
  * - 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));
 }
index ebb90a588c17fcdf796a392a5bd48702a2d84c5c..8e6fc51b17f2432b3b89b6d5a4e257ea0155f927 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 #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);
+}
+
index 2a3dfdd8d63c29e61dff86d16e9c1b72dff6dc9e..06bf4d6dc32e14c7272fddbe9d1856c7299ddca9 100644 (file)
@@ -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;
 }