From patchwork Wed Nov 4 20:04:04 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Capitulino X-Patchwork-Id: 37617 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 69E1AB7B69 for ; Thu, 5 Nov 2009 07:12:58 +1100 (EST) Received: from localhost ([127.0.0.1]:59313 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N5mDu-00022s-HG for incoming@patchwork.ozlabs.org; Wed, 04 Nov 2009 15:12:54 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1N5m5v-0007kJ-Px for qemu-devel@nongnu.org; Wed, 04 Nov 2009 15:04:39 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1N5m5r-0007i8-Iu for qemu-devel@nongnu.org; Wed, 04 Nov 2009 15:04:39 -0500 Received: from [199.232.76.173] (port=58176 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1N5m5r-0007hy-6i for qemu-devel@nongnu.org; Wed, 04 Nov 2009 15:04:35 -0500 Received: from mx1.redhat.com ([209.132.183.28]:9991) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1N5m5q-00071Y-6N for qemu-devel@nongnu.org; Wed, 04 Nov 2009 15:04:34 -0500 Received: from int-mx08.intmail.prod.int.phx2.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id nA4K4XNW032682; Wed, 4 Nov 2009 15:04:33 -0500 Received: from localhost (vpn-8-197.rdu.redhat.com [10.11.8.197]) by int-mx08.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id nA4K4WO0020257; Wed, 4 Nov 2009 15:04:33 -0500 From: Luiz Capitulino To: qemu-devel@nongnu.org Date: Wed, 4 Nov 2009 18:04:04 -0200 Message-Id: <1257365047-25895-6-git-send-email-lcapitulino@redhat.com> In-Reply-To: <1257365047-25895-1-git-send-email-lcapitulino@redhat.com> References: <1257365047-25895-1-git-send-email-lcapitulino@redhat.com> X-Scanned-By: MIMEDefang 2.67 on 10.5.11.21 X-detected-operating-system: by monty-python.gnu.org: Genre and OS details not recognized. Cc: pbonzini@redhat.com, aliguori@us.ibm.com, kraxel@redhat.com, hollisb@us.ibm.com Subject: [Qemu-devel] [PATCH 5/8] Introduce QError X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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 diff --git a/Makefile b/Makefile index 6fcbcaa..2dfaebd 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/qerror.c b/qerror.c new file mode 100644 index 0000000..7d3137f --- /dev/null +++ b/qerror.c @@ -0,0 +1,235 @@ +/* + * QError: QEMU Error data-type. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino + * + * 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); +} diff --git a/qerror.h b/qerror.h new file mode 100644 index 0000000..dc39dec --- /dev/null +++ b/qerror.h @@ -0,0 +1,39 @@ +/* + * QError header file. + * + * Copyright (C) 2009 Red Hat Inc. + * + * Authors: + * Luiz Capitulino + * + * 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 +#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 */ diff --git a/qobject.h b/qobject.h index 167b607..838dddc 100644 --- a/qobject.h +++ b/qobject.h @@ -43,6 +43,7 @@ typedef enum { QTYPE_QLIST, QTYPE_QFLOAT, QTYPE_QBOOL, + QTYPE_QERROR, } qtype_code; struct QObject;