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