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; 30*3ffef1a5SMarc-André Lureau Error *error_warn; 315d24ee70SPeter Crosthwaite 32*3ffef1a5SMarc-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 } 47*3ffef1a5SMarc-André Lureau if (errp == &error_warn) { 48*3ffef1a5SMarc-André Lureau warn_report_err(err); 49*3ffef1a5SMarc-André Lureau } 50a29a37b9SMarkus Armbruster } 511e9b65bbSMarkus Armbruster 52beede7e8SDaniel P. Berrangé G_GNUC_PRINTF(6, 0) 531e9b65bbSMarkus Armbruster static void error_setv(Error **errp, 541e9b65bbSMarkus Armbruster const char *src, int line, const char *func, 5520e2dec1SDaniel P. Berrange ErrorClass err_class, const char *fmt, va_list ap, 5620e2dec1SDaniel P. Berrange const char *suffix) 57baacf047SPaolo Bonzini { 58baacf047SPaolo Bonzini Error *err; 59b276d249SMax Reitz int saved_errno = errno; 60baacf047SPaolo Bonzini 61baacf047SPaolo Bonzini if (errp == NULL) { 62baacf047SPaolo Bonzini return; 63baacf047SPaolo Bonzini } 64baacf047SPaolo Bonzini assert(*errp == NULL); 65baacf047SPaolo Bonzini 66baacf047SPaolo Bonzini err = g_malloc0(sizeof(*err)); 67baacf047SPaolo Bonzini err->msg = g_strdup_vprintf(fmt, ap); 6820e2dec1SDaniel P. Berrange if (suffix) { 6920e2dec1SDaniel P. Berrange char *msg = err->msg; 7020e2dec1SDaniel P. Berrange err->msg = g_strdup_printf("%s: %s", msg, suffix); 7120e2dec1SDaniel P. Berrange g_free(msg); 7220e2dec1SDaniel P. Berrange } 73baacf047SPaolo Bonzini err->err_class = err_class; 741e9b65bbSMarkus Armbruster err->src = src; 751e9b65bbSMarkus Armbruster err->line = line; 761e9b65bbSMarkus Armbruster err->func = func; 77baacf047SPaolo Bonzini 78*3ffef1a5SMarc-André Lureau error_handle(errp, err); 79baacf047SPaolo Bonzini *errp = err; 80b276d249SMax Reitz 81b276d249SMax Reitz errno = saved_errno; 82baacf047SPaolo Bonzini } 83baacf047SPaolo Bonzini 841e9b65bbSMarkus Armbruster void error_set_internal(Error **errp, 851e9b65bbSMarkus Armbruster const char *src, int line, const char *func, 861e9b65bbSMarkus Armbruster ErrorClass err_class, const char *fmt, ...) 8755237508SMarkus Armbruster { 8855237508SMarkus Armbruster va_list ap; 8955237508SMarkus Armbruster 9055237508SMarkus Armbruster va_start(ap, fmt); 9120e2dec1SDaniel P. Berrange error_setv(errp, src, line, func, err_class, fmt, ap, NULL); 9255237508SMarkus Armbruster va_end(ap); 9355237508SMarkus Armbruster } 9455237508SMarkus Armbruster 951e9b65bbSMarkus Armbruster void error_setg_internal(Error **errp, 961e9b65bbSMarkus Armbruster const char *src, int line, const char *func, 971e9b65bbSMarkus Armbruster const char *fmt, ...) 98a9499dddSMarkus Armbruster { 99a9499dddSMarkus Armbruster va_list ap; 100a9499dddSMarkus Armbruster 101a9499dddSMarkus Armbruster va_start(ap, fmt); 10220e2dec1SDaniel P. Berrange error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap, NULL); 103a9499dddSMarkus Armbruster va_end(ap); 104a9499dddSMarkus Armbruster } 105a9499dddSMarkus Armbruster 1061e9b65bbSMarkus Armbruster void error_setg_errno_internal(Error **errp, 1071e9b65bbSMarkus Armbruster const char *src, int line, const char *func, 1081e9b65bbSMarkus Armbruster int os_errno, const char *fmt, ...) 109baacf047SPaolo Bonzini { 110baacf047SPaolo Bonzini va_list ap; 111b276d249SMax Reitz int saved_errno = errno; 112baacf047SPaolo Bonzini 113baacf047SPaolo Bonzini va_start(ap, fmt); 11420e2dec1SDaniel P. Berrange error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap, 11520e2dec1SDaniel P. Berrange os_errno != 0 ? strerror(os_errno) : NULL); 116baacf047SPaolo Bonzini va_end(ap); 117baacf047SPaolo Bonzini 118b276d249SMax Reitz errno = saved_errno; 119baacf047SPaolo Bonzini } 120baacf047SPaolo Bonzini 1211e9b65bbSMarkus Armbruster void error_setg_file_open_internal(Error **errp, 1221e9b65bbSMarkus Armbruster const char *src, int line, const char *func, 1231e9b65bbSMarkus Armbruster int os_errno, const char *filename) 12454028d75SLuiz Capitulino { 1251e9b65bbSMarkus Armbruster error_setg_errno_internal(errp, src, line, func, os_errno, 1261e9b65bbSMarkus Armbruster "Could not open '%s'", filename); 12754028d75SLuiz Capitulino } 12854028d75SLuiz Capitulino 12949fbc723SVladimir Sementsov-Ogievskiy void error_vprepend(Error *const *errp, const char *fmt, va_list ap) 1308277d2aaSMarkus Armbruster { 1318277d2aaSMarkus Armbruster GString *newmsg; 1328277d2aaSMarkus Armbruster 1338277d2aaSMarkus Armbruster if (!errp) { 1348277d2aaSMarkus Armbruster return; 1358277d2aaSMarkus Armbruster } 1368277d2aaSMarkus Armbruster 1378277d2aaSMarkus Armbruster newmsg = g_string_new(NULL); 1388277d2aaSMarkus Armbruster g_string_vprintf(newmsg, fmt, ap); 1398277d2aaSMarkus Armbruster g_string_append(newmsg, (*errp)->msg); 140536eeea8SMax Reitz g_free((*errp)->msg); 1418277d2aaSMarkus Armbruster (*errp)->msg = g_string_free(newmsg, 0); 1428277d2aaSMarkus Armbruster } 1438277d2aaSMarkus Armbruster 14449fbc723SVladimir Sementsov-Ogievskiy void error_prepend(Error *const *errp, const char *fmt, ...) 1458277d2aaSMarkus Armbruster { 1468277d2aaSMarkus Armbruster va_list ap; 1478277d2aaSMarkus Armbruster 1488277d2aaSMarkus Armbruster va_start(ap, fmt); 1498277d2aaSMarkus Armbruster error_vprepend(errp, fmt, ap); 1508277d2aaSMarkus Armbruster va_end(ap); 1518277d2aaSMarkus Armbruster } 1528277d2aaSMarkus Armbruster 15349fbc723SVladimir Sementsov-Ogievskiy void error_append_hint(Error *const *errp, const char *fmt, ...) 15450b7b000SEric Blake { 15550b7b000SEric Blake va_list ap; 15650b7b000SEric Blake int saved_errno = errno; 15750b7b000SEric Blake Error *err; 15850b7b000SEric Blake 15950b7b000SEric Blake if (!errp) { 16050b7b000SEric Blake return; 16150b7b000SEric Blake } 16250b7b000SEric Blake err = *errp; 163f4d0064aSMarkus Armbruster assert(err && errp != &error_abort && errp != &error_fatal); 16450b7b000SEric Blake 16550b7b000SEric Blake if (!err->hint) { 16650b7b000SEric Blake err->hint = g_string_new(NULL); 16750b7b000SEric Blake } 16850b7b000SEric Blake va_start(ap, fmt); 16950b7b000SEric Blake g_string_append_vprintf(err->hint, fmt, ap); 17050b7b000SEric Blake va_end(ap); 17150b7b000SEric Blake 17250b7b000SEric Blake errno = saved_errno; 17350b7b000SEric Blake } 17450b7b000SEric Blake 17520840d4cSTomoki Sekiyama #ifdef _WIN32 17620840d4cSTomoki Sekiyama 1771e9b65bbSMarkus Armbruster void error_setg_win32_internal(Error **errp, 1781e9b65bbSMarkus Armbruster const char *src, int line, const char *func, 1791e9b65bbSMarkus Armbruster int win32_err, const char *fmt, ...) 18020840d4cSTomoki Sekiyama { 18120840d4cSTomoki Sekiyama va_list ap; 18220e2dec1SDaniel P. Berrange char *suffix = NULL; 18320840d4cSTomoki Sekiyama 18420840d4cSTomoki Sekiyama if (errp == NULL) { 18520840d4cSTomoki Sekiyama return; 18620840d4cSTomoki Sekiyama } 18720840d4cSTomoki Sekiyama 18820e2dec1SDaniel P. Berrange if (win32_err != 0) { 18920e2dec1SDaniel P. Berrange suffix = g_win32_error_message(win32_err); 19020e2dec1SDaniel P. Berrange } 19120e2dec1SDaniel P. Berrange 19220840d4cSTomoki Sekiyama va_start(ap, fmt); 19320e2dec1SDaniel P. Berrange error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, 19420e2dec1SDaniel P. Berrange fmt, ap, suffix); 19555237508SMarkus Armbruster va_end(ap); 19655237508SMarkus Armbruster 19720e2dec1SDaniel P. Berrange g_free(suffix); 19820840d4cSTomoki Sekiyama } 19920840d4cSTomoki Sekiyama 20020840d4cSTomoki Sekiyama #endif 20120840d4cSTomoki Sekiyama 202baacf047SPaolo Bonzini Error *error_copy(const Error *err) 203baacf047SPaolo Bonzini { 204baacf047SPaolo Bonzini Error *err_new; 205baacf047SPaolo Bonzini 206baacf047SPaolo Bonzini err_new = g_malloc0(sizeof(*err)); 207baacf047SPaolo Bonzini err_new->msg = g_strdup(err->msg); 208baacf047SPaolo Bonzini err_new->err_class = err->err_class; 20988e2ce29SEric Blake err_new->src = err->src; 21088e2ce29SEric Blake err_new->line = err->line; 21188e2ce29SEric Blake err_new->func = err->func; 21250b7b000SEric Blake if (err->hint) { 21350b7b000SEric Blake err_new->hint = g_string_new(err->hint->str); 21450b7b000SEric Blake } 215baacf047SPaolo Bonzini 216baacf047SPaolo Bonzini return err_new; 217baacf047SPaolo Bonzini } 218baacf047SPaolo Bonzini 219baacf047SPaolo Bonzini ErrorClass error_get_class(const Error *err) 220baacf047SPaolo Bonzini { 221baacf047SPaolo Bonzini return err->err_class; 222baacf047SPaolo Bonzini } 223baacf047SPaolo Bonzini 224d59ce6f3SDaniel P. Berrange const char *error_get_pretty(const Error *err) 225baacf047SPaolo Bonzini { 226baacf047SPaolo Bonzini return err->msg; 227baacf047SPaolo Bonzini } 228baacf047SPaolo Bonzini 2292ee2f1e4SMarkus Armbruster void error_report_err(Error *err) 2302ee2f1e4SMarkus Armbruster { 2312ee2f1e4SMarkus Armbruster error_report("%s", error_get_pretty(err)); 23250b7b000SEric Blake if (err->hint) { 2334c8b7c8bSMarkus Armbruster error_printf("%s", err->hint->str); 23450b7b000SEric Blake } 2352ee2f1e4SMarkus Armbruster error_free(err); 2362ee2f1e4SMarkus Armbruster } 2372ee2f1e4SMarkus Armbruster 238e43ead1dSAlistair Francis void warn_report_err(Error *err) 239e43ead1dSAlistair Francis { 240e43ead1dSAlistair Francis warn_report("%s", error_get_pretty(err)); 241e43ead1dSAlistair Francis if (err->hint) { 2424c8b7c8bSMarkus Armbruster error_printf("%s", err->hint->str); 243e43ead1dSAlistair Francis } 244e43ead1dSAlistair Francis error_free(err); 245e43ead1dSAlistair Francis } 246e43ead1dSAlistair Francis 2478277d2aaSMarkus Armbruster void error_reportf_err(Error *err, const char *fmt, ...) 2488277d2aaSMarkus Armbruster { 2498277d2aaSMarkus Armbruster va_list ap; 2508277d2aaSMarkus Armbruster 2518277d2aaSMarkus Armbruster va_start(ap, fmt); 2528277d2aaSMarkus Armbruster error_vprepend(&err, fmt, ap); 2538277d2aaSMarkus Armbruster va_end(ap); 2548277d2aaSMarkus Armbruster error_report_err(err); 2558277d2aaSMarkus Armbruster } 2568277d2aaSMarkus Armbruster 257e43ead1dSAlistair Francis 258e43ead1dSAlistair Francis void warn_reportf_err(Error *err, const char *fmt, ...) 259e43ead1dSAlistair Francis { 260e43ead1dSAlistair Francis va_list ap; 261e43ead1dSAlistair Francis 262e43ead1dSAlistair Francis va_start(ap, fmt); 263e43ead1dSAlistair Francis error_vprepend(&err, fmt, ap); 264e43ead1dSAlistair Francis va_end(ap); 265e43ead1dSAlistair Francis warn_report_err(err); 266e43ead1dSAlistair Francis } 267e43ead1dSAlistair Francis 268baacf047SPaolo Bonzini void error_free(Error *err) 269baacf047SPaolo Bonzini { 270baacf047SPaolo Bonzini if (err) { 271baacf047SPaolo Bonzini g_free(err->msg); 27250b7b000SEric Blake if (err->hint) { 27350b7b000SEric Blake g_string_free(err->hint, true); 27450b7b000SEric Blake } 275baacf047SPaolo Bonzini g_free(err); 276baacf047SPaolo Bonzini } 277baacf047SPaolo Bonzini } 278baacf047SPaolo Bonzini 279a12a5a1aSEric Blake void error_free_or_abort(Error **errp) 280a12a5a1aSEric Blake { 281a12a5a1aSEric Blake assert(errp && *errp); 282a12a5a1aSEric Blake error_free(*errp); 283a12a5a1aSEric Blake *errp = NULL; 284a12a5a1aSEric Blake } 285a12a5a1aSEric Blake 28664dfefedSMarkus Armbruster void error_propagate(Error **dst_errp, Error *local_err) 287baacf047SPaolo Bonzini { 288a29a37b9SMarkus Armbruster if (!local_err) { 289a29a37b9SMarkus Armbruster return; 290a29a37b9SMarkus Armbruster } 291*3ffef1a5SMarc-André Lureau error_handle(dst_errp, local_err); 292a29a37b9SMarkus Armbruster if (dst_errp && !*dst_errp) { 29364dfefedSMarkus Armbruster *dst_errp = local_err; 294a29a37b9SMarkus Armbruster } else { 295baacf047SPaolo Bonzini error_free(local_err); 296baacf047SPaolo Bonzini } 297baacf047SPaolo Bonzini } 2984b576648SMarkus Armbruster 2994b576648SMarkus Armbruster void error_propagate_prepend(Error **dst_errp, Error *err, 3004b576648SMarkus Armbruster const char *fmt, ...) 3014b576648SMarkus Armbruster { 3024b576648SMarkus Armbruster va_list ap; 3034b576648SMarkus Armbruster 3044b576648SMarkus Armbruster if (dst_errp && !*dst_errp) { 3054b576648SMarkus Armbruster va_start(ap, fmt); 3064b576648SMarkus Armbruster error_vprepend(&err, fmt, ap); 3074b576648SMarkus Armbruster va_end(ap); 3084b576648SMarkus Armbruster } /* else error is being ignored, don't bother with prepending */ 3094b576648SMarkus Armbruster error_propagate(dst_errp, err); 3104b576648SMarkus Armbruster } 311