@@ -135,7 +135,7 @@ obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
obj-y += qemu-char.o aio.o savevm.o
obj-y += msmouse.o ps2.o
obj-y += qdev.o qdev-properties.o
-obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o qjson.o
+obj-y += qint.o qstring.o qdict.o qlist.o qfloat.o qbool.o qjson.o qerror.o
obj-y += qemu-config.o
obj-$(CONFIG_BRLAPI) += baum.o
new file mode 100644
@@ -0,0 +1,235 @@
+/*
+ * QError: QEMU Error data-type.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+#include "qint.h"
+#include "qjson.h"
+#include "qerror.h"
+#include "qstring.h"
+#include "sysemu.h"
+#include "qemu-common.h"
+
+static void qerror_destroy_obj(QObject *obj);
+
+static const QType qerror_type = {
+ .code = QTYPE_QERROR,
+ .destroy = qerror_destroy_obj,
+};
+
+/**
+ * qerror_new(): Create a new QError
+ *
+ * Return strong reference.
+ */
+QError *qerror_new(void)
+{
+ QError *qerr;
+
+ qerr = qemu_mallocz(sizeof(*qerr));
+ QOBJECT_INIT(qerr, &qerror_type);
+
+ return qerr;
+}
+
+/**
+ * qerror_from_info(): Create a new QError from error information
+ *
+ * The information consists of:
+ *
+ * - name generic error name
+ * - file the file name of where the error occurred
+ * - linenr the line number of where the error occurred
+ * - desc detailed description (see below)
+ * - fmt JSON printf-like format for 'specific data'
+ * - va va_list of all arguments for 'specific data'
+ *
+ * Note that this is a low-level function, it is supposed to be called
+ * by higher-level functions or macros.
+ *
+ * The 'desc' parameter is a printf-like string, the format of the format
+ * string is:
+ *
+ * %(KEY)TYPE
+ *
+ * Where KEY is a QDict key and TYPE is the type of its value, KEY and
+ * its value must be passed to qerror_from_info().
+ *
+ * Valid types are:
+ *
+ * s (string)
+ * d (integer)
+ *
+ * Example:
+ *
+ * "foo error on device: %(device)s slot: %(slot_nr)d"
+ *
+ * A single percent sign can be printed if followed by a second one,
+ * for example:
+ *
+ * "running out of foo: %(foo)d%%"
+ *
+ * Return strong reference.
+ */
+QError *qerror_from_info(const char *name, const char *file, int linenr,
+ const char *desc, const char *fmt, va_list *va)
+{
+ QError *qerr;
+
+ qerr = qerror_new();
+ qerr->name = name;
+ qerr->file = file;
+ qerr->linenr = linenr;
+ qerr->desc = desc;
+ if (fmt) {
+ qerr->data = qobject_from_json_va(fmt, va);
+ assert(qerr->data != NULL);
+ }
+
+ return qerr;
+}
+
+static char *get_substr(const char *start, const char *end)
+{
+ char *str;
+ size_t length;
+
+ length = end - start + 1;
+ str = qemu_malloc(length + 1);
+ memcpy(str, start, length);
+ str[length] = '\0';
+
+ return str;
+}
+
+static void qerror_abort(const QError *qerr)
+{
+ fprintf(stderr, " in '%s' at %s:%d\n", qerr->desc, qerr->file,qerr->linenr);
+ abort();
+}
+
+#define ERROR_PREFIX "\n\nqerror: "
+
+static void type_error(const QError *qerr, int c)
+{
+ fprintf(stderr, ERROR_PREFIX "invalid type '%c'", c);
+ qerror_abort(qerr);
+}
+
+static void key_error(const QError *qerr, const char *key)
+{
+ fprintf(stderr, ERROR_PREFIX "key '%s' not found in QDict ", key);
+ fprintf(stderr, "call at %s:%d\n", qerr->file, qerr->linenr);
+ abort();
+}
+
+static void parse_error(const QError *qerror, int c)
+{
+ fprintf(stderr, ERROR_PREFIX "expected '%c'", c);
+ qerror_abort(qerror);
+}
+
+static const char *append_field(QString *qstring, const QError *qerror,
+ const char *start)
+{
+ int type;
+ char *name;
+ QDict *qdict;
+ const char *end;
+
+ if (*start != '%')
+ parse_error(qerror, '%');
+ start++;
+ if (*start != '(')
+ parse_error(qerror, '(');
+ start++;
+
+ end = strchr(start, ')');
+ if (!end)
+ parse_error(qerror, ')');
+
+ name = get_substr(start, end - 1);
+ qdict = qobject_to_qdict(qerror->data);
+
+ if (!qdict_haskey(qdict, name)) {
+ key_error(qerror, name);
+ }
+
+ type = *++end;
+ switch (type) {
+ case 's':
+ qstring_append(qstring, qdict_get_str(qdict, name));
+ break;
+ case 'd':
+ qstring_append_int(qstring, qdict_get_int(qdict, name));
+ break;
+ default:
+ type_error(qerror, type);
+ }
+
+ qemu_free(name);
+ return ++end;
+}
+
+/**
+ * qerror_print(): Print QError data
+ *
+ * This function will print the member 'desc' of the specified QError object,
+ * it uses qemu_error() for this, so that the output is routed to the right
+ * place (ie. stderr ou Monitor's device).
+ */
+void qerror_print(const QError *qerror)
+{
+ const char *p;
+ QString *qstring;
+
+ assert(qerror->desc != NULL);
+
+ qstring = qstring_new();
+
+ for (p = qerror->desc; *p != '\0';) {
+ if (*p != '%') {
+ qstring_append_chr(qstring, *p++);
+ } else if (*(p + 1) == '%') {
+ qstring_append_chr(qstring, '%');
+ p += 2;
+ } else {
+ p = append_field(qstring, qerror, p);
+ }
+ }
+
+ qemu_error("%s\n", qstring_get_str(qstring));
+ QDECREF(qstring);
+}
+
+/**
+ * qobject_to_qerror(): Convert a QObject into a QError
+ */
+QError *qobject_to_qerror(const QObject *obj)
+{
+ if (qobject_type(obj) != QTYPE_QERROR) {
+ return NULL;
+ }
+
+ return container_of(obj, QError, base);
+}
+
+/**
+ * qerror_destroy_obj(): Free all memory allocated by a QError
+ */
+static void qerror_destroy_obj(QObject *obj)
+{
+ QError *qerr;
+
+ assert(obj != NULL);
+ qerr = qobject_to_qerror(obj);
+
+ qobject_decref(qerr->data);
+ qemu_free(qerr);
+}
new file mode 100644
@@ -0,0 +1,39 @@
+/*
+ * QError header file.
+ *
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+#ifndef QERROR_H
+#define QERROR_H
+
+#include <stdarg.h>
+#include "qobject.h"
+
+typedef struct QError {
+ QObject_HEAD;
+ const char *name; /* generic name */
+ const char *desc; /* description */
+ int linenr; /* line number */
+ const char *file; /* file name */
+ QObject *data; /* run-time data */
+} QError;
+
+QError *qerror_new(void);
+QError *qerror_from_info(const char *name, const char *file, int linenr,
+ const char *desc, const char *fmt, va_list *va);
+void qerror_print(const QError *qerror);
+QError *qobject_to_qerror(const QObject *obj);
+
+/*
+ * Common error names
+ */
+#define QERR_DEV_NFOUND "DeviceNotFound"
+#define QERR_SER_UNAV "ServiceUnavailable"
+
+#endif /* QERROR_H */
@@ -43,6 +43,7 @@ typedef enum {
QTYPE_QLIST,
QTYPE_QFLOAT,
QTYPE_QBOOL,
+ QTYPE_QERROR,
} qtype_code;
struct QObject;
QError is a high-level data type which represents an exception, it stores the following error information: - name A generic error name (eg. "ServiceUnavailable") - description A detailed error description, which may contain references to run-time error data - filename The file name of where the error occurred - line number The exact line number of the error - run-time data Run-time error data The qerror_print() function should be used to properly format and print the stored information to the right place, that is, to stderr if the Monitor is not running, or to the Monitor's device otherwise. The following functions are exported: - qerror_new(): Create a new QError - qerror_from_info(): Create a new QError from the specified error information - qerror_print(): Print the specified QError Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com> --- Makefile | 2 +- qerror.c | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ qerror.h | 39 ++++++++++ qobject.h | 1 + 4 files changed, 276 insertions(+), 1 deletions(-) create mode 100644 qerror.c create mode 100644 qerror.h