add qemu_error() + friends
authorGerd Hoffmann <kraxel@redhat.com>
Fri, 14 Aug 2009 08:36:06 +0000 (10:36 +0200)
committerAnthony Liguori <aliguori@us.ibm.com>
Fri, 28 Aug 2009 01:43:33 +0000 (20:43 -0500)
This patch adds some functions for error reporting to address the
problem that error messages should be routed to different destinations
depending on the context of the caller, i.e. monitor command errors
should go to the monitor, command line errors to stderr.

qemu_error() is a printf-like function to report errors.

qemu_errors_to_file() and qemu_errors_to_mon() switch the destination
for the error message to the specified file or monitor.  When setting a
new destination the old one will be kept.  One can switch back using
qemu_errors_to_previous().  i.e. it works like a stack.

main() calls qemu_errors_to_file(stderr), so errors go to stderr by
default.  monitor callbacks are wrapped into qemu_errors_to_mon() +
qemu_errors_to_previous(), so any errors triggered by monitor commands
will go to the monitor.

Each thread has its own error message destination.  qemu-kvm probably
should add a qemu_errors_to_file(stderr) call to the i/o-thread
initialization code.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
monitor.c
sysemu.h
vl.c

index ca1731eddc2ad422eb2cea3eb3e4a00a2bae60d5..2559a625979c917e6b8be29288948e1cace9881a 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -2792,6 +2792,7 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline)
         goto fail;
     }
 
+    qemu_errors_to_mon(mon);
     switch(nb_args) {
     case 0:
         handler_0 = cmd->handler;
@@ -2843,8 +2844,10 @@ static void monitor_handle_command(Monitor *mon, const char *cmdline)
         break;
     default:
         monitor_printf(mon, "unsupported number of arguments: %d\n", nb_args);
-        goto fail;
+        break;
     }
+    qemu_errors_to_previous();
+
  fail:
     for(i = 0; i < MAX_ARGS; i++)
         qemu_free(str_allocated[i]);
@@ -3212,3 +3215,69 @@ void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
     if (err && completion_cb)
         completion_cb(opaque, err);
 }
+
+typedef struct QemuErrorSink QemuErrorSink;
+struct QemuErrorSink {
+    enum {
+        ERR_SINK_FILE,
+        ERR_SINK_MONITOR,
+    } dest;
+    union {
+        FILE    *fp;
+        Monitor *mon;
+    };
+    QemuErrorSink *previous;
+};
+
+static __thread QemuErrorSink *qemu_error_sink;
+
+void qemu_errors_to_file(FILE *fp)
+{
+    QemuErrorSink *sink;
+
+    sink = qemu_mallocz(sizeof(*sink));
+    sink->dest = ERR_SINK_FILE;
+    sink->fp = fp;
+    sink->previous = qemu_error_sink;
+    qemu_error_sink = sink;
+}
+
+void qemu_errors_to_mon(Monitor *mon)
+{
+    QemuErrorSink *sink;
+
+    sink = qemu_mallocz(sizeof(*sink));
+    sink->dest = ERR_SINK_MONITOR;
+    sink->mon = mon;
+    sink->previous = qemu_error_sink;
+    qemu_error_sink = sink;
+}
+
+void qemu_errors_to_previous(void)
+{
+    QemuErrorSink *sink;
+
+    assert(qemu_error_sink != NULL);
+    sink = qemu_error_sink;
+    qemu_error_sink = sink->previous;
+    qemu_free(sink);
+}
+
+void qemu_error(const char *fmt, ...)
+{
+    va_list args;
+
+    assert(qemu_error_sink != NULL);
+    switch (qemu_error_sink->dest) {
+    case ERR_SINK_FILE:
+        va_start(args, fmt);
+        vfprintf(qemu_error_sink->fp, fmt, args);
+        va_end(args);
+        break;
+    case ERR_SINK_MONITOR:
+        va_start(args, fmt);
+        monitor_vprintf(qemu_error_sink->mon, fmt, args);
+        va_end(args);
+        break;
+    }
+}
index 18fa0727c16e932f6aee5c2a5c01dd58e9d3c58b..d42fe9dc7e37a6e3f23bdbb3a0a0114e858abe8e 100644 (file)
--- a/sysemu.h
+++ b/sysemu.h
@@ -65,6 +65,11 @@ int qemu_savevm_state_complete(QEMUFile *f);
 int qemu_savevm_state(QEMUFile *f);
 int qemu_loadvm_state(QEMUFile *f);
 
+void qemu_errors_to_file(FILE *fp);
+void qemu_errors_to_mon(Monitor *mon);
+void qemu_errors_to_previous(void);
+void qemu_error(const char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
+
 #ifdef _WIN32
 /* Polling handling */
 
diff --git a/vl.c b/vl.c
index 10d0c5273dcb856e8a56f9da3901097afdfb2812..cd0f907b31447ff6697d4ba60e7b11bf589d590d 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -4878,6 +4878,7 @@ int main(int argc, char **argv, char **envp)
     CPUState *env;
     int show_vnc_port = 0;
 
+    qemu_errors_to_file(stderr);
     qemu_cache_utils_init(envp);
 
     LIST_INIT (&vm_change_state_head);