xref: /openbmc/qemu/util/error.c (revision cc40b8b8)
1baacf047SPaolo Bonzini /*
2baacf047SPaolo Bonzini  * QEMU Error Objects
3baacf047SPaolo Bonzini  *
4baacf047SPaolo Bonzini  * Copyright IBM, Corp. 2011
5a29a37b9SMarkus Armbruster  * Copyright (C) 2011-2015 Red Hat, Inc.
6baacf047SPaolo Bonzini  *
7baacf047SPaolo Bonzini  * Authors:
8baacf047SPaolo Bonzini  *  Anthony Liguori   <aliguori@us.ibm.com>
9a29a37b9SMarkus Armbruster  *  Markus Armbruster <armbru@redhat.com>,
10baacf047SPaolo Bonzini  *
11baacf047SPaolo Bonzini  * This work is licensed under the terms of the GNU LGPL, version 2.  See
12baacf047SPaolo Bonzini  * the COPYING.LIB file in the top-level directory.
13baacf047SPaolo Bonzini  */
14baacf047SPaolo Bonzini 
15aafd7584SPeter Maydell #include "qemu/osdep.h"
16da34e65cSMarkus Armbruster #include "qapi/error.h"
17073a3411SCole Robinson #include "qemu/error-report.h"
18baacf047SPaolo Bonzini 
19baacf047SPaolo Bonzini struct Error
20baacf047SPaolo Bonzini {
21baacf047SPaolo Bonzini     char *msg;
22baacf047SPaolo Bonzini     ErrorClass err_class;
231e9b65bbSMarkus Armbruster     const char *src, *func;
241e9b65bbSMarkus Armbruster     int line;
2550b7b000SEric Blake     GString *hint;
26baacf047SPaolo Bonzini };
27baacf047SPaolo Bonzini 
285d24ee70SPeter Crosthwaite Error *error_abort;
29a29a37b9SMarkus Armbruster Error *error_fatal;
303ffef1a5SMarc-André Lureau Error *error_warn;
315d24ee70SPeter Crosthwaite 
error_handle(Error ** errp,Error * err)323ffef1a5SMarc-André Lureau static void error_handle(Error **errp, Error *err)
331e9b65bbSMarkus Armbruster {
34a29a37b9SMarkus Armbruster     if (errp == &error_abort) {
351e9b65bbSMarkus Armbruster         fprintf(stderr, "Unexpected error in %s() at %s:%d:\n",
361e9b65bbSMarkus Armbruster                 err->func, err->src, err->line);
37b922c050SVladimir Sementsov-Ogievskiy         error_report("%s", error_get_pretty(err));
38b922c050SVladimir Sementsov-Ogievskiy         if (err->hint) {
39b922c050SVladimir Sementsov-Ogievskiy             error_printf("%s", err->hint->str);
40b922c050SVladimir Sementsov-Ogievskiy         }
411e9b65bbSMarkus Armbruster         abort();
421e9b65bbSMarkus Armbruster     }
43a29a37b9SMarkus Armbruster     if (errp == &error_fatal) {
44a29a37b9SMarkus Armbruster         error_report_err(err);
45a29a37b9SMarkus Armbruster         exit(1);
46a29a37b9SMarkus Armbruster     }
473ffef1a5SMarc-André Lureau     if (errp == &error_warn) {
483ffef1a5SMarc-André Lureau         warn_report_err(err);
49*cc40b8b8SStefan Berger     } else if (errp && !*errp) {
50*cc40b8b8SStefan Berger         *errp = err;
51*cc40b8b8SStefan Berger     } else {
52*cc40b8b8SStefan Berger         error_free(err);
533ffef1a5SMarc-André Lureau     }
54a29a37b9SMarkus Armbruster }
551e9b65bbSMarkus Armbruster 
56beede7e8SDaniel P. Berrangé 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)571e9b65bbSMarkus Armbruster static void error_setv(Error **errp,
581e9b65bbSMarkus Armbruster                        const char *src, int line, const char *func,
5920e2dec1SDaniel P. Berrange                        ErrorClass err_class, const char *fmt, va_list ap,
6020e2dec1SDaniel P. Berrange                        const char *suffix)
61baacf047SPaolo Bonzini {
62baacf047SPaolo Bonzini     Error *err;
63b276d249SMax Reitz     int saved_errno = errno;
64baacf047SPaolo Bonzini 
65baacf047SPaolo Bonzini     if (errp == NULL) {
66baacf047SPaolo Bonzini         return;
67baacf047SPaolo Bonzini     }
68baacf047SPaolo Bonzini     assert(*errp == NULL);
69baacf047SPaolo Bonzini 
70baacf047SPaolo Bonzini     err = g_malloc0(sizeof(*err));
71baacf047SPaolo Bonzini     err->msg = g_strdup_vprintf(fmt, ap);
7220e2dec1SDaniel P. Berrange     if (suffix) {
7320e2dec1SDaniel P. Berrange         char *msg = err->msg;
7420e2dec1SDaniel P. Berrange         err->msg = g_strdup_printf("%s: %s", msg, suffix);
7520e2dec1SDaniel P. Berrange         g_free(msg);
7620e2dec1SDaniel P. Berrange     }
77baacf047SPaolo Bonzini     err->err_class = err_class;
781e9b65bbSMarkus Armbruster     err->src = src;
791e9b65bbSMarkus Armbruster     err->line = line;
801e9b65bbSMarkus Armbruster     err->func = func;
81baacf047SPaolo Bonzini 
823ffef1a5SMarc-André Lureau     error_handle(errp, err);
83b276d249SMax Reitz 
84b276d249SMax Reitz     errno = saved_errno;
85baacf047SPaolo Bonzini }
86baacf047SPaolo Bonzini 
error_set_internal(Error ** errp,const char * src,int line,const char * func,ErrorClass err_class,const char * fmt,...)871e9b65bbSMarkus Armbruster void error_set_internal(Error **errp,
881e9b65bbSMarkus Armbruster                         const char *src, int line, const char *func,
891e9b65bbSMarkus Armbruster                         ErrorClass err_class, const char *fmt, ...)
9055237508SMarkus Armbruster {
9155237508SMarkus Armbruster     va_list ap;
9255237508SMarkus Armbruster 
9355237508SMarkus Armbruster     va_start(ap, fmt);
9420e2dec1SDaniel P. Berrange     error_setv(errp, src, line, func, err_class, fmt, ap, NULL);
9555237508SMarkus Armbruster     va_end(ap);
9655237508SMarkus Armbruster }
9755237508SMarkus Armbruster 
error_setg_internal(Error ** errp,const char * src,int line,const char * func,const char * fmt,...)981e9b65bbSMarkus Armbruster void error_setg_internal(Error **errp,
991e9b65bbSMarkus Armbruster                          const char *src, int line, const char *func,
1001e9b65bbSMarkus Armbruster                          const char *fmt, ...)
101a9499dddSMarkus Armbruster {
102a9499dddSMarkus Armbruster     va_list ap;
103a9499dddSMarkus Armbruster 
104a9499dddSMarkus Armbruster     va_start(ap, fmt);
10520e2dec1SDaniel P. Berrange     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap, NULL);
106a9499dddSMarkus Armbruster     va_end(ap);
107a9499dddSMarkus Armbruster }
108a9499dddSMarkus Armbruster 
error_setg_errno_internal(Error ** errp,const char * src,int line,const char * func,int os_errno,const char * fmt,...)1091e9b65bbSMarkus Armbruster void error_setg_errno_internal(Error **errp,
1101e9b65bbSMarkus Armbruster                                const char *src, int line, const char *func,
1111e9b65bbSMarkus Armbruster                                int os_errno, const char *fmt, ...)
112baacf047SPaolo Bonzini {
113baacf047SPaolo Bonzini     va_list ap;
114b276d249SMax Reitz     int saved_errno = errno;
115baacf047SPaolo Bonzini 
116baacf047SPaolo Bonzini     va_start(ap, fmt);
11720e2dec1SDaniel P. Berrange     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap,
11820e2dec1SDaniel P. Berrange                os_errno != 0 ? strerror(os_errno) : NULL);
119baacf047SPaolo Bonzini     va_end(ap);
120baacf047SPaolo Bonzini 
121b276d249SMax Reitz     errno = saved_errno;
122baacf047SPaolo Bonzini }
123baacf047SPaolo Bonzini 
error_setg_file_open_internal(Error ** errp,const char * src,int line,const char * func,int os_errno,const char * filename)1241e9b65bbSMarkus Armbruster void error_setg_file_open_internal(Error **errp,
1251e9b65bbSMarkus Armbruster                                    const char *src, int line, const char *func,
1261e9b65bbSMarkus Armbruster                                    int os_errno, const char *filename)
12754028d75SLuiz Capitulino {
1281e9b65bbSMarkus Armbruster     error_setg_errno_internal(errp, src, line, func, os_errno,
1291e9b65bbSMarkus Armbruster                               "Could not open '%s'", filename);
13054028d75SLuiz Capitulino }
13154028d75SLuiz Capitulino 
error_vprepend(Error * const * errp,const char * fmt,va_list ap)13249fbc723SVladimir Sementsov-Ogievskiy void error_vprepend(Error *const *errp, const char *fmt, va_list ap)
1338277d2aaSMarkus Armbruster {
1348277d2aaSMarkus Armbruster     GString *newmsg;
1358277d2aaSMarkus Armbruster 
1368277d2aaSMarkus Armbruster     if (!errp) {
1378277d2aaSMarkus Armbruster         return;
1388277d2aaSMarkus Armbruster     }
1398277d2aaSMarkus Armbruster 
1408277d2aaSMarkus Armbruster     newmsg = g_string_new(NULL);
1418277d2aaSMarkus Armbruster     g_string_vprintf(newmsg, fmt, ap);
1428277d2aaSMarkus Armbruster     g_string_append(newmsg, (*errp)->msg);
143536eeea8SMax Reitz     g_free((*errp)->msg);
1448277d2aaSMarkus Armbruster     (*errp)->msg = g_string_free(newmsg, 0);
1458277d2aaSMarkus Armbruster }
1468277d2aaSMarkus Armbruster 
error_prepend(Error * const * errp,const char * fmt,...)14749fbc723SVladimir Sementsov-Ogievskiy void error_prepend(Error *const *errp, const char *fmt, ...)
1488277d2aaSMarkus Armbruster {
1498277d2aaSMarkus Armbruster     va_list ap;
1508277d2aaSMarkus Armbruster 
1518277d2aaSMarkus Armbruster     va_start(ap, fmt);
1528277d2aaSMarkus Armbruster     error_vprepend(errp, fmt, ap);
1538277d2aaSMarkus Armbruster     va_end(ap);
1548277d2aaSMarkus Armbruster }
1558277d2aaSMarkus Armbruster 
error_append_hint(Error * const * errp,const char * fmt,...)15649fbc723SVladimir Sementsov-Ogievskiy void error_append_hint(Error *const *errp, const char *fmt, ...)
15750b7b000SEric Blake {
15850b7b000SEric Blake     va_list ap;
15950b7b000SEric Blake     int saved_errno = errno;
16050b7b000SEric Blake     Error *err;
16150b7b000SEric Blake 
16250b7b000SEric Blake     if (!errp) {
16350b7b000SEric Blake         return;
16450b7b000SEric Blake     }
16550b7b000SEric Blake     err = *errp;
166f4d0064aSMarkus Armbruster     assert(err && errp != &error_abort && errp != &error_fatal);
16750b7b000SEric Blake 
16850b7b000SEric Blake     if (!err->hint) {
16950b7b000SEric Blake         err->hint = g_string_new(NULL);
17050b7b000SEric Blake     }
17150b7b000SEric Blake     va_start(ap, fmt);
17250b7b000SEric Blake     g_string_append_vprintf(err->hint, fmt, ap);
17350b7b000SEric Blake     va_end(ap);
17450b7b000SEric Blake 
17550b7b000SEric Blake     errno = saved_errno;
17650b7b000SEric Blake }
17750b7b000SEric Blake 
17820840d4cSTomoki Sekiyama #ifdef _WIN32
17920840d4cSTomoki Sekiyama 
error_setg_win32_internal(Error ** errp,const char * src,int line,const char * func,int win32_err,const char * fmt,...)1801e9b65bbSMarkus Armbruster void error_setg_win32_internal(Error **errp,
1811e9b65bbSMarkus Armbruster                                const char *src, int line, const char *func,
1821e9b65bbSMarkus Armbruster                                int win32_err, const char *fmt, ...)
18320840d4cSTomoki Sekiyama {
18420840d4cSTomoki Sekiyama     va_list ap;
18520e2dec1SDaniel P. Berrange     char *suffix = NULL;
18620840d4cSTomoki Sekiyama 
18720840d4cSTomoki Sekiyama     if (errp == NULL) {
18820840d4cSTomoki Sekiyama         return;
18920840d4cSTomoki Sekiyama     }
19020840d4cSTomoki Sekiyama 
19120e2dec1SDaniel P. Berrange     if (win32_err != 0) {
19220e2dec1SDaniel P. Berrange         suffix = g_win32_error_message(win32_err);
19320e2dec1SDaniel P. Berrange     }
19420e2dec1SDaniel P. Berrange 
19520840d4cSTomoki Sekiyama     va_start(ap, fmt);
19620e2dec1SDaniel P. Berrange     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR,
19720e2dec1SDaniel P. Berrange                fmt, ap, suffix);
19855237508SMarkus Armbruster     va_end(ap);
19955237508SMarkus Armbruster 
20020e2dec1SDaniel P. Berrange     g_free(suffix);
20120840d4cSTomoki Sekiyama }
20220840d4cSTomoki Sekiyama 
20320840d4cSTomoki Sekiyama #endif
20420840d4cSTomoki Sekiyama 
error_copy(const Error * err)205baacf047SPaolo Bonzini Error *error_copy(const Error *err)
206baacf047SPaolo Bonzini {
207baacf047SPaolo Bonzini     Error *err_new;
208baacf047SPaolo Bonzini 
209baacf047SPaolo Bonzini     err_new = g_malloc0(sizeof(*err));
210baacf047SPaolo Bonzini     err_new->msg = g_strdup(err->msg);
211baacf047SPaolo Bonzini     err_new->err_class = err->err_class;
21288e2ce29SEric Blake     err_new->src = err->src;
21388e2ce29SEric Blake     err_new->line = err->line;
21488e2ce29SEric Blake     err_new->func = err->func;
21550b7b000SEric Blake     if (err->hint) {
21650b7b000SEric Blake         err_new->hint = g_string_new(err->hint->str);
21750b7b000SEric Blake     }
218baacf047SPaolo Bonzini 
219baacf047SPaolo Bonzini     return err_new;
220baacf047SPaolo Bonzini }
221baacf047SPaolo Bonzini 
error_get_class(const Error * err)222baacf047SPaolo Bonzini ErrorClass error_get_class(const Error *err)
223baacf047SPaolo Bonzini {
224baacf047SPaolo Bonzini     return err->err_class;
225baacf047SPaolo Bonzini }
226baacf047SPaolo Bonzini 
error_get_pretty(const Error * err)227d59ce6f3SDaniel P. Berrange const char *error_get_pretty(const Error *err)
228baacf047SPaolo Bonzini {
229baacf047SPaolo Bonzini     return err->msg;
230baacf047SPaolo Bonzini }
231baacf047SPaolo Bonzini 
error_report_err(Error * err)2322ee2f1e4SMarkus Armbruster void error_report_err(Error *err)
2332ee2f1e4SMarkus Armbruster {
2342ee2f1e4SMarkus Armbruster     error_report("%s", error_get_pretty(err));
23550b7b000SEric Blake     if (err->hint) {
2364c8b7c8bSMarkus Armbruster         error_printf("%s", err->hint->str);
23750b7b000SEric Blake     }
2382ee2f1e4SMarkus Armbruster     error_free(err);
2392ee2f1e4SMarkus Armbruster }
2402ee2f1e4SMarkus Armbruster 
warn_report_err(Error * err)241e43ead1dSAlistair Francis void warn_report_err(Error *err)
242e43ead1dSAlistair Francis {
243e43ead1dSAlistair Francis     warn_report("%s", error_get_pretty(err));
244e43ead1dSAlistair Francis     if (err->hint) {
2454c8b7c8bSMarkus Armbruster         error_printf("%s", err->hint->str);
246e43ead1dSAlistair Francis     }
247e43ead1dSAlistair Francis     error_free(err);
248e43ead1dSAlistair Francis }
249e43ead1dSAlistair Francis 
error_reportf_err(Error * err,const char * fmt,...)2508277d2aaSMarkus Armbruster void error_reportf_err(Error *err, const char *fmt, ...)
2518277d2aaSMarkus Armbruster {
2528277d2aaSMarkus Armbruster     va_list ap;
2538277d2aaSMarkus Armbruster 
2548277d2aaSMarkus Armbruster     va_start(ap, fmt);
2558277d2aaSMarkus Armbruster     error_vprepend(&err, fmt, ap);
2568277d2aaSMarkus Armbruster     va_end(ap);
2578277d2aaSMarkus Armbruster     error_report_err(err);
2588277d2aaSMarkus Armbruster }
2598277d2aaSMarkus Armbruster 
260e43ead1dSAlistair Francis 
warn_reportf_err(Error * err,const char * fmt,...)261e43ead1dSAlistair Francis void warn_reportf_err(Error *err, const char *fmt, ...)
262e43ead1dSAlistair Francis {
263e43ead1dSAlistair Francis     va_list ap;
264e43ead1dSAlistair Francis 
265e43ead1dSAlistair Francis     va_start(ap, fmt);
266e43ead1dSAlistair Francis     error_vprepend(&err, fmt, ap);
267e43ead1dSAlistair Francis     va_end(ap);
268e43ead1dSAlistair Francis     warn_report_err(err);
269e43ead1dSAlistair Francis }
270e43ead1dSAlistair Francis 
error_free(Error * err)271baacf047SPaolo Bonzini void error_free(Error *err)
272baacf047SPaolo Bonzini {
273baacf047SPaolo Bonzini     if (err) {
274baacf047SPaolo Bonzini         g_free(err->msg);
27550b7b000SEric Blake         if (err->hint) {
27650b7b000SEric Blake             g_string_free(err->hint, true);
27750b7b000SEric Blake         }
278baacf047SPaolo Bonzini         g_free(err);
279baacf047SPaolo Bonzini     }
280baacf047SPaolo Bonzini }
281baacf047SPaolo Bonzini 
error_free_or_abort(Error ** errp)282a12a5a1aSEric Blake void error_free_or_abort(Error **errp)
283a12a5a1aSEric Blake {
284a12a5a1aSEric Blake     assert(errp && *errp);
285a12a5a1aSEric Blake     error_free(*errp);
286a12a5a1aSEric Blake     *errp = NULL;
287a12a5a1aSEric Blake }
288a12a5a1aSEric Blake 
error_propagate(Error ** dst_errp,Error * local_err)28964dfefedSMarkus Armbruster void error_propagate(Error **dst_errp, Error *local_err)
290baacf047SPaolo Bonzini {
291a29a37b9SMarkus Armbruster     if (!local_err) {
292a29a37b9SMarkus Armbruster         return;
293a29a37b9SMarkus Armbruster     }
2943ffef1a5SMarc-André Lureau     error_handle(dst_errp, local_err);
295baacf047SPaolo Bonzini }
2964b576648SMarkus Armbruster 
error_propagate_prepend(Error ** dst_errp,Error * err,const char * fmt,...)2974b576648SMarkus Armbruster void error_propagate_prepend(Error **dst_errp, Error *err,
2984b576648SMarkus Armbruster                              const char *fmt, ...)
2994b576648SMarkus Armbruster {
3004b576648SMarkus Armbruster     va_list ap;
3014b576648SMarkus Armbruster 
3024b576648SMarkus Armbruster     if (dst_errp && !*dst_errp) {
3034b576648SMarkus Armbruster         va_start(ap, fmt);
3044b576648SMarkus Armbruster         error_vprepend(&err, fmt, ap);
3054b576648SMarkus Armbruster         va_end(ap);
3064b576648SMarkus Armbruster     } /* else error is being ignored, don't bother with prepending */
3074b576648SMarkus Armbruster     error_propagate(dst_errp, err);
3084b576648SMarkus Armbruster }
309