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    (*errp)->msg = g_string_free(newmsg, 0);
 138}
 139
 140void error_prepend(Error **errp, const char *fmt, ...)
 141{
 142    va_list ap;
 143
 144    va_start(ap, fmt);
 145    error_vprepend(errp, fmt, ap);
 146    va_end(ap);
 147}
 148
 149void error_append_hint(Error **errp, const char *fmt, ...)
 150{
 151    va_list ap;
 152    int saved_errno = errno;
 153    Error *err;
 154
 155    if (!errp) {
 156        return;
 157    }
 158    err = *errp;
 159    assert(err && errp != &error_abort && errp != &error_fatal);
 160
 161    if (!err->hint) {
 162        err->hint = g_string_new(NULL);
 163    }
 164    va_start(ap, fmt);
 165    g_string_append_vprintf(err->hint, fmt, ap);
 166    va_end(ap);
 167
 168    errno = saved_errno;
 169}
 170
 171#ifdef _WIN32
 172
 173void error_setg_win32_internal(Error **errp,
 174                               const char *src, int line, const char *func,
 175                               int win32_err, const char *fmt, ...)
 176{
 177    va_list ap;
 178    char *suffix = NULL;
 179
 180    if (errp == NULL) {
 181        return;
 182    }
 183
 184    if (win32_err != 0) {
 185        suffix = g_win32_error_message(win32_err);
 186    }
 187
 188    va_start(ap, fmt);
 189    error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR,
 190               fmt, ap, suffix);
 191    va_end(ap);
 192
 193    g_free(suffix);
 194}
 195
 196#endif
 197
 198Error *error_copy(const Error *err)
 199{
 200    Error *err_new;
 201
 202    err_new = g_malloc0(sizeof(*err));
 203    err_new->msg = g_strdup(err->msg);
 204    err_new->err_class = err->err_class;
 205    err_new->src = err->src;
 206    err_new->line = err->line;
 207    err_new->func = err->func;
 208    if (err->hint) {
 209        err_new->hint = g_string_new(err->hint->str);
 210    }
 211
 212    return err_new;
 213}
 214
 215ErrorClass error_get_class(const Error *err)
 216{
 217    return err->err_class;
 218}
 219
 220const char *error_get_pretty(Error *err)
 221{
 222    return err->msg;
 223}
 224
 225void error_report_err(Error *err)
 226{
 227    error_report("%s", error_get_pretty(err));
 228    if (err->hint) {
 229        error_printf_unless_qmp("%s", err->hint->str);
 230    }
 231    error_free(err);
 232}
 233
 234void error_reportf_err(Error *err, const char *fmt, ...)
 235{
 236    va_list ap;
 237
 238    va_start(ap, fmt);
 239    error_vprepend(&err, fmt, ap);
 240    va_end(ap);
 241    error_report_err(err);
 242}
 243
 244void error_free(Error *err)
 245{
 246    if (err) {
 247        g_free(err->msg);
 248        if (err->hint) {
 249            g_string_free(err->hint, true);
 250        }
 251        g_free(err);
 252    }
 253}
 254
 255void error_free_or_abort(Error **errp)
 256{
 257    assert(errp && *errp);
 258    error_free(*errp);
 259    *errp = NULL;
 260}
 261
 262void error_propagate(Error **dst_errp, Error *local_err)
 263{
 264    if (!local_err) {
 265        return;
 266    }
 267    error_handle_fatal(dst_errp, local_err);
 268    if (dst_errp && !*dst_errp) {
 269        *dst_errp = local_err;
 270    } else {
 271        error_free(local_err);
 272    }
 273}
 274