qemu-error.c (10081B)
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 27/* Prepend timestamp to messages */ 28bool message_with_timestamp; 29bool error_with_guestname; 30const char *error_guest_name; 31 32int error_printf(const char *fmt, ...) 33{ 34 va_list ap; 35 int ret; 36 37 va_start(ap, fmt); 38 ret = error_vprintf(fmt, ap); 39 va_end(ap); 40 return ret; 41} 42 43int error_printf_unless_qmp(const char *fmt, ...) 44{ 45 va_list ap; 46 int ret; 47 48 va_start(ap, fmt); 49 ret = error_vprintf_unless_qmp(fmt, ap); 50 va_end(ap); 51 return ret; 52} 53 54static Location std_loc = { 55 .kind = LOC_NONE 56}; 57static Location *cur_loc = &std_loc; 58 59/* 60 * Push location saved in LOC onto the location stack, return it. 61 * The top of that stack is the current location. 62 * Needs a matching loc_pop(). 63 */ 64Location *loc_push_restore(Location *loc) 65{ 66 assert(!loc->prev); 67 loc->prev = cur_loc; 68 cur_loc = loc; 69 return loc; 70} 71 72/* 73 * Initialize *LOC to "nowhere", push it onto the location stack. 74 * The top of that stack is the current location. 75 * Needs a matching loc_pop(). 76 * Return LOC. 77 */ 78Location *loc_push_none(Location *loc) 79{ 80 loc->kind = LOC_NONE; 81 loc->prev = NULL; 82 return loc_push_restore(loc); 83} 84 85/* 86 * Pop the location stack. 87 * LOC must be the current location, i.e. the top of the stack. 88 */ 89Location *loc_pop(Location *loc) 90{ 91 assert(cur_loc == loc && loc->prev); 92 cur_loc = loc->prev; 93 loc->prev = NULL; 94 return loc; 95} 96 97/* 98 * Save the current location in LOC, return LOC. 99 */ 100Location *loc_save(Location *loc) 101{ 102 *loc = *cur_loc; 103 loc->prev = NULL; 104 return loc; 105} 106 107/* 108 * Change the current location to the one saved in LOC. 109 */ 110void loc_restore(Location *loc) 111{ 112 Location *prev = cur_loc->prev; 113 assert(!loc->prev); 114 *cur_loc = *loc; 115 cur_loc->prev = prev; 116} 117 118/* 119 * Change the current location to "nowhere in particular". 120 */ 121void loc_set_none(void) 122{ 123 cur_loc->kind = LOC_NONE; 124} 125 126/* 127 * Change the current location to argument ARGV[IDX..IDX+CNT-1]. 128 */ 129void loc_set_cmdline(char **argv, int idx, int cnt) 130{ 131 cur_loc->kind = LOC_CMDLINE; 132 cur_loc->num = cnt; 133 cur_loc->ptr = argv + idx; 134} 135 136/* 137 * Change the current location to file FNAME, line LNO. 138 */ 139void loc_set_file(const char *fname, int lno) 140{ 141 assert (fname || cur_loc->kind == LOC_FILE); 142 cur_loc->kind = LOC_FILE; 143 cur_loc->num = lno; 144 if (fname) { 145 cur_loc->ptr = fname; 146 } 147} 148 149static const char *progname; 150 151/* 152 * Set the program name for error_print_loc(). 153 */ 154static void error_set_progname(const char *argv0) 155{ 156 const char *p = strrchr(argv0, '/'); 157 progname = p ? p + 1 : argv0; 158} 159 160const char *error_get_progname(void) 161{ 162 return progname; 163} 164 165/* 166 * Print current location to current monitor if we have one, else to stderr. 167 */ 168static void print_loc(void) 169{ 170 const char *sep = ""; 171 int i; 172 const char *const *argp; 173 174 if (!monitor_cur() && progname) { 175 fprintf(stderr, "%s:", progname); 176 sep = " "; 177 } 178 switch (cur_loc->kind) { 179 case LOC_CMDLINE: 180 argp = cur_loc->ptr; 181 for (i = 0; i < cur_loc->num; i++) { 182 error_printf("%s%s", sep, argp[i]); 183 sep = " "; 184 } 185 error_printf(": "); 186 break; 187 case LOC_FILE: 188 error_printf("%s:", (const char *)cur_loc->ptr); 189 if (cur_loc->num) { 190 error_printf("%d:", cur_loc->num); 191 } 192 error_printf(" "); 193 break; 194 default: 195 error_printf("%s", sep); 196 } 197} 198 199/* 200 * Print a message to current monitor if we have one, else to stderr. 201 * @report_type is the type of message: error, warning or informational. 202 * Format arguments like vsprintf(). The resulting message should be 203 * a single phrase, with no newline or trailing punctuation. 204 * Prepend the current location and append a newline. 205 */ 206static void vreport(report_type type, const char *fmt, va_list ap) 207{ 208 GTimeVal tv; 209 gchar *timestr; 210 211 if (message_with_timestamp && !monitor_cur()) { 212 g_get_current_time(&tv); 213 timestr = g_time_val_to_iso8601(&tv); 214 error_printf("%s ", timestr); 215 g_free(timestr); 216 } 217 218 /* Only prepend guest name if -msg guest-name and -name guest=... are set */ 219 if (error_with_guestname && error_guest_name && !monitor_cur()) { 220 error_printf("%s ", error_guest_name); 221 } 222 223 print_loc(); 224 225 switch (type) { 226 case REPORT_TYPE_ERROR: 227 break; 228 case REPORT_TYPE_WARNING: 229 error_printf("warning: "); 230 break; 231 case REPORT_TYPE_INFO: 232 error_printf("info: "); 233 break; 234 } 235 236 error_vprintf(fmt, ap); 237 error_printf("\n"); 238} 239 240/* 241 * Print an error 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 error_vreport(const char *fmt, va_list ap) 248{ 249 vreport(REPORT_TYPE_ERROR, fmt, ap); 250} 251 252/* 253 * Print a warning message to current monitor if we have one, else to stderr. 254 * Format arguments like vsprintf(). The resulting message should be 255 * a single phrase, with no newline or trailing punctuation. 256 * Prepend the current location and append a newline. 257 */ 258void warn_vreport(const char *fmt, va_list ap) 259{ 260 vreport(REPORT_TYPE_WARNING, fmt, ap); 261} 262 263/* 264 * Print an information message to current monitor if we have one, else to 265 * stderr. 266 * Format arguments like vsprintf(). The resulting message should be 267 * a single phrase, with no newline or trailing punctuation. 268 * Prepend the current location and append a newline. 269 */ 270void info_vreport(const char *fmt, va_list ap) 271{ 272 vreport(REPORT_TYPE_INFO, fmt, ap); 273} 274 275/* 276 * Print an error message to current monitor if we have one, else to stderr. 277 * Format arguments like sprintf(). The resulting message should be 278 * a single phrase, with no newline or trailing punctuation. 279 * Prepend the current location and append a newline. 280 * It's wrong to call this in a QMP monitor. Use error_setg() there. 281 */ 282void error_report(const char *fmt, ...) 283{ 284 va_list ap; 285 286 va_start(ap, fmt); 287 vreport(REPORT_TYPE_ERROR, fmt, ap); 288 va_end(ap); 289} 290 291/* 292 * Print a warning message to current monitor if we have one, else to stderr. 293 * Format arguments like sprintf(). The resulting message should be a 294 * single phrase, with no newline or trailing punctuation. 295 * Prepend the current location and append a newline. 296 */ 297void warn_report(const char *fmt, ...) 298{ 299 va_list ap; 300 301 va_start(ap, fmt); 302 vreport(REPORT_TYPE_WARNING, fmt, ap); 303 va_end(ap); 304} 305 306/* 307 * Print an information message to current monitor if we have one, else to 308 * stderr. 309 * Format arguments like sprintf(). The resulting message should be a 310 * single phrase, with no newline or trailing punctuation. 311 * Prepend the current location and append a newline. 312 */ 313void info_report(const char *fmt, ...) 314{ 315 va_list ap; 316 317 va_start(ap, fmt); 318 vreport(REPORT_TYPE_INFO, fmt, ap); 319 va_end(ap); 320} 321 322/* 323 * Like error_report(), except print just once. 324 * If *printed is false, print the message, and flip *printed to true. 325 * Return whether the message was printed. 326 */ 327bool error_report_once_cond(bool *printed, const char *fmt, ...) 328{ 329 va_list ap; 330 331 assert(printed); 332 if (*printed) { 333 return false; 334 } 335 *printed = true; 336 va_start(ap, fmt); 337 vreport(REPORT_TYPE_ERROR, fmt, ap); 338 va_end(ap); 339 return true; 340} 341 342/* 343 * Like warn_report(), except print just once. 344 * If *printed is false, print the message, and flip *printed to true. 345 * Return whether the message was printed. 346 */ 347bool warn_report_once_cond(bool *printed, const char *fmt, ...) 348{ 349 va_list ap; 350 351 assert(printed); 352 if (*printed) { 353 return false; 354 } 355 *printed = true; 356 va_start(ap, fmt); 357 vreport(REPORT_TYPE_WARNING, fmt, ap); 358 va_end(ap); 359 return true; 360} 361 362static char *qemu_glog_domains; 363 364static void qemu_log_func(const gchar *log_domain, 365 GLogLevelFlags log_level, 366 const gchar *message, 367 gpointer user_data) 368{ 369 switch (log_level & G_LOG_LEVEL_MASK) { 370 case G_LOG_LEVEL_DEBUG: 371 case G_LOG_LEVEL_INFO: 372 /* 373 * Use same G_MESSAGES_DEBUG logic as glib to enable/disable debug 374 * messages 375 */ 376 if (qemu_glog_domains == NULL) { 377 break; 378 } 379 if (strcmp(qemu_glog_domains, "all") != 0 && 380 (log_domain == NULL || !strstr(qemu_glog_domains, log_domain))) { 381 break; 382 } 383 /* Fall through */ 384 case G_LOG_LEVEL_MESSAGE: 385 info_report("%s%s%s", 386 log_domain ?: "", log_domain ? ": " : "", message); 387 388 break; 389 case G_LOG_LEVEL_WARNING: 390 warn_report("%s%s%s", 391 log_domain ?: "", log_domain ? ": " : "", message); 392 break; 393 case G_LOG_LEVEL_CRITICAL: 394 case G_LOG_LEVEL_ERROR: 395 error_report("%s%s%s", 396 log_domain ?: "", log_domain ? ": " : "", message); 397 break; 398 } 399} 400 401void error_init(const char *argv0) 402{ 403 /* Set the program name for error_print_loc(). */ 404 error_set_progname(argv0); 405 406 /* 407 * This sets up glib logging so libraries using it also print their logs 408 * through error_report(), warn_report(), info_report(). 409 */ 410 g_log_set_default_handler(qemu_log_func, NULL); 411 g_warn_if_fail(qemu_glog_domains == NULL); 412 qemu_glog_domains = g_strdup(g_getenv("G_MESSAGES_DEBUG")); 413}