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    va_start(ap, fmt);
 107    error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap,
 108               os_errno != 0 ? strerror(os_errno) : NULL);
 109    va_end(ap);
 110
 111    errno = saved_errno;
 112}
 113
 114void error_setg_file_open_internal(Error **errp,
 115                                   const char *src, int line, const char *func,
 116                                   int os_errno, const char *filename)
 117{
 118    error_setg_errno_internal(errp, src, line, func, os_errno,
 119                              "Could not open '%s'", filename);
 120}
 121
 122void error_vprepend(Error **errp, const char *fmt, va_list ap)
 123{
 124    GString *newmsg;
 125
 126    if (!errp) {
 127        return;
 128    }
 129
 130    newmsg = g_string_new(NULL);
 131    g_string_vprintf(newmsg, fmt, ap);
 132    g_string_append(newmsg, (*errp)->msg);
 133    g_free((*errp)->msg);
 134    (*errp)->msg = g_string_free(newmsg, 0);
 135}
 136
 137void error_prepend(Error **errp, const char *fmt, ...)
 138{
 139    va_list ap;
 140
 141    va_start(ap, fmt);
 142    error_vprepend(errp, fmt, ap);
 143    va_end(ap);
 144}
 145
 146void error_append_hint(Error **errp, const char *fmt, ...)
 147{
 148    va_list ap;
 149    int saved_errno = errno;
 150    Error *err;
 151
 152    if (!errp) {
 153        return;
 154    }
 155    err = *errp;
 156    assert(err && errp != &error_abort && errp != &error_fatal);
 157
 158    if (!err->hint) {
 159        err->hint = g_string_new(NULL);
 160    }
 161    va_start(ap, fmt);
 162    g_string_append_vprintf(err->hint, fmt, ap);
 163    va_end(ap);
 164
 165    errno = saved_errno;
 166}
 167
 168#ifdef _WIN32
 169
 170void error_setg_win32_internal(Error **errp,
 171                               const char *src, int line, const char *func,
 172                               int win32_err, const char *fmt, ...)
 173{
 174    va_list ap;
 175    char *suffix = NULL;
 176
 177    if (errp == NULL) {
 178        return;
 179    }
 180
 181    if (win32_err != 0) {
 182        suffix = g_win32_error_message(win32_err);
 183    }
 184
 185    va_start(ap, fmt);
 186    error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR,
 187               fmt, ap, suffix);
 188    va_end(ap);
 189
 190    g_free(suffix);
 191}
 192
 193#endif
 194
 195Error *error_copy(const Error *err)
 196{
 197    Error *err_new;
 198
 199    err_new = g_malloc0(sizeof(*err));
 200    err_new->msg = g_strdup(err->msg);
 201    err_new->err_class = err->err_class;
 202    err_new->src = err->src;
 203    err_new->line = err->line;
 204    err_new->func = err->func;
 205    if (err->hint) {
 206        err_new->hint = g_string_new(err->hint->str);
 207    }
 208
 209    return err_new;
 210}
 211
 212ErrorClass error_get_class(const Error *err)
 213{
 214    return err->err_class;
 215}
 216
 217const char *error_get_pretty(const Error *err)
 218{
 219    return err->msg;
 220}
 221
 222void error_report_err(Error *err)
 223{
 224    error_report("%s", error_get_pretty(err));
 225    if (err->hint) {
 226        error_printf_unless_qmp("%s", err->hint->str);
 227    }
 228    error_free(err);
 229}
 230
 231void warn_report_err(Error *err)
 232{
 233    warn_report("%s", error_get_pretty(err));
 234    if (err->hint) {
 235        error_printf_unless_qmp("%s", err->hint->str);
 236    }
 237    error_free(err);
 238}
 239
 240void error_reportf_err(Error *err, const char *fmt, ...)
 241{
 242    va_list ap;
 243
 244    va_start(ap, fmt);
 245    error_vprepend(&err, fmt, ap);
 246    va_end(ap);
 247    error_report_err(err);
 248}
 249
 250
 251void warn_reportf_err(Error *err, const char *fmt, ...)
 252{
 253    va_list ap;
 254
 255    va_start(ap, fmt);
 256    error_vprepend(&err, fmt, ap);
 257    va_end(ap);
 258    warn_report_err(err);
 259}
 260
 261void error_free(Error *err)
 262{
 263    if (err) {
 264        g_free(err->msg);
 265        if (err->hint) {
 266            g_string_free(err->hint, true);
 267        }
 268        g_free(err);
 269    }
 270}
 271
 272void error_free_or_abort(Error **errp)
 273{
 274    assert(errp && *errp);
 275    error_free(*errp);
 276    *errp = NULL;
 277}
 278
 279void error_propagate(Error **dst_errp, Error *local_err)
 280{
 281    if (!local_err) {
 282        return;
 283    }
 284    error_handle_fatal(dst_errp, local_err);
 285    if (dst_errp && !*dst_errp) {
 286        *dst_errp = local_err;
 287    } else {
 288        error_free(local_err);
 289    }
 290}
 291
 292void error_propagate_prepend(Error **dst_errp, Error *err,
 293                             const char *fmt, ...)
 294{
 295    va_list ap;
 296
 297    if (dst_errp && !*dst_errp) {
 298        va_start(ap, fmt);
 299        error_vprepend(&err, fmt, ap);
 300        va_end(ap);
 301    } /* else error is being ignored, don't bother with prepending */
 302    error_propagate(dst_errp, err);
 303}
 304