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