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