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