xref: /openbmc/qemu/util/error.c (revision cc40b8b8)
1 /*
2  * QEMU Error Objects
3  *
4  * Copyright IBM, Corp. 2011
5  * Copyright (C) 2011-2015 Red Hat, Inc.
6  *
7  * Authors:
8  *  Anthony Liguori   <aliguori@us.ibm.com>
9  *  Markus Armbruster <armbru@redhat.com>,
10  *
11  * This work is licensed under the terms of the GNU LGPL, version 2.  See
12  * the COPYING.LIB file in the top-level directory.
13  */
14 
15 #include "qemu/osdep.h"
16 #include "qapi/error.h"
17 #include "qemu/error-report.h"
18 
19 struct Error
20 {
21     char *msg;
22     ErrorClass err_class;
23     const char *src, *func;
24     int line;
25     GString *hint;
26 };
27 
28 Error *error_abort;
29 Error *error_fatal;
30 Error *error_warn;
31 
error_handle(Error ** errp,Error * err)32 static void error_handle(Error **errp, Error *err)
33 {
34     if (errp == &error_abort) {
35         fprintf(stderr, "Unexpected error in %s() at %s:%d:\n",
36                 err->func, err->src, err->line);
37         error_report("%s", error_get_pretty(err));
38         if (err->hint) {
39             error_printf("%s", err->hint->str);
40         }
41         abort();
42     }
43     if (errp == &error_fatal) {
44         error_report_err(err);
45         exit(1);
46     }
47     if (errp == &error_warn) {
48         warn_report_err(err);
49     } else if (errp && !*errp) {
50         *errp = err;
51     } else {
52         error_free(err);
53     }
54 }
55 
56 G_GNUC_PRINTF(6, 0)
error_setv(Error ** errp,const char * src,int line,const char * func,ErrorClass err_class,const char * fmt,va_list ap,const char * suffix)57 static void error_setv(Error **errp,
58                        const char *src, int line, const char *func,
59                        ErrorClass err_class, const char *fmt, va_list ap,
60                        const char *suffix)
61 {
62     Error *err;
63     int saved_errno = errno;
64 
65     if (errp == NULL) {
66         return;
67     }
68     assert(*errp == NULL);
69 
70     err = g_malloc0(sizeof(*err));
71     err->msg = g_strdup_vprintf(fmt, ap);
72     if (suffix) {
73         char *msg = err->msg;
74         err->msg = g_strdup_printf("%s: %s", msg, suffix);
75         g_free(msg);
76     }
77     err->err_class = err_class;
78     err->src = src;
79     err->line = line;
80     err->func = func;
81 
82     error_handle(errp, err);
83 
84     errno = saved_errno;
85 }
86 
error_set_internal(Error ** errp,const char * src,int line,const char * func,ErrorClass err_class,const char * fmt,...)87 void error_set_internal(Error **errp,
88                         const char *src, int line, const char *func,
89                         ErrorClass err_class, const char *fmt, ...)
90 {
91     va_list ap;
92 
93     va_start(ap, fmt);
94     error_setv(errp, src, line, func, err_class, fmt, ap, NULL);
95     va_end(ap);
96 }
97 
error_setg_internal(Error ** errp,const char * src,int line,const char * func,const char * fmt,...)98 void error_setg_internal(Error **errp,
99                          const char *src, int line, const char *func,
100                          const char *fmt, ...)
101 {
102     va_list ap;
103 
104     va_start(ap, fmt);
105     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap, NULL);
106     va_end(ap);
107 }
108 
error_setg_errno_internal(Error ** errp,const char * src,int line,const char * func,int os_errno,const char * fmt,...)109 void error_setg_errno_internal(Error **errp,
110                                const char *src, int line, const char *func,
111                                int os_errno, const char *fmt, ...)
112 {
113     va_list ap;
114     int saved_errno = errno;
115 
116     va_start(ap, fmt);
117     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap,
118                os_errno != 0 ? strerror(os_errno) : NULL);
119     va_end(ap);
120 
121     errno = saved_errno;
122 }
123 
error_setg_file_open_internal(Error ** errp,const char * src,int line,const char * func,int os_errno,const char * filename)124 void error_setg_file_open_internal(Error **errp,
125                                    const char *src, int line, const char *func,
126                                    int os_errno, const char *filename)
127 {
128     error_setg_errno_internal(errp, src, line, func, os_errno,
129                               "Could not open '%s'", filename);
130 }
131 
error_vprepend(Error * const * errp,const char * fmt,va_list ap)132 void error_vprepend(Error *const *errp, const char *fmt, va_list ap)
133 {
134     GString *newmsg;
135 
136     if (!errp) {
137         return;
138     }
139 
140     newmsg = g_string_new(NULL);
141     g_string_vprintf(newmsg, fmt, ap);
142     g_string_append(newmsg, (*errp)->msg);
143     g_free((*errp)->msg);
144     (*errp)->msg = g_string_free(newmsg, 0);
145 }
146 
error_prepend(Error * const * errp,const char * fmt,...)147 void error_prepend(Error *const *errp, const char *fmt, ...)
148 {
149     va_list ap;
150 
151     va_start(ap, fmt);
152     error_vprepend(errp, fmt, ap);
153     va_end(ap);
154 }
155 
error_append_hint(Error * const * errp,const char * fmt,...)156 void error_append_hint(Error *const *errp, const char *fmt, ...)
157 {
158     va_list ap;
159     int saved_errno = errno;
160     Error *err;
161 
162     if (!errp) {
163         return;
164     }
165     err = *errp;
166     assert(err && errp != &error_abort && errp != &error_fatal);
167 
168     if (!err->hint) {
169         err->hint = g_string_new(NULL);
170     }
171     va_start(ap, fmt);
172     g_string_append_vprintf(err->hint, fmt, ap);
173     va_end(ap);
174 
175     errno = saved_errno;
176 }
177 
178 #ifdef _WIN32
179 
error_setg_win32_internal(Error ** errp,const char * src,int line,const char * func,int win32_err,const char * fmt,...)180 void error_setg_win32_internal(Error **errp,
181                                const char *src, int line, const char *func,
182                                int win32_err, const char *fmt, ...)
183 {
184     va_list ap;
185     char *suffix = NULL;
186 
187     if (errp == NULL) {
188         return;
189     }
190 
191     if (win32_err != 0) {
192         suffix = g_win32_error_message(win32_err);
193     }
194 
195     va_start(ap, fmt);
196     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR,
197                fmt, ap, suffix);
198     va_end(ap);
199 
200     g_free(suffix);
201 }
202 
203 #endif
204 
error_copy(const Error * err)205 Error *error_copy(const Error *err)
206 {
207     Error *err_new;
208 
209     err_new = g_malloc0(sizeof(*err));
210     err_new->msg = g_strdup(err->msg);
211     err_new->err_class = err->err_class;
212     err_new->src = err->src;
213     err_new->line = err->line;
214     err_new->func = err->func;
215     if (err->hint) {
216         err_new->hint = g_string_new(err->hint->str);
217     }
218 
219     return err_new;
220 }
221 
error_get_class(const Error * err)222 ErrorClass error_get_class(const Error *err)
223 {
224     return err->err_class;
225 }
226 
error_get_pretty(const Error * err)227 const char *error_get_pretty(const Error *err)
228 {
229     return err->msg;
230 }
231 
error_report_err(Error * err)232 void error_report_err(Error *err)
233 {
234     error_report("%s", error_get_pretty(err));
235     if (err->hint) {
236         error_printf("%s", err->hint->str);
237     }
238     error_free(err);
239 }
240 
warn_report_err(Error * err)241 void warn_report_err(Error *err)
242 {
243     warn_report("%s", error_get_pretty(err));
244     if (err->hint) {
245         error_printf("%s", err->hint->str);
246     }
247     error_free(err);
248 }
249 
error_reportf_err(Error * err,const char * fmt,...)250 void error_reportf_err(Error *err, const char *fmt, ...)
251 {
252     va_list ap;
253 
254     va_start(ap, fmt);
255     error_vprepend(&err, fmt, ap);
256     va_end(ap);
257     error_report_err(err);
258 }
259 
260 
warn_reportf_err(Error * err,const char * fmt,...)261 void warn_reportf_err(Error *err, const char *fmt, ...)
262 {
263     va_list ap;
264 
265     va_start(ap, fmt);
266     error_vprepend(&err, fmt, ap);
267     va_end(ap);
268     warn_report_err(err);
269 }
270 
error_free(Error * err)271 void error_free(Error *err)
272 {
273     if (err) {
274         g_free(err->msg);
275         if (err->hint) {
276             g_string_free(err->hint, true);
277         }
278         g_free(err);
279     }
280 }
281 
error_free_or_abort(Error ** errp)282 void error_free_or_abort(Error **errp)
283 {
284     assert(errp && *errp);
285     error_free(*errp);
286     *errp = NULL;
287 }
288 
error_propagate(Error ** dst_errp,Error * local_err)289 void error_propagate(Error **dst_errp, Error *local_err)
290 {
291     if (!local_err) {
292         return;
293     }
294     error_handle(dst_errp, local_err);
295 }
296 
error_propagate_prepend(Error ** dst_errp,Error * err,const char * fmt,...)297 void error_propagate_prepend(Error **dst_errp, Error *err,
298                              const char *fmt, ...)
299 {
300     va_list ap;
301 
302     if (dst_errp && !*dst_errp) {
303         va_start(ap, fmt);
304         error_vprepend(&err, fmt, ap);
305         va_end(ap);
306     } /* else error is being ignored, don't bother with prepending */
307     error_propagate(dst_errp, err);
308 }
309