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 */
 198static void vreport(report_type type, const char *fmt, va_list ap)
 199{
 200    GTimeVal tv;
 201    gchar *timestr;
 202
 203    if (enable_timestamp_msg && !cur_mon) {
 204        g_get_current_time(&tv);
 205        timestr = g_time_val_to_iso8601(&tv);
 206        error_printf("%s ", timestr);
 207        g_free(timestr);
 208    }
 209
 210    print_loc();
 211
 212    switch (type) {
 213    case REPORT_TYPE_ERROR:
 214        break;
 215    case REPORT_TYPE_WARNING:
 216        error_printf("warning: ");
 217        break;
 218    case REPORT_TYPE_INFO:
 219        error_printf("info: ");
 220        break;
 221    }
 222
 223    error_vprintf(fmt, ap);
 224    error_printf("\n");
 225}
 226
 227/*
 228 * Print an error message to current monitor if we have one, else to stderr.
 229 * Format arguments like vsprintf().  The resulting message should be
 230 * a single phrase, with no newline or trailing punctuation.
 231 * Prepend the current location and append a newline.
 232 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 233 */
 234void error_vreport(const char *fmt, va_list ap)
 235{
 236    vreport(REPORT_TYPE_ERROR, fmt, ap);
 237}
 238
 239/*
 240 * Print a warning message to current monitor if we have one, else to stderr.
 241 * Format arguments like vsprintf().  The resulting message should be
 242 * a single phrase, with no newline or trailing punctuation.
 243 * Prepend the current location and append a newline.
 244 */
 245void warn_vreport(const char *fmt, va_list ap)
 246{
 247    vreport(REPORT_TYPE_WARNING, fmt, ap);
 248}
 249
 250/*
 251 * Print an information message to current monitor if we have one, else to
 252 * stderr.
 253 * Format arguments like vsprintf().  The resulting message should be
 254 * a single phrase, with no newline or trailing punctuation.
 255 * Prepend the current location and append a newline.
 256 */
 257void info_vreport(const char *fmt, va_list ap)
 258{
 259    vreport(REPORT_TYPE_INFO, fmt, ap);
 260}
 261
 262/*
 263 * Print an error message to current monitor if we have one, else to stderr.
 264 * Format arguments like sprintf().  The resulting message should be
 265 * a single phrase, with no newline or trailing punctuation.
 266 * Prepend the current location and append a newline.
 267 * It's wrong to call this in a QMP monitor.  Use error_setg() there.
 268 */
 269void error_report(const char *fmt, ...)
 270{
 271    va_list ap;
 272
 273    va_start(ap, fmt);
 274    vreport(REPORT_TYPE_ERROR, fmt, ap);
 275    va_end(ap);
 276}
 277
 278/*
 279 * Print a warning message to current monitor if we have one, else to stderr.
 280 * Format arguments like sprintf(). The resulting message should be a
 281 * single phrase, with no newline or trailing punctuation.
 282 * Prepend the current location and append a newline.
 283 */
 284void warn_report(const char *fmt, ...)
 285{
 286    va_list ap;
 287
 288    va_start(ap, fmt);
 289    vreport(REPORT_TYPE_WARNING, fmt, ap);
 290    va_end(ap);
 291}
 292
 293/*
 294 * Print an information message to current monitor if we have one, else to
 295 * stderr.
 296 * Format arguments like sprintf(). The resulting message should be a
 297 * single phrase, with no newline or trailing punctuation.
 298 * Prepend the current location and append a newline.
 299 */
 300void info_report(const char *fmt, ...)
 301{
 302    va_list ap;
 303
 304    va_start(ap, fmt);
 305    vreport(REPORT_TYPE_INFO, fmt, ap);
 306    va_end(ap);
 307}
 308
 309/*
 310 * Like error_report(), except print just once.
 311 * If *printed is false, print the message, and flip *printed to true.
 312 * Return whether the message was printed.
 313 */
 314bool error_report_once_cond(bool *printed, const char *fmt, ...)
 315{
 316    va_list ap;
 317
 318    assert(printed);
 319    if (*printed) {
 320        return false;
 321    }
 322    *printed = true;
 323    va_start(ap, fmt);
 324    vreport(REPORT_TYPE_ERROR, fmt, ap);
 325    va_end(ap);
 326    return true;
 327}
 328
 329/*
 330 * Like warn_report(), except print just once.
 331 * If *printed is false, print the message, and flip *printed to true.
 332 * Return whether the message was printed.
 333 */
 334bool warn_report_once_cond(bool *printed, const char *fmt, ...)
 335{
 336    va_list ap;
 337
 338    assert(printed);
 339    if (*printed) {
 340        return false;
 341    }
 342    *printed = true;
 343    va_start(ap, fmt);
 344    vreport(REPORT_TYPE_WARNING, fmt, ap);
 345    va_end(ap);
 346    return true;
 347}
 348