qemu/util/qemu-error.c
<<
>>
Prefs
   1/*
   2 * Error reporting
   3 *
   4 * Copyright (C) 2010 Red Hat Inc.
   5 *
   6 * Authors:
   7 *  Markus Armbruster <armbru@redhat.com>,
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "monitor/monitor.h"
  15#include "qemu/error-report.h"
  16
  17/*
  18 * @report_type is the type of message: error, warning or
  19 * informational.
  20 */
  21typedef enum {
  22    REPORT_TYPE_ERROR,
  23    REPORT_TYPE_WARNING,
  24    REPORT_TYPE_INFO,
  25} report_type;
  26
  27void error_printf(const char *fmt, ...)
  28{
  29    va_list ap;
  30
  31    va_start(ap, fmt);
  32    error_vprintf(fmt, ap);
  33    va_end(ap);
  34}
  35
  36void error_printf_unless_qmp(const char *fmt, ...)
  37{
  38    va_list ap;
  39
  40    va_start(ap, fmt);
  41    error_vprintf_unless_qmp(fmt, ap);
  42    va_end(ap);
  43}
  44
  45static Location std_loc = {
  46    .kind = LOC_NONE
  47};
  48static Location *cur_loc = &std_loc;
  49
  50/*
  51 * Push location saved in LOC onto the location stack, return it.
  52 * The top of that stack is the current location.
  53 * Needs a matching loc_pop().
  54 */
  55Location *loc_push_restore(Location *loc)
  56{
  57    assert(!loc->prev);
  58    loc->prev = cur_loc;
  59    cur_loc = loc;
  60    return loc;
  61}
  62
  63/*
  64 * Initialize *LOC to "nowhere", push it onto the location stack.
  65 * The top of that stack is the current location.
  66 * Needs a matching loc_pop().
  67 * Return LOC.
  68 */
  69Location *loc_push_none(Location *loc)
  70{
  71    loc->kind = LOC_NONE;
  72    loc->prev = NULL;
  73    return loc_push_restore(loc);
  74}
  75
  76/*
  77 * Pop the location stack.
  78 * LOC must be the current location, i.e. the top of the stack.
  79 */
  80Location *loc_pop(Location *loc)
  81{
  82    assert(cur_loc == loc && loc->prev);
  83    cur_loc = loc->prev;
  84    loc->prev = NULL;
  85    return loc;
  86}
  87
  88/*
  89 * Save the current location in LOC, return LOC.
  90 */
  91Location *loc_save(Location *loc)
  92{
  93    *loc = *cur_loc;
  94    loc->prev = NULL;
  95    return loc;
  96}
  97
  98/*
  99 * Change the current location to the one saved in LOC.
 100 */
 101void loc_restore(Location *loc)
 102{
 103    Location *prev = cur_loc->prev;
 104    assert(!loc->prev);
 105    *cur_loc = *loc;
 106    cur_loc->prev = prev;
 107}
 108
 109/*
 110 * Change the current location to "nowhere in particular".
 111 */
 112void loc_set_none(void)
 113{
 114    cur_loc->kind = LOC_NONE;
 115}
 116
 117/*
 118 * Change the current location to argument ARGV[IDX..IDX+CNT-1].
 119 */
 120void loc_set_cmdline(char **argv, int idx, int cnt)
 121{
 122    cur_loc->kind = LOC_CMDLINE;
 123    cur_loc->num = cnt;
 124    cur_loc->ptr = argv + idx;
 125}
 126
 127/*
 128 * Change the current location to file FNAME, line LNO.
 129 */
 130void loc_set_file(const char *fname, int lno)
 131{
 132    assert (fname || cur_loc->kind == LOC_FILE);
 133    cur_loc->kind = LOC_FILE;
 134    cur_loc->num = lno;
 135    if (fname) {
 136        cur_loc->ptr = fname;
 137    }
 138}
 139
 140static const char *progname;
 141
 142/*
 143 * Set the program name for error_print_loc().
 144 */
 145void error_set_progname(const char *argv0)
 146{
 147    const char *p = strrchr(argv0, '/');
 148    progname = p ? p + 1 : argv0;
 149}
 150
 151const char *error_get_progname(void)
 152{
 153    return progname;
 154}
 155
 156/*
 157 * Print current location to current monitor if we have one, else to stderr.
 158 */
 159static void print_loc(void)
 160{
 161    const char *sep = "";
 162    int i;
 163    const char *const *argp;
 164
 165    if (!cur_mon && progname) {
 166        fprintf(stderr, "%s:", progname);
 167        sep = " ";
 168    }
 169    switch (cur_loc->kind) {
 170    case LOC_CMDLINE:
 171        argp = cur_loc->ptr;
 172        for (i = 0; i < cur_loc->num; i++) {
 173            error_printf("%s%s", sep, argp[i]);
 174            sep = " ";
 175        }
 176        error_printf(": ");
 177        break;
 178    case LOC_FILE:
 179        error_printf("%s:", (const char *)cur_loc->ptr);
 180        if (cur_loc->num) {
 181            error_printf("%d:", cur_loc->num);
 182        }
 183        error_printf(" ");
 184        break;
 185    default:
 186        error_printf("%s", sep);
 187    }
 188}
 189
 190bool enable_timestamp_msg;
 191/*
 192 * Print a message to current monitor if we have one, else to stderr.
 193 * @report_type is the type of message: error, warning or informational.
 194 * Format arguments like vsprintf().  The resulting message should be
 195 * a single phrase, with no newline or trailing punctuation.
 196 * Prepend the current location and append a newline.
 197 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 198 */
 199static void vreport(report_type type, const char *fmt, va_list ap)
 200{
 201    GTimeVal tv;
 202    gchar *timestr;
 203
 204    if (enable_timestamp_msg && !cur_mon) {
 205        g_get_current_time(&tv);
 206        timestr = g_time_val_to_iso8601(&tv);
 207        error_printf("%s ", timestr);
 208        g_free(timestr);
 209    }
 210
 211    print_loc();
 212
 213    switch (type) {
 214    case REPORT_TYPE_ERROR:
 215        break;
 216    case REPORT_TYPE_WARNING:
 217        error_printf("warning: ");
 218        break;
 219    case REPORT_TYPE_INFO:
 220        error_printf("info: ");
 221        break;
 222    }
 223
 224    error_vprintf(fmt, ap);
 225    error_printf("\n");
 226}
 227
 228/*
 229 * Print an error message to current monitor if we have one, else to stderr.
 230 * Format arguments like vsprintf().  The resulting message should be
 231 * a single phrase, with no newline or trailing punctuation.
 232 * Prepend the current location and append a newline.
 233 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 234 */
 235void error_vreport(const char *fmt, va_list ap)
 236{
 237    vreport(REPORT_TYPE_ERROR, fmt, ap);
 238}
 239
 240/*
 241 * Print a warning message to current monitor if we have one, else to stderr.
 242 * Format arguments like vsprintf().  The resulting message should be
 243 * a single phrase, with no newline or trailing punctuation.
 244 * Prepend the current location and append a newline.
 245 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 246 */
 247void warn_vreport(const char *fmt, va_list ap)
 248{
 249    vreport(REPORT_TYPE_WARNING, fmt, ap);
 250}
 251
 252/*
 253 * Print an information message to current monitor if we have one, else to
 254 * stderr.
 255 * Format arguments like vsprintf().  The resulting message should be
 256 * a single phrase, with no newline or trailing punctuation.
 257 * Prepend the current location and append a newline.
 258 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 259 */
 260void info_vreport(const char *fmt, va_list ap)
 261{
 262    vreport(REPORT_TYPE_INFO, fmt, ap);
 263}
 264
 265/*
 266 * Print an error message to current monitor if we have one, else to stderr.
 267 * Format arguments like sprintf().  The resulting message should be
 268 * a single phrase, with no newline or trailing punctuation.
 269 * Prepend the current location and append a newline.
 270 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 271 */
 272void error_report(const char *fmt, ...)
 273{
 274    va_list ap;
 275
 276    va_start(ap, fmt);
 277    vreport(REPORT_TYPE_ERROR, fmt, ap);
 278    va_end(ap);
 279}
 280
 281/*
 282 * Print a warning message to current monitor if we have one, else to stderr.
 283 * Format arguments like sprintf(). The resulting message should be a
 284 * single phrase, with no newline or trailing punctuation.
 285 * Prepend the current location and append a newline.
 286 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 287 */
 288void warn_report(const char *fmt, ...)
 289{
 290    va_list ap;
 291
 292    va_start(ap, fmt);
 293    vreport(REPORT_TYPE_WARNING, fmt, ap);
 294    va_end(ap);
 295}
 296
 297/*
 298 * Print an information message to current monitor if we have one, else to
 299 * stderr.
 300 * Format arguments like sprintf(). The resulting message should be a
 301 * single phrase, with no newline or trailing punctuation.
 302 * Prepend the current location and append a newline.
 303 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 304 */
 305void info_report(const char *fmt, ...)
 306{
 307    va_list ap;
 308
 309    va_start(ap, fmt);
 310    vreport(REPORT_TYPE_INFO, fmt, ap);
 311    va_end(ap);
 312}
 313