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