summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--include/qapi/error.h31
-rw-r--r--util/error.c33
2 files changed, 62 insertions, 2 deletions
diff --git a/include/qapi/error.h b/include/qapi/error.h
index b18a608c6d..45d6c72dee 100644
--- a/include/qapi/error.h
+++ b/include/qapi/error.h
@@ -31,6 +31,9 @@
  *     error_report_err(err);
  * This frees the error object.
  *
+ * Report an error to stderr with additional text prepended:
+ *     error_reportf_err(err, "Could not frobnicate '%s': ", name);
+ *
  * Report an error somewhere else:
  *     const char *msg = error_get_pretty(err);
  *     do with msg what needs to be done...
@@ -48,6 +51,10 @@
  *     error_propagate(errp, err);
  * where Error **errp is a parameter, by convention the last one.
  *
+ * Pass an existing error to the caller with the message modified:
+ *     error_propagate(errp, err);
+ *     error_prepend(errp, "Could not frobnicate '%s': ", name);
+ *
  * Create a new error and pass it to the caller:
  *     error_setg(errp, "situation normal, all fouled up");
  *
@@ -108,9 +115,10 @@
 #ifndef ERROR_H
 #define ERROR_H
 
+#include <stdarg.h>
+#include <stdbool.h>
 #include "qemu/compiler.h"
 #include "qapi-types.h"
-#include <stdbool.h>
 
 /*
  * Opaque error object.
@@ -208,7 +216,20 @@ void error_setg_win32_internal(Error **errp,
  */
 void error_propagate(Error **dst_errp, Error *local_err);
 
-/**
+/*
+ * Prepend some text to @errp's human-readable error message.
+ * The text is made by formatting @fmt, @ap like vprintf().
+ */
+void error_vprepend(Error **errp, const char *fmt, va_list ap);
+
+/*
+ * Prepend some text to @errp's human-readable error message.
+ * The text is made by formatting @fmt, ... like printf().
+ */
+void error_prepend(Error **errp, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
+/*
  * Append a printf-style human-readable explanation to an existing error.
  * @errp may be NULL, but not &error_fatal or &error_abort.
  * Trivially the case if you call it only after error_setg() or
@@ -251,6 +272,12 @@ void error_free_or_abort(Error **errp);
 void error_report_err(Error *err);
 
 /*
+ * Convenience function to error_prepend(), error_report() and free @err.
+ */
+void error_reportf_err(Error *err, const char *fmt, ...)
+    GCC_FMT_ATTR(2, 3);
+
+/*
  * Just like error_setg(), except you get to specify the error class.
  * Note: use of error classes other than ERROR_CLASS_GENERIC_ERROR is
  * strongly discouraged.
diff --git a/util/error.c b/util/error.c
index ebfb74b02e..57303fd05c 100644
--- a/util/error.c
+++ b/util/error.c
@@ -122,6 +122,29 @@ void error_setg_file_open_internal(Error **errp,
                               "Could not open '%s'", filename);
 }
 
+void error_vprepend(Error **errp, const char *fmt, va_list ap)
+{
+    GString *newmsg;
+
+    if (!errp) {
+        return;
+    }
+
+    newmsg = g_string_new(NULL);
+    g_string_vprintf(newmsg, fmt, ap);
+    g_string_append(newmsg, (*errp)->msg);
+    (*errp)->msg = g_string_free(newmsg, 0);
+}
+
+void error_prepend(Error **errp, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    error_vprepend(errp, fmt, ap);
+    va_end(ap);
+}
+
 void error_append_hint(Error **errp, const char *fmt, ...)
 {
     va_list ap;
@@ -209,6 +232,16 @@ void error_report_err(Error *err)
     error_free(err);
 }
 
+void error_reportf_err(Error *err, const char *fmt, ...)
+{
+    va_list ap;
+
+    va_start(ap, fmt);
+    error_vprepend(&err, fmt, ap);
+    va_end(ap);
+    error_report_err(err);
+}
+
 void error_free(Error *err)
 {
     if (err) {