8be47a0242bc1894b91533260a946acb737f9a07
[vsc-common.git] / misc / error.c
1 /*
2  * error.c: Library of miscellaneous stuff for other libvsc* libraries
3  *
4  * Copyright (C) 2009 Matthias Bolte <matthias.bolte@googlemail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25
26 #include "../include/libvscmisc/assert.h"
27 #include "../include/libvscmisc/error.h"
28 #include "../include/libvscmisc/list.h"
29 #include "../include/libvscmisc/memory.h"
30
31 #define _ERROR__MESSAGE_SIZE 4096
32
33 static const char *_error_default_message =
34    "Could not allocate memory for error message";
35
36 static struct VscError _error_default = {
37         .next = NULL,
38         .occured = TRUE,
39         .code = VSC__ERROR_CODE__OUT_OF_MEMORY,
40         .message = NULL,
41         .file = "none",
42         .line = -1,
43         .function = "none",
44 };
45
46 static void
47 _error_report_v (struct VscError *error, enum VscErrorCode code,
48                  const char *file, int line, const char *function,
49                  const char *message, va_list args)
50 {
51         VSC__ASSERT (error != NULL);
52         VSC__ASSERT (! error->occured);
53         VSC__ASSERT (error->message == NULL);
54         VSC__ASSERT (code != VSC__ERROR_CODE__UNDEFINED);
55
56         error->occured = TRUE;
57         error->code = code;
58         error->file = file;
59         error->line = line;
60         error->function = function;
61
62         if (message == NULL) {
63                 error->message = NULL;
64         } else {
65                 error->message = calloc (1, _ERROR__MESSAGE_SIZE);
66
67                 if (error->message == NULL) {
68                         error->message = (char *) _error_default_message;
69                 } else {
70                         vsnprintf (error->message, _ERROR__MESSAGE_SIZE, message, args);
71                 }
72         }
73
74         gettimeofday (&error->timestamp, NULL);
75 }
76
77 const char *
78 vsc_error_string (enum VscErrorCode code)
79 {
80         switch (code) {
81         case VSC__ERROR_CODE__INTERNAL_ERROR:
82                 return "Internal error";
83
84         case VSC__ERROR_CODE__OUT_OF_MEMORY:
85                 return "Out of memory";
86
87         case VSC__ERROR_CODE__XMLRPC_ERROR:
88                 return "XML-RPC error";
89
90         case VSC__ERROR_CODE__PTHREAD_ERROR:
91                 return "Pthread error";
92
93         case VSC__ERROR_CODE__LIBVIRT_ERROR:
94                 return "Libvirt error";
95
96         case VSC__ERROR_CODE__INVALID_ARGUMENT:
97                 return "Invalid argument";
98
99         case VSC__ERROR_CODE__INVALID_CALL:
100                 return "Invalid call";
101
102         case VSC__ERROR_CODE__INVALID_UUID_STRING:
103                 return "Invalid UUID string";
104
105         case VSC__ERROR_CODE__INVALID_IPV4_STRING:
106                 return "Invalid IPv4 string";
107
108         case VSC__ERROR_CODE__INVALID_HOST_TYPE_STRING:
109                 return "Invalid host type string";
110
111         case VSC__ERROR_CODE__NOT_INITIALIZED:
112                 return "Not initialized";
113
114         case VSC__ERROR_CODE__NOT_IMPLEMENTED_YET:
115                 return "Not implemented yet";
116
117         case VSC__ERROR_CODE__ALREADY_KNOWN:
118                 return "Already known";
119
120         case VSC__ERROR_CODE__ERRNO:
121                 return "errno";
122
123         case VSC__ERROR_CODE__TRACE:
124                 return "Inherited error";
125
126         default:
127                 return "Undefined";
128         }
129 }
130
131 void
132 vsc_error_fprint (struct VscError *error, FILE *stream)
133 {
134         struct tm time_info;
135         struct VscError *error_next = NULL;
136
137         VSC__ASSERT (error != NULL);
138         VSC__ASSERT (error->occured);
139         VSC__ASSERT (stream != NULL);
140
141         if (! error->occured) {
142                 return;
143         }
144
145         localtime_r (&error->timestamp.tv_sec, &time_info);
146
147         fprintf (stream, "%02d:%02d:%02d.%03d %s:%d %s : error [%s]",
148                  time_info.tm_hour, time_info.tm_min, time_info.tm_sec,
149                  (int) error->timestamp.tv_usec / 1000, error->file,
150                  error->line, error->function,
151                  vsc_error_string (error->code));
152
153         if (error->message != NULL) {
154                 fprintf (stream, " %s\n", error->message);
155         } else {
156                 fprintf (stream, "\n");
157         }
158
159         for (error_next = error->next; error_next != NULL;
160              error_next = error_next->next) {
161                 fprintf (stream, "             %s:%d %s : error [%s]",
162                          error_next->file, error_next->line, error_next->function,
163                          vsc_error_string (error_next->code));
164
165                 if (error_next->message != NULL) {
166                         fprintf (stream, " %s\n", error_next->message);
167                 } else {
168                         fprintf (stream, "\n");
169                 }
170         }
171 }
172
173 void
174 vsc_error_init (struct VscError *error)
175 {
176         VSC__ASSERT (error != NULL);
177
178         error->next = NULL;
179         error->occured = FALSE;
180         error->code = VSC__ERROR_CODE__UNDEFINED;
181         error->file = NULL;
182         error->line = -1;
183         error->function = NULL;
184         error->message = NULL;
185
186         memset (&error->timestamp, 0, sizeof (struct timeval));
187 }
188
189 void
190 vsc_error_cleanup (struct VscError *error)
191 {
192         struct VscError *current;
193         struct VscError *next;
194
195         VSC__ASSERT (error != NULL);
196
197         if (error->message != _error_default_message) {
198                 vsc_free (&error->message);
199         } else {
200                 error->message = NULL;
201         }
202
203         /*
204          * Free the error list messages if they are allocated (not the default
205          * error message) and free the error structs too, if they are allocated
206          * (not the default error). But do not free the first element of the list
207          * because we do not "own" its memory.
208          */
209         current = error->next;
210
211         while (current != NULL) {
212                 next = current->next;
213
214                 if (current->message != _error_default_message) {
215                         vsc_free (&current->message);
216                 } else {
217                         current->message = NULL;
218                 }
219
220                 if (current != &_error_default) {
221                         vsc_free (&current);
222                 }
223
224                 current = next;
225         }
226 }
227
228 void
229 vsc_error_report (struct VscError *error, enum VscErrorCode code,
230                   const char *file, int line, const char *function,
231                   const char *message, ...)
232 {
233         va_list args;
234
235         va_start (args, message);
236         _error_report_v (error, code, file, line, function, message, args);
237         va_end (args);
238 }
239
240 void
241 vsc_error_append_report (struct VscError *error, enum VscErrorCode code,
242                          const char *file, int line, const char *function,
243                          const char *message, ...)
244 {
245         va_list args;
246         struct VscError *error_last;
247         struct VscError *error_next;
248
249         VSC__ASSERT (error != NULL);
250         VSC__ASSERT (error->occured);
251         VSC__ASSERT (code != VSC__ERROR_CODE__UNDEFINED);
252
253         error_last = (struct VscError *)
254                         vsc_list_get_last ((struct VscList *) error);
255
256         /*
257          * Do not append to the default error, because if it is appended we are
258          * already in an out-of-memory situation.
259          */
260         if (error_last == &_error_default) {
261                 return;
262         }
263
264         error_next = calloc (1, sizeof (struct VscError));
265
266         if (error_next == NULL) {
267                 error_next = &_error_default;
268         } else {
269                 va_start (args, message);
270                 _error_report_v (error_next, code, file, line, function, message,
271                                  args);
272                 va_end (args);
273         }
274
275         error_last->next = error_next;
276 }